From eded32744c92fb51fbf1cfc3658df8135ae46de0 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 21 Aug 2021 12:42:56 +0200 Subject: [PATCH 1/3] crypto: fix JWK RSA-PSS SubtleCrypto.exportKey --- lib/internal/crypto/keys.js | 6 +-- lib/internal/crypto/webcrypto.js | 2 +- src/crypto/crypto_keys.cc | 20 ++++++--- .../test-webcrypto-export-import-rsa.js | 41 +++++++++++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index 1127217d6b9dee..4d5545ab1aae1a 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -141,7 +141,7 @@ const { validateOneOf( options.format, 'options.format', [undefined, 'buffer', 'jwk']); if (options.format === 'jwk') { - return this[kHandle].exportJwk({}); + return this[kHandle].exportJwk({}, false); } } return this[kHandle].export(); @@ -196,7 +196,7 @@ const { export(options) { if (options && options.format === 'jwk') { - return this[kHandle].exportJwk({}); + return this[kHandle].exportJwk({}, false); } const { format, @@ -217,7 +217,7 @@ const { throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS( 'jwk', 'does not support encryption'); } - return this[kHandle].exportJwk({}); + return this[kHandle].exportJwk({}, false); } const { format, diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index 7cb32ec702767d..0edd5c2cd3f131 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -328,7 +328,7 @@ async function exportKeyJWK(key) { const jwk = key[kKeyObject][kHandle].exportJwk({ key_ops: key.usages, ext: key.extractable, - }); + }, true); switch (key.algorithm.name) { case 'RSASSA-PKCS1-v1_5': jwk.alg = normalizeHashName( diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 821a06b1bd1417..3243ece8670ce2 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -489,8 +489,13 @@ std::shared_ptr ImportJWKSecretKey( Maybe ExportJWKAsymmetricKey( Environment* env, std::shared_ptr key, - Local target) { + Local target, + bool handleRsaPss) { switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { + case EVP_PKEY_RSA_PSS: { + if (handleRsaPss) return ExportJWKRsaKey(env, key, target); + break; + } case EVP_PKEY_RSA: return ExportJWKRsaKey(env, key, target); case EVP_PKEY_EC: return ExportJWKEcKey(env, key, target); case EVP_PKEY_ED25519: @@ -609,14 +614,16 @@ static inline Maybe Tristate(bool b) { Maybe ExportJWKInner(Environment* env, std::shared_ptr key, - Local result) { + Local result, + bool handleRsaPss) { switch (key->GetKeyType()) { case kKeyTypeSecret: return ExportJWKSecretKey(env, key, result.As()); case kKeyTypePublic: // Fall through case kKeyTypePrivate: - return ExportJWKAsymmetricKey(env, key, result.As()); + return ExportJWKAsymmetricKey( + env, key, result.As(), handleRsaPss); default: UNREACHABLE(); } @@ -638,7 +645,7 @@ Maybe ManagedEVPPKey::ToEncodedPublicKey( std::shared_ptr data = KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); *out = Object::New(env->isolate()); - return ExportJWKInner(env, data, *out); + return ExportJWKInner(env, data, *out, false); } return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out)); @@ -658,7 +665,7 @@ Maybe ManagedEVPPKey::ToEncodedPrivateKey( std::shared_ptr data = KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); *out = Object::New(env->isolate()); - return ExportJWKInner(env, data, *out); + return ExportJWKInner(env, data, *out, false); } return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out)); @@ -1237,8 +1244,9 @@ void KeyObjectHandle::ExportJWK( ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); CHECK(args[0]->IsObject()); + CHECK(args[1]->IsBoolean()); - ExportJWKInner(env, key->Data(), args[0]); + ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue()); args.GetReturnValue().Set(args[0]); } diff --git a/test/parallel/test-webcrypto-export-import-rsa.js b/test/parallel/test-webcrypto-export-import-rsa.js index f43259fd22faea..77163180ce224d 100644 --- a/test/parallel/test-webcrypto-export-import-rsa.js +++ b/test/parallel/test-webcrypto-export-import-rsa.js @@ -1,6 +1,7 @@ 'use strict'; const common = require('../common'); +const fixtures = require('../common/fixtures'); if (!common.hasCrypto) common.skip('missing crypto'); @@ -478,3 +479,43 @@ const testVectors = [ }); await Promise.all(variations); })().then(common.mustCall()); + +{ + const publicPem = fixtures.readKey('rsa_pss_public_2048.pem', 'ascii'); + const privatePem = fixtures.readKey('rsa_pss_private_2048.pem', 'ascii'); + + const publicDer = Buffer.from( + publicPem.replace( + /(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, + '' + ), + 'base64' + ); + const privateDer = Buffer.from( + privatePem.replace( + /(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g, + '' + ), + 'base64' + ); + + (async () => { + const key = await subtle.importKey( + 'spki', + publicDer, + { name: 'RSA-PSS', hash: 'SHA-256' }, + true, + ['verify']); + await subtle.exportKey('jwk', key); + })().then(common.mustCall()); + + (async () => { + const key = await subtle.importKey( + 'pkcs8', + privateDer, + { name: 'RSA-PSS', hash: 'SHA-256' }, + true, + ['sign']); + await subtle.exportKey('jwk', key); + })().then(common.mustCall()); +} From 51a4f08499843a573631d72734f09c6ace0583c0 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 21 Aug 2021 17:10:51 +0200 Subject: [PATCH 2/3] fixup! crypto: fix JWK RSA-PSS SubtleCrypto.exportKey --- test/parallel/test-webcrypto-export-import-rsa.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-webcrypto-export-import-rsa.js b/test/parallel/test-webcrypto-export-import-rsa.js index 77163180ce224d..fd062039bbd579 100644 --- a/test/parallel/test-webcrypto-export-import-rsa.js +++ b/test/parallel/test-webcrypto-export-import-rsa.js @@ -506,7 +506,8 @@ const testVectors = [ { name: 'RSA-PSS', hash: 'SHA-256' }, true, ['verify']); - await subtle.exportKey('jwk', key); + const jwk = await subtle.exportKey('jwk', key); + assert.equal(jwk.alg, 'PS256'); })().then(common.mustCall()); (async () => { @@ -516,6 +517,7 @@ const testVectors = [ { name: 'RSA-PSS', hash: 'SHA-256' }, true, ['sign']); - await subtle.exportKey('jwk', key); + const jwk = await subtle.exportKey('jwk', key); + assert.equal(jwk.alg, 'PS256'); })().then(common.mustCall()); } From cc8c546fcad0b40988bc6a9a9384c8efb3d6d631 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 21 Aug 2021 17:25:07 +0200 Subject: [PATCH 3/3] fixup! crypto: fix JWK RSA-PSS SubtleCrypto.exportKey --- test/parallel/test-webcrypto-export-import-rsa.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-webcrypto-export-import-rsa.js b/test/parallel/test-webcrypto-export-import-rsa.js index fd062039bbd579..04cf6388fc739d 100644 --- a/test/parallel/test-webcrypto-export-import-rsa.js +++ b/test/parallel/test-webcrypto-export-import-rsa.js @@ -507,7 +507,7 @@ const testVectors = [ true, ['verify']); const jwk = await subtle.exportKey('jwk', key); - assert.equal(jwk.alg, 'PS256'); + assert.strictEqual(jwk.alg, 'PS256'); })().then(common.mustCall()); (async () => { @@ -518,6 +518,6 @@ const testVectors = [ true, ['sign']); const jwk = await subtle.exportKey('jwk', key); - assert.equal(jwk.alg, 'PS256'); + assert.strictEqual(jwk.alg, 'PS256'); })().then(common.mustCall()); }