1 | const { JOSECritNotUnderstood, JWSInvalid } = require('../errors')
|
2 |
|
3 | const DEFINED = new Set([
|
4 | 'alg', 'jku', 'jwk', 'kid', 'x5u', 'x5c', 'x5t', 'x5t#S256', 'typ', 'cty',
|
5 | 'crit', 'enc', 'zip', 'epk', 'apu', 'apv', 'iv', 'tag', 'p2s', 'p2c'
|
6 | ])
|
7 |
|
8 | module.exports = function validateCrit (Err, protectedHeader, unprotectedHeader, understood) {
|
9 | if (protectedHeader && 'crit' in protectedHeader) {
|
10 | if (
|
11 | !Array.isArray(protectedHeader.crit) ||
|
12 | protectedHeader.crit.length === 0 ||
|
13 | protectedHeader.crit.some(s => typeof s !== 'string' || !s)
|
14 | ) {
|
15 | throw new Err('"crit" Header Parameter MUST be an array of non-empty strings when present')
|
16 | }
|
17 | const whitelisted = new Set(understood)
|
18 | const combined = { ...protectedHeader, ...unprotectedHeader }
|
19 | protectedHeader.crit.forEach((parameter) => {
|
20 | if (DEFINED.has(parameter)) {
|
21 | throw new Err(`The critical list contains a non-extension Header Parameter ${parameter}`)
|
22 | }
|
23 | if (!whitelisted.has(parameter)) {
|
24 | throw new JOSECritNotUnderstood(`critical "${parameter}" is not understood`)
|
25 | }
|
26 | if (parameter === 'b64') {
|
27 | if (!('b64' in protectedHeader)) {
|
28 | throw new JWSInvalid('"b64" critical parameter must be integrity protected')
|
29 | }
|
30 | if (typeof protectedHeader.b64 !== 'boolean') {
|
31 | throw new JWSInvalid('"b64" critical parameter must be a boolean')
|
32 | }
|
33 | } else if (!(parameter in combined)) {
|
34 | throw new Err(`critical parameter "${parameter}" is missing`)
|
35 | }
|
36 | })
|
37 | }
|
38 | if (unprotectedHeader && 'crit' in unprotectedHeader) {
|
39 | throw new Err('"crit" Header Parameter MUST be integrity protected when present')
|
40 | }
|
41 | }
|