Skip to content

Commit 7f0c495

Browse files
committed
rfc3230 algo compare with uppercase
1 parent 2408f36 commit 7f0c495

File tree

7 files changed

+61
-47
lines changed

7 files changed

+61
-47
lines changed

dist/digest/digest-rfc9530.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,5 @@ export declare function verifyRFC9530DigestHeader(request: IncomingRequest, rawB
7777
* If `varifyAll: false`, it is also used to choose the hash algorithm to verify.
7878
* (Younger index is preferred.)
7979
*/
80-
hashAlgorithms?: RFC9530HashAlgorithm[];
80+
algorithms?: RFC9530HashAlgorithm[];
8181
}, errorLogger?: ((message: any) => any)): Promise<boolean>;

dist/index.cjs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1619,7 +1619,7 @@ async function verifyRFC3230DigestHeader(request, rawBody, opts = {
16191619
algorithms: ["SHA-256", "SHA-512"]
16201620
}, errorLogger) {
16211621
const failOnNoDigest = typeof opts === "boolean" ? opts : opts.failOnNoDigest;
1622-
const algorithms = typeof opts === "boolean" ? ["SHA-256", "SHA-512"] : opts.algorithms;
1622+
const algorithms = typeof opts === "boolean" ? ["SHA-256", "SHA-512"] : opts.algorithms.map((algo2) => algo2.toUpperCase());
16231623
const digestHeader = getHeaderValue(collectHeaders(request), "digest");
16241624
if (!digestHeader) {
16251625
if (failOnNoDigest) {
@@ -1641,12 +1641,13 @@ async function verifyRFC3230DigestHeader(request, rawBody, opts = {
16411641
return false;
16421642
}
16431643
const value = import_rfc46482.base64.parse(match[2]);
1644-
const algo = match[1];
1644+
let algo = match[1];
16451645
if (!algo) {
16461646
if (errorLogger)
16471647
errorLogger(`Invalid Digest header algorithm: ${match[1]}`);
16481648
return false;
16491649
}
1650+
algo = algo.toUpperCase();
16501651
if (!algorithms.includes(algo) && !(algo === "SHA" && algorithms.includes("SHA-1"))) {
16511652
if (errorLogger)
16521653
errorLogger(`Unsupported hash algorithm detected in opts.algorithms: ${algo} (supported: ${algorithms.join(", ")})`);
@@ -1786,7 +1787,7 @@ async function genRFC9530DigestHeader(body, hashAlgorithms = ["SHA-256"], proces
17861787
async function verifyRFC9530DigestHeader(request, rawBody, opts = {
17871788
failOnNoDigest: true,
17881789
verifyAll: true,
1789-
hashAlgorithms: ["sha-256", "sha-512"]
1790+
algorithms: ["sha-256", "sha-512"]
17901791
}, errorLogger) {
17911792
const headers = collectHeaders(request);
17921793
const contentDigestHeader = getHeaderValue(headers, "content-digest");
@@ -1811,27 +1812,25 @@ async function verifyRFC9530DigestHeader(request, rawBody, opts = {
18111812
errorLogger("Digest header is empty");
18121813
return false;
18131814
}
1814-
let hashAlgorithms = (opts.hashAlgorithms || ["sha-256", "sha-512"]).map((v) => v.toLowerCase());
1815-
if (hashAlgorithms.length === 0) {
1815+
let acceptableAlgorithms = (opts.algorithms || ["sha-256", "sha-512"]).map((v) => v.toLowerCase());
1816+
if (acceptableAlgorithms.length === 0) {
18161817
throw new Error("hashAlgorithms is empty");
18171818
}
1818-
for (const algo of hashAlgorithms) {
1819-
if (!isSupportedRFC9530HashAlgorithm(algo)) {
1820-
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms: ${algo} (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(", ")})`);
1821-
}
1819+
if (acceptableAlgorithms.some((algo) => !isSupportedRFC9530HashAlgorithm(algo))) {
1820+
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(", ")})`);
18221821
}
18231822
const dictionaryAlgorithms = dictionary.reduce((prev, [k]) => prev.add(k), /* @__PURE__ */ new Set());
1824-
if (!hashAlgorithms.some((v) => dictionaryAlgorithms.has(v))) {
1823+
if (!acceptableAlgorithms.some((v) => dictionaryAlgorithms.has(v))) {
18251824
if (errorLogger)
18261825
errorLogger("No supported Content-Digest header algorithm");
18271826
return false;
18281827
}
18291828
if (!opts.verifyAll) {
1830-
hashAlgorithms = [hashAlgorithms.find((v) => dictionaryAlgorithms.has(v))];
1829+
acceptableAlgorithms = [acceptableAlgorithms.find((v) => dictionaryAlgorithms.has(v))];
18311830
}
18321831
const results = await Promise.allSettled(
18331832
dictionary.map(([algo, [value]]) => {
1834-
if (!hashAlgorithms.includes(algo.toLowerCase())) {
1833+
if (!acceptableAlgorithms.includes(algo.toLowerCase())) {
18351834
return Promise.resolve(null);
18361835
}
18371836
if (!(value instanceof sh.ByteSequence)) {
@@ -1873,7 +1872,7 @@ async function verifyDigestHeader(request, rawBody, opts = {
18731872
return await verifyRFC9530DigestHeader(
18741873
request,
18751874
rawBody,
1876-
{ failOnNoDigest, verifyAll, hashAlgorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) },
1875+
{ failOnNoDigest, verifyAll, algorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) },
18771876
errorLogger
18781877
);
18791878
} else if (headerKeys.has("digest")) {

dist/index.mjs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,7 @@ async function verifyRFC3230DigestHeader(request, rawBody, opts = {
15181518
algorithms: ["SHA-256", "SHA-512"]
15191519
}, errorLogger) {
15201520
const failOnNoDigest = typeof opts === "boolean" ? opts : opts.failOnNoDigest;
1521-
const algorithms = typeof opts === "boolean" ? ["SHA-256", "SHA-512"] : opts.algorithms;
1521+
const algorithms = typeof opts === "boolean" ? ["SHA-256", "SHA-512"] : opts.algorithms.map((algo2) => algo2.toUpperCase());
15221522
const digestHeader = getHeaderValue(collectHeaders(request), "digest");
15231523
if (!digestHeader) {
15241524
if (failOnNoDigest) {
@@ -1540,12 +1540,13 @@ async function verifyRFC3230DigestHeader(request, rawBody, opts = {
15401540
return false;
15411541
}
15421542
const value = base642.parse(match[2]);
1543-
const algo = match[1];
1543+
let algo = match[1];
15441544
if (!algo) {
15451545
if (errorLogger)
15461546
errorLogger(`Invalid Digest header algorithm: ${match[1]}`);
15471547
return false;
15481548
}
1549+
algo = algo.toUpperCase();
15491550
if (!algorithms.includes(algo) && !(algo === "SHA" && algorithms.includes("SHA-1"))) {
15501551
if (errorLogger)
15511552
errorLogger(`Unsupported hash algorithm detected in opts.algorithms: ${algo} (supported: ${algorithms.join(", ")})`);
@@ -1685,7 +1686,7 @@ async function genRFC9530DigestHeader(body, hashAlgorithms = ["SHA-256"], proces
16851686
async function verifyRFC9530DigestHeader(request, rawBody, opts = {
16861687
failOnNoDigest: true,
16871688
verifyAll: true,
1688-
hashAlgorithms: ["sha-256", "sha-512"]
1689+
algorithms: ["sha-256", "sha-512"]
16891690
}, errorLogger) {
16901691
const headers = collectHeaders(request);
16911692
const contentDigestHeader = getHeaderValue(headers, "content-digest");
@@ -1710,27 +1711,25 @@ async function verifyRFC9530DigestHeader(request, rawBody, opts = {
17101711
errorLogger("Digest header is empty");
17111712
return false;
17121713
}
1713-
let hashAlgorithms = (opts.hashAlgorithms || ["sha-256", "sha-512"]).map((v) => v.toLowerCase());
1714-
if (hashAlgorithms.length === 0) {
1714+
let acceptableAlgorithms = (opts.algorithms || ["sha-256", "sha-512"]).map((v) => v.toLowerCase());
1715+
if (acceptableAlgorithms.length === 0) {
17151716
throw new Error("hashAlgorithms is empty");
17161717
}
1717-
for (const algo of hashAlgorithms) {
1718-
if (!isSupportedRFC9530HashAlgorithm(algo)) {
1719-
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms: ${algo} (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(", ")})`);
1720-
}
1718+
if (acceptableAlgorithms.some((algo) => !isSupportedRFC9530HashAlgorithm(algo))) {
1719+
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(", ")})`);
17211720
}
17221721
const dictionaryAlgorithms = dictionary.reduce((prev, [k]) => prev.add(k), /* @__PURE__ */ new Set());
1723-
if (!hashAlgorithms.some((v) => dictionaryAlgorithms.has(v))) {
1722+
if (!acceptableAlgorithms.some((v) => dictionaryAlgorithms.has(v))) {
17241723
if (errorLogger)
17251724
errorLogger("No supported Content-Digest header algorithm");
17261725
return false;
17271726
}
17281727
if (!opts.verifyAll) {
1729-
hashAlgorithms = [hashAlgorithms.find((v) => dictionaryAlgorithms.has(v))];
1728+
acceptableAlgorithms = [acceptableAlgorithms.find((v) => dictionaryAlgorithms.has(v))];
17301729
}
17311730
const results = await Promise.allSettled(
17321731
dictionary.map(([algo, [value]]) => {
1733-
if (!hashAlgorithms.includes(algo.toLowerCase())) {
1732+
if (!acceptableAlgorithms.includes(algo.toLowerCase())) {
17341733
return Promise.resolve(null);
17351734
}
17361735
if (!(value instanceof sh.ByteSequence)) {
@@ -1772,7 +1771,7 @@ async function verifyDigestHeader(request, rawBody, opts = {
17721771
return await verifyRFC9530DigestHeader(
17731772
request,
17741773
rawBody,
1775-
{ failOnNoDigest, verifyAll, hashAlgorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) },
1774+
{ failOnNoDigest, verifyAll, algorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) },
17761775
errorLogger
17771776
);
17781777
} else if (headerKeys.has("digest")) {

src/digest/digest-rfc3230.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ export async function verifyRFC3230DigestHeader(
3636
errorLogger?: ((message: any) => any)
3737
) {
3838
const failOnNoDigest = typeof opts === 'boolean' ? opts : opts.failOnNoDigest;
39-
const algorithms = typeof opts === 'boolean' ? ['SHA-256', 'SHA-512'] : opts.algorithms;
39+
/**
40+
* UPPERCASED
41+
*/
42+
const algorithms = typeof opts === 'boolean' ?
43+
['SHA-256', 'SHA-512']
44+
: opts.algorithms.map((algo) => algo.toUpperCase() as DigestHashAlgorithm);
4045
const digestHeader = getHeaderValue(collectHeaders(request), 'digest');
4146
if (!digestHeader) {
4247
if (failOnNoDigest) {
@@ -58,11 +63,15 @@ export async function verifyRFC3230DigestHeader(
5863
}
5964
const value = base64.parse(match[2]);
6065

61-
const algo = match[1] as DigestHashAlgorithm;
66+
/**
67+
* UPPERCASED
68+
*/
69+
let algo = match[1] as DigestHashAlgorithm;
6270
if (!algo) {
6371
if (errorLogger) errorLogger(`Invalid Digest header algorithm: ${match[1]}`);
6472
return false;
6573
}
74+
algo = algo.toUpperCase() as DigestHashAlgorithm;
6675
if (!algorithms.includes(algo) && !(algo === 'SHA' && algorithms.includes('SHA-1'))) {
6776
if (errorLogger) errorLogger(`Unsupported hash algorithm detected in opts.algorithms: ${algo} (supported: ${algorithms.join(', ')})`);
6877
return false;

src/digest/digest-rfc9530.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,23 @@ describe('rfc9530', () => {
123123
'content-digest': `sha-256=:${base64Resultes.get('')?.['sha-256']}:, sha-512=:${base64Resultes.get(body)?.['sha-512']}:`,
124124
}
125125
};
126-
expect(await verifyRFC9530DigestHeader(request as any, '', { verifyAll: false, hashAlgorithms: ['sha-256', 'sha-512'] })).toBe(true);
126+
expect(await verifyRFC9530DigestHeader(request as any, '', { verifyAll: false, algorithms: ['sha-256', 'sha-512'] })).toBe(true);
127127
});
128128
test('verify one first algorithm fail', async () => {
129129
const request = {
130130
headers: {
131131
'content-digest': `sha-256=:${base64Resultes.get('')?.['sha-256']}:, sha-512=:${base64Resultes.get(body)?.['sha-512']}:`,
132132
}
133133
};
134-
expect(await verifyRFC9530DigestHeader(request as any, '', { verifyAll: false, hashAlgorithms: ['sha-512', 'sha-256'] })).toBe(false);
134+
expect(await verifyRFC9530DigestHeader(request as any, '', { verifyAll: false, algorithms: ['sha-512', 'sha-256'] })).toBe(false);
135135
});
136136
test('algorithms missmatch must fail', async () => {
137137
const request = {
138138
headers: {
139139
'content-digest': `sha-512=:${base64Resultes.get('')?.['sha-512']}:`,
140140
}
141141
};
142-
expect(await verifyRFC9530DigestHeader(request as any, '', { hashAlgorithms: ['sha-256'] })).toBe(false);
142+
expect(await verifyRFC9530DigestHeader(request as any, '', { algorithms: ['sha-256'] })).toBe(false);
143143
});
144144

145145
describe('errors', () => {
@@ -149,16 +149,16 @@ describe('rfc9530', () => {
149149
'content-digest': `sha-256=:${base64Resultes.get('')?.['sha-256']}:`,
150150
}
151151
};
152-
expect(verifyRFC9530DigestHeader(request as any, '', { hashAlgorithms: [] })).rejects.toThrow('hashAlgorithms is empty');
152+
expect(verifyRFC9530DigestHeader(request as any, '', { algorithms: [] })).rejects.toThrow('hashAlgorithms is empty');
153153
});
154154
test('algorithm not supported', async () => {
155155
const request = {
156156
headers: {
157157
'content-digest': `sha-256=:${base64Resultes.get('')?.['sha-256']}:`,
158158
}
159159
};
160-
expect(verifyRFC9530DigestHeader(request as any, '', { hashAlgorithms: ['md5'] })).rejects
161-
.toThrow('Unsupported hash algorithm detected in opts.hashAlgorithms: md5 (supported: sha-256, sha-512)');
160+
expect(verifyRFC9530DigestHeader(request as any, '', { algorithms: ['md5'] })).rejects
161+
.toThrow('Unsupported hash algorithm detected in opts.hashAlgorithms (supported: sha-256, sha-512)');
162162
});
163163
});
164164
});

src/digest/digest-rfc9530.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,11 @@ export async function verifyRFC9530DigestHeader(
182182
* If `varifyAll: false`, it is also used to choose the hash algorithm to verify.
183183
* (Younger index is preferred.)
184184
*/
185-
hashAlgorithms?: RFC9530HashAlgorithm[],
185+
algorithms?: RFC9530HashAlgorithm[],
186186
} = {
187187
failOnNoDigest: true,
188188
verifyAll: true,
189-
hashAlgorithms: ['sha-256', 'sha-512'],
189+
algorithms: ['sha-256', 'sha-512'],
190190
},
191191
errorLogger?: ((message: any) => any)
192192
) {
@@ -200,6 +200,9 @@ export async function verifyRFC9530DigestHeader(
200200
return true;
201201
}
202202

203+
/**
204+
* lowercased
205+
*/
203206
let dictionary: RFC9530DigestHeaderObject;
204207
try {
205208
dictionary = Array.from(sh.parseDictionary(contentDigestHeader), ([k, v]) => [k.toLowerCase(), v]) as RFC9530DigestHeaderObject;
@@ -213,27 +216,31 @@ export async function verifyRFC9530DigestHeader(
213216
return false;
214217
}
215218

216-
let hashAlgorithms = (opts.hashAlgorithms || ['sha-256', 'sha-512']).map(v => v.toLowerCase());
217-
if (hashAlgorithms.length === 0) {
219+
/**
220+
* lowercased
221+
*/
222+
let acceptableAlgorithms = (opts.algorithms || ['sha-256', 'sha-512']).map(v => v.toLowerCase());
223+
if (acceptableAlgorithms.length === 0) {
218224
throw new Error('hashAlgorithms is empty');
219225
}
220-
for (const algo of hashAlgorithms) {
221-
if (!isSupportedRFC9530HashAlgorithm(algo)) {
222-
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms: ${algo} (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(', ')})`);
223-
}
226+
if (acceptableAlgorithms.some(algo => !isSupportedRFC9530HashAlgorithm(algo))) {
227+
throw new Error(`Unsupported hash algorithm detected in opts.hashAlgorithms (supported: ${supportedHashAlgorithmsWithRFC9530AndWebCrypto.join(', ')})`);
224228
}
229+
/**
230+
* lowercased (from dictionary)
231+
*/
225232
const dictionaryAlgorithms = dictionary.reduce((prev, [k]) => prev.add(k), new Set<string>());
226-
if (!hashAlgorithms.some(v => dictionaryAlgorithms.has(v))) {
233+
if (!acceptableAlgorithms.some(v => dictionaryAlgorithms.has(v))) {
227234
if (errorLogger) errorLogger('No supported Content-Digest header algorithm');
228235
return false;
229236
}
230237
if (!opts.verifyAll) {
231-
hashAlgorithms = [hashAlgorithms.find(v => dictionaryAlgorithms.has(v))!];
238+
acceptableAlgorithms = [acceptableAlgorithms.find(v => dictionaryAlgorithms.has(v))!];
232239
}
233240

234241
const results = await Promise.allSettled(
235242
dictionary.map(([algo, [value]]) => {
236-
if (!hashAlgorithms.includes(algo.toLowerCase() as RFC9530HashAlgorithm)) {
243+
if (!acceptableAlgorithms.includes(algo.toLowerCase() as RFC9530HashAlgorithm)) {
237244
return Promise.resolve(null);
238245
}
239246
if (!(value instanceof sh.ByteSequence)) {

src/digest/digest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export async function verifyDigestHeader(
3939
if (headerKeys.has('content-digest')) {
4040
return await verifyRFC9530DigestHeader(
4141
request, rawBody,
42-
{ failOnNoDigest, verifyAll, hashAlgorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) }, errorLogger,
42+
{ failOnNoDigest, verifyAll, algorithms: algorithms.map(convertHashAlgorithmFromWebCryptoToRFC9530) }, errorLogger,
4343
);
4444
} else if (headerKeys.has('digest')) {
4545
return await verifyRFC3230DigestHeader(

0 commit comments

Comments
 (0)