From 4cb82ea430824a779e97a247ddefd520db7a8f22 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 22 Jan 2024 13:44:50 -0500 Subject: [PATCH 1/3] test(base64): Add coverage for invalid input --- packages/base64/test/test-main.js | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/base64/test/test-main.js b/packages/base64/test/test-main.js index 7e68df8123..5051fda520 100644 --- a/packages/base64/test/test-main.js +++ b/packages/base64/test/test-main.js @@ -57,3 +57,40 @@ test('bytes conversions', t => { t.is(atob(btoa(str)), str, `${str} round trips with atob(btoa)`); } }); + +test('invalid encodings', t => { + const badInputs = [ + ['%', /Invalid base64 character %/], + ['=', undefined], // this input is bad in multiple ways + + ['Z%', /Invalid base64 character %/], + ['Z', /Missing padding at offset 1/], + ['Z=', /Missing padding at offset 2/], + ['Z=%', /Missing padding at offset 2/], + ['Z==%', /Missing padding at offset 3/], + ['Z==m', /Missing padding at offset 3/], + + ['Zg%', /Invalid base64 character %/], + ['Zg', /Missing padding at offset 2/], + ['Zg=', /Missing padding at offset 3/], + ['Zg=%', /Missing padding at offset 3/], + ['Zg==%', /trailing garbage %/], + ['Zg==m', /trailing garbage m/], + + ['Zm8%', /Invalid base64 character %/], + ['Zm8', /Missing padding at offset 3/], + // not invalid: 'Zm8=' + ['Zm8=%', /trailing garbage %/], + ['Zm8==%', /trailing garbage =%/], + ['Zm8==m', /trailing garbage =m/], + + // non-zero padding bits (MAY reject): ['Qf==', ...], + ]; + for (const [badInput, message] of badInputs) { + t.throws( + () => decodeBase64(badInput), + message && { message }, + `${badInput} is rejected`, + ); + } +}); From 06d2fc5f81f68977e10b47448e1e0c56dce5048f Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 22 Jan 2024 11:50:03 -0500 Subject: [PATCH 2/3] fix(base64): Reject too-short encodings Fixes #1990 --- packages/base64/src/decode.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/base64/src/decode.js b/packages/base64/src/decode.js index 63542f60f4..5d44d666e8 100644 --- a/packages/base64/src/decode.js +++ b/packages/base64/src/decode.js @@ -44,10 +44,12 @@ export const jsDecodeBase64 = (string, name = '') => { i += 1; } - while (i < string.length && quantum % 8 !== 0) { - if (string[i] !== padding) { + while (quantum % 8 !== 0) { + if (i === string.length || string[i] !== padding) { throw Error(`Missing padding at offset ${i} of string ${name}`); } + // We MAY reject non-zero padding bits, but choose not to. + // https://datatracker.ietf.org/doc/html/rfc4648#section-3.5 i += 1; quantum += 6; } From 01c06d43273cd1dd522e8736e998b1c050f0475c Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 22 Jan 2024 12:00:57 -0500 Subject: [PATCH 3/3] perf(base64): Avoid unnecessary calculations --- packages/base64/src/decode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/base64/src/decode.js b/packages/base64/src/decode.js index 5d44d666e8..6c8fea3a8f 100644 --- a/packages/base64/src/decode.js +++ b/packages/base64/src/decode.js @@ -44,14 +44,14 @@ export const jsDecodeBase64 = (string, name = '') => { i += 1; } - while (quantum % 8 !== 0) { + while (quantum > 0) { if (i === string.length || string[i] !== padding) { throw Error(`Missing padding at offset ${i} of string ${name}`); } // We MAY reject non-zero padding bits, but choose not to. // https://datatracker.ietf.org/doc/html/rfc4648#section-3.5 i += 1; - quantum += 6; + quantum -= 2; } if (i < string.length) {