Skip to content

Commit 20cf470

Browse files
panvatargos
authored andcommitted
crypto: fix JWK RSA-PSS SubtleCrypto.exportKey
PR-URL: #39828 Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent a4b8c13 commit 20cf470

File tree

4 files changed

+61
-10
lines changed

4 files changed

+61
-10
lines changed

lib/internal/crypto/keys.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ const {
141141
validateOneOf(
142142
options.format, 'options.format', [undefined, 'buffer', 'jwk']);
143143
if (options.format === 'jwk') {
144-
return this[kHandle].exportJwk({});
144+
return this[kHandle].exportJwk({}, false);
145145
}
146146
}
147147
return this[kHandle].export();
@@ -196,7 +196,7 @@ const {
196196

197197
export(options) {
198198
if (options && options.format === 'jwk') {
199-
return this[kHandle].exportJwk({});
199+
return this[kHandle].exportJwk({}, false);
200200
}
201201
const {
202202
format,
@@ -217,7 +217,7 @@ const {
217217
throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
218218
'jwk', 'does not support encryption');
219219
}
220-
return this[kHandle].exportJwk({});
220+
return this[kHandle].exportJwk({}, false);
221221
}
222222
const {
223223
format,

lib/internal/crypto/webcrypto.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ async function exportKeyJWK(key) {
328328
const jwk = key[kKeyObject][kHandle].exportJwk({
329329
key_ops: key.usages,
330330
ext: key.extractable,
331-
});
331+
}, true);
332332
switch (key.algorithm.name) {
333333
case 'RSASSA-PKCS1-v1_5':
334334
jwk.alg = normalizeHashName(

src/crypto/crypto_keys.cc

+14-6
Original file line numberDiff line numberDiff line change
@@ -489,8 +489,13 @@ std::shared_ptr<KeyObjectData> ImportJWKSecretKey(
489489
Maybe<bool> ExportJWKAsymmetricKey(
490490
Environment* env,
491491
std::shared_ptr<KeyObjectData> key,
492-
Local<Object> target) {
492+
Local<Object> target,
493+
bool handleRsaPss) {
493494
switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) {
495+
case EVP_PKEY_RSA_PSS: {
496+
if (handleRsaPss) return ExportJWKRsaKey(env, key, target);
497+
break;
498+
}
494499
case EVP_PKEY_RSA: return ExportJWKRsaKey(env, key, target);
495500
case EVP_PKEY_EC: return ExportJWKEcKey(env, key, target);
496501
case EVP_PKEY_ED25519:
@@ -609,14 +614,16 @@ static inline Maybe<bool> Tristate(bool b) {
609614

610615
Maybe<bool> ExportJWKInner(Environment* env,
611616
std::shared_ptr<KeyObjectData> key,
612-
Local<Value> result) {
617+
Local<Value> result,
618+
bool handleRsaPss) {
613619
switch (key->GetKeyType()) {
614620
case kKeyTypeSecret:
615621
return ExportJWKSecretKey(env, key, result.As<Object>());
616622
case kKeyTypePublic:
617623
// Fall through
618624
case kKeyTypePrivate:
619-
return ExportJWKAsymmetricKey(env, key, result.As<Object>());
625+
return ExportJWKAsymmetricKey(
626+
env, key, result.As<Object>(), handleRsaPss);
620627
default:
621628
UNREACHABLE();
622629
}
@@ -638,7 +645,7 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
638645
std::shared_ptr<KeyObjectData> data =
639646
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
640647
*out = Object::New(env->isolate());
641-
return ExportJWKInner(env, data, *out);
648+
return ExportJWKInner(env, data, *out, false);
642649
}
643650

644651
return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out));
@@ -658,7 +665,7 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey(
658665
std::shared_ptr<KeyObjectData> data =
659666
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
660667
*out = Object::New(env->isolate());
661-
return ExportJWKInner(env, data, *out);
668+
return ExportJWKInner(env, data, *out, false);
662669
}
663670

664671
return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out));
@@ -1237,8 +1244,9 @@ void KeyObjectHandle::ExportJWK(
12371244
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder());
12381245

12391246
CHECK(args[0]->IsObject());
1247+
CHECK(args[1]->IsBoolean());
12401248

1241-
ExportJWKInner(env, key->Data(), args[0]);
1249+
ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue());
12421250

12431251
args.GetReturnValue().Set(args[0]);
12441252
}

test/parallel/test-webcrypto-export-import-rsa.js

+43
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
45

56
if (!common.hasCrypto)
67
common.skip('missing crypto');
@@ -478,3 +479,45 @@ const testVectors = [
478479
});
479480
await Promise.all(variations);
480481
})().then(common.mustCall());
482+
483+
{
484+
const publicPem = fixtures.readKey('rsa_pss_public_2048.pem', 'ascii');
485+
const privatePem = fixtures.readKey('rsa_pss_private_2048.pem', 'ascii');
486+
487+
const publicDer = Buffer.from(
488+
publicPem.replace(
489+
/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g,
490+
''
491+
),
492+
'base64'
493+
);
494+
const privateDer = Buffer.from(
495+
privatePem.replace(
496+
/(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g,
497+
''
498+
),
499+
'base64'
500+
);
501+
502+
(async () => {
503+
const key = await subtle.importKey(
504+
'spki',
505+
publicDer,
506+
{ name: 'RSA-PSS', hash: 'SHA-256' },
507+
true,
508+
['verify']);
509+
const jwk = await subtle.exportKey('jwk', key);
510+
assert.strictEqual(jwk.alg, 'PS256');
511+
})().then(common.mustCall());
512+
513+
(async () => {
514+
const key = await subtle.importKey(
515+
'pkcs8',
516+
privateDer,
517+
{ name: 'RSA-PSS', hash: 'SHA-256' },
518+
true,
519+
['sign']);
520+
const jwk = await subtle.exportKey('jwk', key);
521+
assert.strictEqual(jwk.alg, 'PS256');
522+
})().then(common.mustCall());
523+
}

0 commit comments

Comments
 (0)