From 4a11ec655810f66411e69ffe45c026b311e5eb93 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Fri, 17 Feb 2023 14:11:43 +0100 Subject: [PATCH] crypto: re-add padding for AES-KW wrapped JWKs PR-URL: https://github.com/nodejs/node/pull/46563 Reviewed-By: James M Snell Backport-PR-URL: https://github.com/nodejs/node/pull/46252 --- lib/internal/crypto/webcrypto.js | 12 +++++++++++- test/parallel/test-webcrypto-wrap-unwrap.js | 13 ++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index a0ab68199cd31b..79edd8d8cd2028 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -8,6 +8,7 @@ const { ReflectApply, ReflectConstruct, SafeSet, + StringPrototypeRepeat, SymbolToStringTag, } = primordials; @@ -680,7 +681,16 @@ async function wrapKey(format, key, wrappingKey, algorithm) { let keyData = await ReflectApply(exportKey, this, [format, key]); if (format === 'jwk') { - keyData = new TextEncoder().encode(JSONStringify(keyData)); + const ec = new TextEncoder(); + const raw = JSONStringify(keyData); + // As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey + // we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes + // in length + if (algorithm.name === 'AES-KW' && raw.length % 8 !== 0) { + keyData = ec.encode(raw + StringPrototypeRepeat(' ', 8 - (raw.length % 8))); + } else { + keyData = ec.encode(raw); + } } return cipherOrWrap( diff --git a/test/parallel/test-webcrypto-wrap-unwrap.js b/test/parallel/test-webcrypto-wrap-unwrap.js index 1094845c73e143..a64d4cccdbc4c0 100644 --- a/test/parallel/test-webcrypto-wrap-unwrap.js +++ b/test/parallel/test-webcrypto-wrap-unwrap.js @@ -199,6 +199,10 @@ function getFormats(key) { // material length must be a multiple of 8. // If the wrapping algorithm is RSA-OAEP, the exported key // material maximum length is a factor of the modulusLength +// +// As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey +// we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes +// in length async function wrappingIsPossible(name, exported) { if ('byteLength' in exported) { switch (name) { @@ -207,13 +211,8 @@ async function wrappingIsPossible(name, exported) { case 'RSA-OAEP': return exported.byteLength <= 446; } - } else if ('kty' in exported) { - switch (name) { - case 'AES-KW': - return JSON.stringify(exported).length % 8 === 0; - case 'RSA-OAEP': - return JSON.stringify(exported).length <= 478; - } + } else if ('kty' in exported && name === 'RSA-OAEP') { + return JSON.stringify(exported).length <= 478; } return true; }