Summary
The current spec doesn't specify a behavior for PKC8-encoded raw private key import (when I say "raw private key" I mean "without the optional public key bytes").
Chrome and other browsers seem firmly in the camp of "this should be an error" (see this test) and throw a DataError, while Bun and NodeJS import the key without throwing an error.
Steps to repro
Here's a snippet to reproduce the inconsistent behavior:
In Node/Bun ✅
$ 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 🚫
> 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
The imported bytes above represent a P-256 private key without the public key bytes (in hex: 308141020100301306072a8648ce3d020106082a8648ce3d0301070427302502010104207632de7338577bc12c1731fa29f08019206af381f74af60f4d5e0395218f205c). Here's a asn1js link to see the structure
@panva helped me run this case across multiple implementations, here are the results:
| runtime |
result |
| Bun |
✔️ |
| Chromium |
DataError |
| Deno |
DataError |
| Firefox |
DataError |
| Node.js |
✔️ |
| WebKit |
DataError |
| Workerd |
DataError |
See nodejs/node#50174 for context
Summary
The current spec doesn't specify a behavior for PKC8-encoded raw private key import (when I say "raw private key" I mean "without the optional public key bytes").
Chrome and other browsers seem firmly in the camp of "this should be an error" (see this test) and throw a
DataError, while Bun and NodeJS import the key without throwing an error.Steps to repro
Here's a snippet to reproduce the inconsistent behavior:
In Node/Bun ✅
In browsers 🚫
The imported bytes above represent a P-256 private key without the public key bytes (in hex:
308141020100301306072a8648ce3d020106082a8648ce3d0301070427302502010104207632de7338577bc12c1731fa29f08019206af381f74af60f4d5e0395218f205c). Here's a asn1js link to see the structure@panva helped me run this case across multiple implementations, here are the results:
See nodejs/node#50174 for context