Skip to content

Inconsistent behavior between Node and browser crypto with PKCS8 EC imports #50174

@ArnaudBrousseau

Description

@ArnaudBrousseau

Version

v20.8.0

Platform

MacOS

Subsystem

crypto

What steps will reproduce the bug?

In Node console:

$ node
Welcome to Node.js v20.8.0.
Type ".help" for more information.
> require("crypto")
> buffer = new Uint8Array([48,129,65,2,1,0,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,4,39,48,37,2,1,1,4,32,118,50,222,115,56,87,123,193,44,23,49,250,41,240,128,25,32,106,243,129,247,74,246,15,77,94,3,149,33,143,32,92])
> await crypto.subtle.importKey("pkcs8", buffer, { name: "ECDSA", namedCurve: "P-256" }, true, ["sign"])
CryptoKey {
  type: 'private',
  extractable: true,
  algorithm: { name: 'ECDSA', namedCurve: 'P-256' },
  usages: [ 'sign' ]
}

In browsers (tried both Firefox and Chrome):

> buffer = new Uint8Array([48,129,65,2,1,0,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,4,39,48,37,2,1,1,4,32,118,50,222,115,56,87,123,193,44,23,49,250,41,240,128,25,32,106,243,129,247,74,246,15,77,94,3,149,33,143,32,92])
> await crypto.subtle.importKey("pkcs8", buffer, { name: "ECDSA", namedCurve: "P-256" }, true, ["sign"])
Uncaught Error

Additional information

The bytes I'm importing are, in hex format: 308141020100301306072a8648ce3d020106082a8648ce3d0301070427302502010104207632de7338577bc12c1731fa29f08019206af381f74af60f4d5e0395218f205c

You can use asn1js to decode this pkc8 structure: https://lapo.it/asn1js/#MIFBAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBCcwJQIBAQQgdjLeczhXe8EsFzH6KfCAGSBq84H3SvYPTV4DlSGPIFw
image

This is a P-256 private key with no public key bytes (they are optional in pkcs8)

I'm honestly not sure that browsers are doing the right thing here but at the very least this behavior ("error when no public key bytes are present") seems intentional: Chrome has an explicit test case for it:

// The private key is exactly equal to the order, and the public key is
// omitted.
{
  "crv": "P-256",
  "key_format": "pkcs8",
  "key": "3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010420FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
  "error": "DataError"
},

This specific private key (from the test case) also succeeds in NodeJS:

// This is `3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010420FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551`
buffer = new Uint8Array([48,65,2,1,0,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,4,39,48,37,2,1,1,4,32,255,255,255,255,0,0,0,0,255,255,255,255,255,255,255,255,188,230,250,173,167,23,158,132,243,185,202,194,252,99,37,81])
> await crypto.subtle.importKey("pkcs8", buffer, { name: "ECDSA", namedCurve: "P-256" }, true, ["sign"])
CryptoKey {
  type: 'private',
  extractable: true,
  algorithm: { name: 'ECDSA', namedCurve: 'P-256' },
  usages: [ 'sign' ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    cryptoIssues and PRs related to the crypto subsystem.questionIssues that look for answers.webcrypto

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions