1+ // Flags: --expose-internals
12'use strict' ;
23
34const common = require ( '../common' ) ;
@@ -18,6 +19,17 @@ const { once } = require('events');
1819const { promisify } = require ( 'util' ) ;
1920const { Worker, parentPort, workerData } = require ( 'worker_threads' ) ;
2021const fixtures = require ( '../common/fixtures' ) ;
22+ const { internalBinding } = require ( 'internal/test/binding' ) ;
23+ const { getKeyObjectHandle } = require ( 'internal/crypto/keys' ) ;
24+ const {
25+ ECKeyExportJob,
26+ RSAKeyExportJob,
27+ kCryptoJobWebCrypto,
28+ kKeyVariantRSA_SSA_PKCS1_v1_5,
29+ kWebCryptoKeyFormatRaw,
30+ kWebCryptoKeyFormatPKCS8,
31+ kWebCryptoKeyFormatSPKI,
32+ } = internalBinding ( 'crypto' ) ;
2133const { subtle } = globalThis . crypto ;
2234const signAsync = promisify ( sign ) ;
2335const verifyAsync = promisify ( verify ) ;
@@ -28,6 +40,14 @@ const sec1 = { type: 'sec1', format: 'der' };
2840const spki = { type : 'spki' , format : 'der' } ;
2941const iterations = 16 ;
3042
43+ function exportLegacyKey ( Job , format , key , expected , ...params ) {
44+ return new Job (
45+ kCryptoJobWebCrypto , format , getKeyObjectHandle ( key ) , ...params )
46+ . run ( ) . then ( ( encoded ) => {
47+ assert . deepStrictEqual ( Buffer . from ( encoded ) , Buffer . from ( expected ) ) ;
48+ } ) ;
49+ }
50+
3151async function exercise ( { keys, peer, expected } ) {
3252 // Check generated signatures and exports with independent imports that do
3353 // not warm the shared key's provider caches before its first operation.
@@ -37,6 +57,9 @@ async function exercise({ keys, peer, expected }) {
3757 const referencePublic = createPublicKey ( { key : expected . public , ...spki } ) ;
3858 const referencePem = referencePrivate . export ( pkcs8Pem ) ;
3959 const referenceSec1 = referencePrivate . export ( sec1 ) ;
60+ const referenceRsaPublic = createPublicKey ( {
61+ key : expected . rsa . public , ...spki ,
62+ } ) ;
4063
4164 for ( let i = 0 ; i < iterations ; i ++ ) {
4265 const data = Buffer . from ( `shared key operation ${ i } ` ) ;
@@ -76,6 +99,40 @@ async function exercise({ keys, peer, expected }) {
7699 ) ;
77100 }
78101
102+ // Public Web Crypto exports use direct bindings. Exercise the older
103+ // export jobs explicitly while the same keys are used by other jobs.
104+ pending . push (
105+ exportLegacyKey ( ECKeyExportJob , kWebCryptoKeyFormatRaw ,
106+ keys . publicKey , expected . rawPublic ) ,
107+ exportLegacyKey ( ECKeyExportJob , kWebCryptoKeyFormatSPKI ,
108+ keys . publicKey , expected . public ) ,
109+ exportLegacyKey ( ECKeyExportJob , kWebCryptoKeyFormatPKCS8 ,
110+ keys . privateKey , expected . originalPrivate ) ,
111+ exportLegacyKey ( RSAKeyExportJob , kWebCryptoKeyFormatSPKI ,
112+ keys . rsa . publicKey , expected . rsa . public ,
113+ kKeyVariantRSA_SSA_PKCS1_v1_5 ) ,
114+ exportLegacyKey ( RSAKeyExportJob , kWebCryptoKeyFormatPKCS8 ,
115+ keys . rsa . privateKey , expected . rsa . private ,
116+ kKeyVariantRSA_SSA_PKCS1_v1_5 ) ,
117+ assert . rejects ( new ECKeyExportJob (
118+ kCryptoJobWebCrypto , kWebCryptoKeyFormatPKCS8 ,
119+ getKeyObjectHandle ( keys . publicKey ) ) . run ( ) , ( err ) => {
120+ assert . strictEqual ( err . name , 'OperationError' ) ;
121+ assert . strictEqual (
122+ err . message , 'The operation failed for an operation-specific reason' ) ;
123+ assert . strictEqual ( err . cause ?. message , 'Invalid key type' ) ;
124+ return true ;
125+ } ) ,
126+ signAsync ( 'sha256' , data , keys . rsa . privateKey ) . then ( ( signature ) => {
127+ assert . strictEqual (
128+ verify ( 'sha256' , data , referenceRsaPublic , signature ) , true ) ;
129+ return verifyAsync ( 'sha256' , data , keys . rsa . publicKey , signature )
130+ . then ( ( valid ) => {
131+ assert . strictEqual ( valid , true ) ;
132+ } ) ;
133+ } ) ,
134+ ) ;
135+
79136 // Export, compare, and query metadata while jobs use this same native key
80137 // in the threadpool and other Workers. Fresh wrappers also exercise the
81138 // native metadata getters on every iteration rather than their JS caches.
@@ -106,7 +163,8 @@ async function exercise({ keys, peer, expected }) {
106163 format : 'raw-public' , type : 'compressed' ,
107164 } ) , Buffer . from ( expected . compressedPublic ) ) ;
108165 assert . deepStrictEqual (
109- publicKey . export ( spki ) , Buffer . from ( expected . public ) ) ;
166+ publicKey . export ( spki ) ,
167+ Buffer . from ( expected . originalPublic ?? expected . public ) ) ;
110168 assert . deepStrictEqual (
111169 privateKey . export ( pkcs8 ) , Buffer . from ( expected . originalPrivate ) ) ;
112170 assert . strictEqual ( privateKey . export ( pkcs8Pem ) , referencePem ) ;
@@ -161,8 +219,15 @@ if (workerData?.sharedKeyTest) {
161219 // exercising concurrent first use of the shared key. CryptoKey conversion
162220 // validates the key before its first concurrent sign/derive/export calls.
163221 const privateKey = createPrivateKey ( { key : input , ...pkcs8 } ) ;
164- const publicKey = createPublicKey ( privateKey ) ;
165- const keys = { privateKey, publicKey } ;
222+ const publicKey = expected . originalPublic === undefined ?
223+ createPublicKey ( privateKey ) :
224+ createPublicKey ( { key : expected . originalPublic , ...spki } ) ;
225+ const rsaPrivate = createPrivateKey ( { key : expected . rsa . private , ...pkcs8 } ) ;
226+ const keys = {
227+ privateKey,
228+ publicKey,
229+ rsa : { privateKey : rsaPrivate , publicKey : createPublicKey ( rsaPrivate ) } ,
230+ } ;
166231 if ( webcrypto ) {
167232 keys . ecdsaPrivate = privateKey . toCryptoKey ( {
168233 name : 'ECDSA' , namedCurve : 'P-256' ,
@@ -198,6 +263,8 @@ if (workerData?.sharedKeyTest) {
198263 privateKey . export ( pkcs8 ) , Buffer . from ( expected . originalPrivate ) ) ;
199264 assert . deepStrictEqual ( privateKey . export ( sec1 ) ,
200265 createPrivateKey ( { key : input , ...pkcs8 } ) . export ( sec1 ) ) ;
266+ assert . deepStrictEqual ( publicKey . export ( spki ) ,
267+ Buffer . from ( expected . originalPublic ?? expected . public ) ) ;
201268 }
202269
203270 ( async ( ) => {
@@ -207,6 +274,7 @@ if (workerData?.sharedKeyTest) {
207274 namedCurve : 'prime256v1' ,
208275 } ) ;
209276 const privateJwk = reference . export ( { format : 'jwk' } ) ;
277+ const rsaPrivate = createPrivateKey ( fixtures . readKey ( 'rsa_private_2048.pem' ) ) ;
210278 const expected = {
211279 private : reference . export ( pkcs8 ) ,
212280 public : publicKey . export ( spki ) ,
@@ -224,6 +292,10 @@ if (workerData?.sharedKeyTest) {
224292 dsaEncoding : 'ieee-p1363' ,
225293 } ) ;
226294 } ) ,
295+ rsa : {
296+ private : rsaPrivate . export ( pkcs8 ) ,
297+ public : createPublicKey ( rsaPrivate ) . export ( spki ) ,
298+ } ,
227299 } ;
228300 const cryptoPeer = peer . toCryptoKey ( {
229301 name : 'ECDH' , namedCurve : 'P-256' ,
@@ -237,6 +309,14 @@ if (workerData?.sharedKeyTest) {
237309
238310 const algorithmIdentifier = der ( 0x30 , Buffer . from (
239311 '06072a8648ce3d020106082a8648ce3d030107' , 'hex' ) ) ;
312+ const compressedPublic = der (
313+ 0x30 , algorithmIdentifier ,
314+ der ( 0x03 , Buffer . from ( [ 0 ] ) , expected . compressedPublic ) ) ;
315+ await run ( expected . private , cryptoPeer , {
316+ ...expected ,
317+ originalPrivate : expected . private ,
318+ originalPublic : compressedPublic ,
319+ } ) ;
240320 const ecPrivateKey = der (
241321 0x30 , Buffer . from ( '020101' , 'hex' ) ,
242322 der ( 0x04 , Buffer . from ( privateJwk . d , 'base64url' ) ) ) ;
0 commit comments