@blamejs/pki 0.8.3 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/lib/guard-parsed.js +2 -2
- package/lib/schema-attrcert.js +36 -26
- package/lib/schema-c509.js +72 -42
- package/lib/schema-cmc.js +25 -22
- package/lib/schema-cmp.js +8 -8
- package/lib/schema-cms.js +39 -28
- package/lib/schema-crl.js +11 -11
- package/lib/schema-crmf.js +11 -6
- package/lib/schema-csrattrs.js +8 -6
- package/lib/schema-engine.js +65 -2
- package/lib/schema-ocsp.js +17 -16
- package/lib/schema-pkcs12.js +15 -11
- package/lib/schema-pkcs8.js +9 -2
- package/lib/schema-pkix.js +44 -17
- package/lib/schema-tsp.js +16 -3
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/schema-cmp.js
CHANGED
|
@@ -283,7 +283,7 @@ var GEN_MSG_CONTENT = schema.seqOf(INFO_TYPE_AND_VALUE, {
|
|
|
283
283
|
build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
|
|
284
284
|
});
|
|
285
285
|
|
|
286
|
-
var CERT_TEMPLATE_LEAF = schema.decode(function (n) { return crmf.walkCertTemplate(n); });
|
|
286
|
+
var CERT_TEMPLATE_LEAF = schema.decode(function (n, ctx) { return crmf.walkCertTemplate(n, ctx); });
|
|
287
287
|
var REV_DETAILS = schema.seq([
|
|
288
288
|
schema.field("certDetails", CERT_TEMPLATE_LEAF),
|
|
289
289
|
schema.optional("crlEntryDetails", EXTENSIONS, { whenUniversal: [TAGS.SEQUENCE] }),
|
|
@@ -348,7 +348,7 @@ var ENCRYPTED_KEY = schema.choice([
|
|
|
348
348
|
{ when: { tagClass: "context", tagNumber: 0 },
|
|
349
349
|
schema: schema.decode(function (n, ctx) {
|
|
350
350
|
var env;
|
|
351
|
-
try { env = cms.walkEnvelopedData(
|
|
351
|
+
try { env = cms.walkEnvelopedData(pkix.decodeNested(asn1.sequenceTlv(n), ctx, "an EncryptedKey envelopedData"), ctx); }
|
|
352
352
|
catch (e) {
|
|
353
353
|
throw ctx.E("cmp/bad-cert-response", "envelopedData [0] must be a well-formed IMPLICIT EnvelopedData (RFC 9810 sec. 5.2.2)", e);
|
|
354
354
|
}
|
|
@@ -521,7 +521,7 @@ var BODY = schema.decode(function (n, ctx) {
|
|
|
521
521
|
var out = { arm: BODY_ARMS[n.tagNumber], tag: n.tagNumber, bytes: inner.bytes };
|
|
522
522
|
if (CRMF_ARMS[n.tagNumber]) {
|
|
523
523
|
var isCcr = n.tagNumber === 13;
|
|
524
|
-
out.decoded = crmf.walkCertReqMessages(inner, { allowSigningAlg: isCcr, allowV1Version: isCcr });
|
|
524
|
+
out.decoded = crmf.walkCertReqMessages(inner, { allowSigningAlg: isCcr, allowV1Version: isCcr }, ctx);
|
|
525
525
|
} else if (DECODED_ARMS[n.tagNumber]) {
|
|
526
526
|
var match = schema.walk(DECODED_ARMS[n.tagNumber], inner, ctx);
|
|
527
527
|
out.decoded = match.result;
|
|
@@ -612,7 +612,7 @@ var PKI_MESSAGE = schema.seq([
|
|
|
612
612
|
for (var cn = 0; cn < controls.length; cn++) {
|
|
613
613
|
if (controls[cn].type !== OID_PKI_ARCHIVE_OPTIONS) continue;
|
|
614
614
|
var arch;
|
|
615
|
-
try { arch =
|
|
615
|
+
try { arch = pkix.decodeNested(controls[cn].value, ctx, "a pkiArchiveOptions control value"); }
|
|
616
616
|
catch (e) { throw ctx.E("cmp/bad-body", "a ccr pkiArchiveOptions control did not decode (RFC 9810 sec. 5.3.11)", e); }
|
|
617
617
|
if (arch.tagClass === "context" && arch.tagNumber === 0) {
|
|
618
618
|
throw ctx.E("cmp/bad-body", "a cross-certification request (ccr) must not send the private key -- a pkiArchiveOptions encryptedPrivKey control is forbidden (RFC 9810 sec. 5.3.11, sec. 5.2.8.3.1)");
|
|
@@ -631,7 +631,7 @@ var PKI_MESSAGE = schema.seq([
|
|
|
631
631
|
if (archCtrls && header.pvno !== 3) {
|
|
632
632
|
for (var ac = 0; ac < archCtrls.length; ac++) {
|
|
633
633
|
if (archCtrls[ac].type !== OID_PKI_ARCHIVE_OPTIONS) continue;
|
|
634
|
-
var opt =
|
|
634
|
+
var opt = pkix.decodeNested(archCtrls[ac].value, ctx, "a pkiArchiveOptions control value");
|
|
635
635
|
if (opt.tagClass === "context" && opt.tagNumber === 0 && opt.children && opt.children.length >= 1 &&
|
|
636
636
|
opt.children[0].tagClass === "context" && opt.children[0].tagNumber === 0) {
|
|
637
637
|
throw ctx.E("cmp/bad-version", "a pkiArchiveOptions encryptedPrivKey using the EnvelopedData form requires CMP version cmp2021(3) (RFC 9810 sec. 5.2.8.3.1, sec. 7)");
|
|
@@ -643,7 +643,7 @@ var PKI_MESSAGE = schema.seq([
|
|
|
643
643
|
if (header.generalInfo) {
|
|
644
644
|
for (var gi = 0; gi < header.generalInfo.length; gi++) {
|
|
645
645
|
if (header.generalInfo[gi].type !== OID_CERT_PROFILE) continue;
|
|
646
|
-
var profileCount =
|
|
646
|
+
var profileCount = pkix.decodeNested(header.generalInfo[gi].value, ctx, "a certProfile infoValue").children.length;
|
|
647
647
|
var bodyCount = null;
|
|
648
648
|
if (body.arm === "p10cr") bodyCount = 1;
|
|
649
649
|
else if (body.decoded && body.decoded.messages) bodyCount = body.decoded.messages.length;
|
|
@@ -654,13 +654,13 @@ var PKI_MESSAGE = schema.seq([
|
|
|
654
654
|
}
|
|
655
655
|
}
|
|
656
656
|
if (body.arm === "ckuann" && header.pvno !== 3) {
|
|
657
|
-
var caKeyUpd =
|
|
657
|
+
var caKeyUpd = pkix.decodeNested(body.bytes, ctx, "a ckuann body");
|
|
658
658
|
if (caKeyUpd.tagClass === "context" && caKeyUpd.tagNumber === 0) {
|
|
659
659
|
throw ctx.E("cmp/bad-version", "a ckuann using the cAKeyUpdAnnV3 [0] RootCaKeyUpdateContent form requires CMP version cmp2021(3) (RFC 9810 sec. 5.3.13, sec. 7)");
|
|
660
660
|
}
|
|
661
661
|
}
|
|
662
662
|
if (body.arm === "popdecc" && header.pvno !== 3) {
|
|
663
|
-
var challenges =
|
|
663
|
+
var challenges = pkix.decodeNested(body.bytes, ctx, "a popdecc body");
|
|
664
664
|
if (challenges.tagClass === "universal" && challenges.tagNumber === TAGS.SEQUENCE && challenges.children) {
|
|
665
665
|
for (var chi = 0; chi < challenges.children.length; chi++) {
|
|
666
666
|
var chKids = challenges.children[chi].children;
|
package/lib/schema-cms.js
CHANGED
|
@@ -127,7 +127,7 @@ function _checkAttrPlacement(attrs, place) {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
function _checkContentBindingAttrs(attrs, mode) {
|
|
130
|
+
function _checkContentBindingAttrs(attrs, mode, ctx) {
|
|
131
131
|
var ct = 0, md = 0, seen = Object.create(null);
|
|
132
132
|
for (var i = 0; i < attrs.length; i++) {
|
|
133
133
|
var a = attrs[i];
|
|
@@ -141,16 +141,16 @@ function _checkContentBindingAttrs(attrs, mode) {
|
|
|
141
141
|
ct += 1;
|
|
142
142
|
if (mode === "countersig") throw NS.E("cms/misplaced-attr", "a countersignature's signedAttrs must not carry a content-type attribute (RFC 5652 sec. 11.4)");
|
|
143
143
|
if (a.values.length !== 1) throw NS.E("cms/bad-content-type-attr", "the content-type attribute must be single-valued");
|
|
144
|
-
try { asn1.read.oid(
|
|
144
|
+
try { asn1.read.oid(pkix.decodeNested(a.values[0], ctx, "a content-type attribute value")); }
|
|
145
145
|
catch (e) { throw NS.E("cms/bad-content-type-attr", "the content-type attribute value must be a valid OBJECT IDENTIFIER", e); }
|
|
146
146
|
} else if (a.type === OID_MESSAGE_DIGEST) {
|
|
147
147
|
md += 1;
|
|
148
148
|
if (a.values.length !== 1) throw NS.E("cms/bad-message-digest-attr", "the message-digest attribute must be single-valued");
|
|
149
|
-
try { asn1.read.octetString(
|
|
149
|
+
try { asn1.read.octetString(pkix.decodeNested(a.values[0], ctx, "a message-digest attribute value")); }
|
|
150
150
|
catch (e) { throw NS.E("cms/bad-message-digest-attr", "the message-digest attribute value must be an OCTET STRING", e); }
|
|
151
151
|
} else if (a.type === OID_SIGNING_TIME) {
|
|
152
152
|
if (a.values.length !== 1) throw NS.E("cms/bad-signing-time-attr", "the signing-time attribute must be single-valued (RFC 5652 sec. 11.3)");
|
|
153
|
-
try { asn1.read.time(
|
|
153
|
+
try { asn1.read.time(pkix.decodeNested(a.values[0], ctx, "a signing-time attribute value")); }
|
|
154
154
|
catch (e) { throw NS.E("cms/bad-signing-time-attr", "the signing-time attribute value must be a Time (RFC 5652 sec. 11.3)", e); }
|
|
155
155
|
}
|
|
156
156
|
}
|
|
@@ -187,6 +187,7 @@ function _ascendingDer(nodes) {
|
|
|
187
187
|
function looksLikeSignedAttributes(bytes) {
|
|
188
188
|
if (!bytes || !bytes.length) return false;
|
|
189
189
|
var node;
|
|
190
|
+
// allow:bare-decode a shape probe on bytes a caller hands the signer or verifier, outside any parse.
|
|
190
191
|
try { node = asn1.decode(bytes); }
|
|
191
192
|
catch (_e) { return false; }
|
|
192
193
|
if (!schema.isUniversal(node, asn1.TAGS.SET) || !node.constructed) return false;
|
|
@@ -225,12 +226,12 @@ function looksLikeSignedAttributes(bytes) {
|
|
|
225
226
|
return sawContentType && sawMessageDigest;
|
|
226
227
|
}
|
|
227
228
|
|
|
228
|
-
function _assertContentTypeMatchesAttrs(attrs, eContentType) {
|
|
229
|
+
function _assertContentTypeMatchesAttrs(attrs, eContentType, ctx) {
|
|
229
230
|
for (var i = 0; i < attrs.length; i++) {
|
|
230
231
|
if (attrs[i].type !== OID_CONTENT_TYPE) continue;
|
|
231
232
|
if (attrs[i].values.length !== 1) throw NS.E("cms/bad-content-type-attr", "the content-type attribute must be single-valued (RFC 5652 sec. 11.1)");
|
|
232
233
|
var ctv;
|
|
233
|
-
try { ctv = asn1.read.oid(
|
|
234
|
+
try { ctv = asn1.read.oid(pkix.decodeNested(attrs[i].values[0], ctx, "a content-type attribute value")); }
|
|
234
235
|
catch (e) { throw NS.E("cms/bad-content-type-attr", "the content-type attribute value must be a valid OBJECT IDENTIFIER", e); }
|
|
235
236
|
if (ctv !== eContentType) throw NS.E("cms/content-type-mismatch", "the content-type attribute (" + ctv + ") must equal the eContentType (" + eContentType + ") (RFC 5652 sec. 5.3)");
|
|
236
237
|
}
|
|
@@ -244,13 +245,13 @@ function _checkNoDuplicateAttrs(attrs) {
|
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
|
|
247
|
-
function _validateAeadParams(alg, macLen) {
|
|
248
|
+
function _validateAeadParams(alg, macLen, ctx) {
|
|
248
249
|
var kind = AEAD_ALGS[alg.oid];
|
|
249
250
|
if (!kind) return null;
|
|
250
251
|
var K = kind.toUpperCase();
|
|
251
252
|
if (alg.parameters === null) throw NS.E("cms/bad-aead-params", "an AES-" + K + " content-encryption algorithm MUST carry its parameters (RFC 5084 sec. 3." + (kind === "gcm" ? "2" : "1") + ")");
|
|
252
253
|
var node;
|
|
253
|
-
try { node =
|
|
254
|
+
try { node = pkix.decodeNested(alg.parameters, ctx, "AES-" + K + " content-encryption parameters"); }
|
|
254
255
|
catch (e) { throw NS.E("cms/bad-aead-params", "malformed AES-" + K + " parameters", e); }
|
|
255
256
|
if (node.tagClass !== "universal" || node.tagNumber !== T.SEQUENCE || !node.children || node.children.length < 1 || node.children.length > 2) {
|
|
256
257
|
throw NS.E("cms/bad-aead-params", "AES-" + K + " parameters must be a SEQUENCE { aes-nonce, aes-ICVlen DEFAULT 12 } (RFC 5084)");
|
|
@@ -275,8 +276,8 @@ function _validateAeadParams(alg, macLen) {
|
|
|
275
276
|
return { kind: kind, nonce: nonce, icvLen: icvLen };
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
function _assertDerEncodedAttrs(node, code) {
|
|
279
|
-
try {
|
|
279
|
+
function _assertDerEncodedAttrs(node, code, ctx) {
|
|
280
|
+
try { pkix.decodeNested(node.bytes, ctx, "an attribute set"); }
|
|
280
281
|
catch (e) { throw NS.E(code, "the attribute set must be DER encoded even inside a BER envelope (RFC 5652 sec. 5.3)", e); }
|
|
281
282
|
}
|
|
282
283
|
|
|
@@ -373,10 +374,10 @@ function makeSignerInfo(mode) {
|
|
|
373
374
|
}
|
|
374
375
|
var signedAttrs = null, signedAttrsBytes = null;
|
|
375
376
|
if (m.fields.signedAttrs.present) {
|
|
376
|
-
_assertDerEncodedAttrs(m.fields.signedAttrs.node, "cms/bad-signed-attrs");
|
|
377
|
+
_assertDerEncodedAttrs(m.fields.signedAttrs.node, "cms/bad-signed-attrs", ctx);
|
|
377
378
|
signedAttrs = m.fields.signedAttrs.value.items.map(function (it) { return it.value.result; });
|
|
378
379
|
_checkAttrPlacement(signedAttrs, "signed");
|
|
379
|
-
_checkContentBindingAttrs(signedAttrs, mode);
|
|
380
|
+
_checkContentBindingAttrs(signedAttrs, mode, ctx);
|
|
380
381
|
signedAttrsBytes = m.fields.signedAttrs.node.bytes;
|
|
381
382
|
}
|
|
382
383
|
var unsignedAttrs = null;
|
|
@@ -387,7 +388,7 @@ function makeSignerInfo(mode) {
|
|
|
387
388
|
if (unsignedAttrs[u].type !== OID_COUNTERSIGNATURE) continue;
|
|
388
389
|
for (var v = 0; v < unsignedAttrs[u].values.length; v++) {
|
|
389
390
|
var csNode;
|
|
390
|
-
try { csNode =
|
|
391
|
+
try { csNode = pkix.decodeNested(unsignedAttrs[u].values[v], ctx, "a countersignature attribute value"); }
|
|
391
392
|
catch (e) { throw NS.E("cms/bad-countersignature", "a countersignature attribute value must be DER (RFC 5652 sec. 11.4)", e); }
|
|
392
393
|
schema.walk(COUNTERSIGNATURE_SIGNER_INFO, csNode, ctx);
|
|
393
394
|
}
|
|
@@ -418,7 +419,7 @@ var SIGNED_DATA = schema.seq([
|
|
|
418
419
|
schema.field("signerInfos", schema.setOf(SIGNER_INFO, { min: 0, code: "cms/bad-signer-infos", what: "signerInfos" })),
|
|
419
420
|
], {
|
|
420
421
|
assert: "sequence", code: "cms/bad-signed-data", what: "SignedData",
|
|
421
|
-
build: function (m) {
|
|
422
|
+
build: function (m, ctx) {
|
|
422
423
|
var version = m.fields.version.value;
|
|
423
424
|
var encapContentInfo = m.fields.encapContentInfo.value.result;
|
|
424
425
|
var certificates = m.fields.certificates.present ? m.fields.certificates.value.items.map(rawChoiceElement(CERT_CHOICE_TAGS, "cms/bad-certificates", "certificates")) : [];
|
|
@@ -432,7 +433,7 @@ var SIGNED_DATA = schema.seq([
|
|
|
432
433
|
}
|
|
433
434
|
|
|
434
435
|
for (var si = 0; si < signerInfos.length; si++) {
|
|
435
|
-
if (signerInfos[si].signedAttrs) _assertContentTypeMatchesAttrs(signerInfos[si].signedAttrs, encapContentInfo.eContentType);
|
|
436
|
+
if (signerInfos[si].signedAttrs) _assertContentTypeMatchesAttrs(signerInfos[si].signedAttrs, encapContentInfo.eContentType, ctx);
|
|
436
437
|
}
|
|
437
438
|
|
|
438
439
|
var expected = _expectedSignedDataVersion(certificates, crls, signerInfos, encapContentInfo.eContentType);
|
|
@@ -771,7 +772,7 @@ var AUTHENTICATED_DATA = schema.seq([
|
|
|
771
772
|
schema.optional("unauthAttrs", schema.implicitSetOf(3, ATTRIBUTE, { min: 1, code: "cms/bad-unauth-attrs", what: "unauthAttrs" }), { tag: 3 }),
|
|
772
773
|
], {
|
|
773
774
|
assert: "sequence", code: "cms/bad-auth-data", what: "AuthenticatedData",
|
|
774
|
-
build: function (m) {
|
|
775
|
+
build: function (m, ctx) {
|
|
775
776
|
var version = m.fields.version.value;
|
|
776
777
|
var originatorInfo = m.fields.originatorInfo.present ? m.fields.originatorInfo.value.result : null;
|
|
777
778
|
var encapContentInfo = m.fields.encapContentInfo.value.result;
|
|
@@ -789,11 +790,11 @@ var AUTHENTICATED_DATA = schema.seq([
|
|
|
789
790
|
|
|
790
791
|
var authAttrs = null, authAttrsBytes = null;
|
|
791
792
|
if (hasAuthAttrs) {
|
|
792
|
-
_assertDerEncodedAttrs(m.fields.authAttrs.node, "cms/bad-auth-attrs");
|
|
793
|
+
_assertDerEncodedAttrs(m.fields.authAttrs.node, "cms/bad-auth-attrs", ctx);
|
|
793
794
|
authAttrs = m.fields.authAttrs.value.items.map(function (it) { return it.value.result; });
|
|
794
795
|
_checkAttrPlacement(authAttrs, "auth");
|
|
795
|
-
_checkContentBindingAttrs(authAttrs, "content");
|
|
796
|
-
_assertContentTypeMatchesAttrs(authAttrs, encapContentInfo.eContentType);
|
|
796
|
+
_checkContentBindingAttrs(authAttrs, "content", ctx);
|
|
797
|
+
_assertContentTypeMatchesAttrs(authAttrs, encapContentInfo.eContentType, ctx);
|
|
797
798
|
authAttrsBytes = m.fields.authAttrs.node.bytes;
|
|
798
799
|
}
|
|
799
800
|
var unauthAttrs = null;
|
|
@@ -826,10 +827,10 @@ var AUTH_ENVELOPED_DATA = schema.seq([
|
|
|
826
827
|
schema.optional("unauthAttrs", schema.implicitSetOf(2, ATTRIBUTE, { min: 1, code: "cms/bad-unauth-attrs", what: "unauthAttrs" }), { tag: 2 }),
|
|
827
828
|
], {
|
|
828
829
|
assert: "sequence", code: "cms/bad-auth-enveloped-data", what: "AuthEnvelopedData",
|
|
829
|
-
build: function (m) {
|
|
830
|
+
build: function (m, ctx) {
|
|
830
831
|
var encryptedContentInfo = m.fields.authEncryptedContentInfo.value.result;
|
|
831
832
|
var mac = m.fields.mac.value;
|
|
832
|
-
var aead = _validateAeadParams(encryptedContentInfo.contentEncryptionAlgorithm, mac.length);
|
|
833
|
+
var aead = _validateAeadParams(encryptedContentInfo.contentEncryptionAlgorithm, mac.length, ctx);
|
|
833
834
|
|
|
834
835
|
var hasAuthAttrs = m.fields.authAttrs.present;
|
|
835
836
|
if (!hasAuthAttrs && encryptedContentInfo.contentType !== OID_DATA) {
|
|
@@ -837,11 +838,11 @@ var AUTH_ENVELOPED_DATA = schema.seq([
|
|
|
837
838
|
}
|
|
838
839
|
var authAttrs = null, authAttrsBytes = null;
|
|
839
840
|
if (hasAuthAttrs) {
|
|
840
|
-
_assertDerEncodedAttrs(m.fields.authAttrs.node, "cms/bad-auth-attrs");
|
|
841
|
+
_assertDerEncodedAttrs(m.fields.authAttrs.node, "cms/bad-auth-attrs", ctx);
|
|
841
842
|
authAttrs = m.fields.authAttrs.value.items.map(function (it) { return it.value.result; });
|
|
842
843
|
_checkAttrPlacement(authAttrs, "auth");
|
|
843
844
|
_checkNoDuplicateAttrs(authAttrs);
|
|
844
|
-
_assertContentTypeMatchesAttrs(authAttrs, encryptedContentInfo.contentType);
|
|
845
|
+
_assertContentTypeMatchesAttrs(authAttrs, encryptedContentInfo.contentType, ctx);
|
|
845
846
|
authAttrsBytes = m.fields.authAttrs.node.bytes;
|
|
846
847
|
}
|
|
847
848
|
var unauthAttrs = null;
|
|
@@ -1030,13 +1031,23 @@ function matches(root) {
|
|
|
1030
1031
|
return true;
|
|
1031
1032
|
}
|
|
1032
1033
|
|
|
1033
|
-
|
|
1034
|
+
/** @internal `ctx` is the walk context of the parse that reached this structure, when another
|
|
1035
|
+
* format carries it. Only its caps and budget cross over: a cap the caller named at that
|
|
1036
|
+
* format's door has to reach this walk, and a fault in this structure is still CMS's to report. */
|
|
1037
|
+
function walkEnvelopedData(node, ctx) {
|
|
1038
|
+
return schema.walk(ENVELOPED_DATA, node, schema.withResources(NS, ctx)).result;
|
|
1039
|
+
}
|
|
1034
1040
|
|
|
1035
|
-
var walkSignedData = guard.parsed.recordingWalker("cms", function (node) {
|
|
1036
|
-
return schema.walk(SIGNED_DATA, node, NS).result;
|
|
1041
|
+
var walkSignedData = guard.parsed.recordingWalker("cms", function (node, ctx) {
|
|
1042
|
+
return schema.walk(SIGNED_DATA, node, schema.withResources(NS, ctx)).result;
|
|
1043
|
+
// allow:bare-decode the re-decode a recording walker performs on raw DER a caller hands it, outside any parse.
|
|
1037
1044
|
}, function (der) { return asn1.decode(der, { ber: true }); });
|
|
1038
|
-
function walkEncryptedData(node
|
|
1039
|
-
|
|
1045
|
+
function walkEncryptedData(node, ctx) {
|
|
1046
|
+
return schema.walk(ENCRYPTED_DATA, node, schema.withResources(NS, ctx)).result;
|
|
1047
|
+
}
|
|
1048
|
+
function walkCountersignature(node, ctx) {
|
|
1049
|
+
return schema.walk(COUNTERSIGNATURE_SIGNER_INFO, node, schema.withResources(NS, ctx)).result;
|
|
1050
|
+
}
|
|
1040
1051
|
|
|
1041
1052
|
function assertAttachedCiphertext(eci, E, code, label) {
|
|
1042
1053
|
if (!eci || eci.encryptedContent === null || eci.encryptedContent.length === 0) {
|
package/lib/schema-crl.js
CHANGED
|
@@ -51,20 +51,20 @@ var TIME = pkix.time(NS);
|
|
|
51
51
|
|
|
52
52
|
var CRL_VERSION = pkix.versionReader(NS, { "1": 2 });
|
|
53
53
|
|
|
54
|
-
function decodeExt(ext, scope) {
|
|
54
|
+
function decodeExt(ext, scope, ctx) {
|
|
55
55
|
var value = ext.value;
|
|
56
56
|
var atCrl = scope !== "entry";
|
|
57
57
|
var atEntry = scope !== "crl";
|
|
58
58
|
try {
|
|
59
59
|
if (ext.oid === OID_CRL_NUMBER && atCrl) {
|
|
60
|
-
value = asn1.read.integer(
|
|
60
|
+
value = asn1.read.integer(pkix.decodeNested(ext.value, ctx, "a cRLNumber extension value"));
|
|
61
61
|
if (value < 0n) throw new Error("cRLNumber must be non-negative (INTEGER 0..MAX)");
|
|
62
62
|
} else if (ext.oid === OID_REASON_CODE && atEntry) {
|
|
63
|
-
var reason = asn1.read.enumerated(
|
|
63
|
+
var reason = asn1.read.enumerated(pkix.decodeNested(ext.value, ctx, "a reasonCode extension value"));
|
|
64
64
|
if (!_hasOwn(CRL_REASONS, reason.toString())) throw new Error("undefined CRLReason " + reason.toString());
|
|
65
65
|
value = Number(reason);
|
|
66
66
|
} else if (ext.oid === OID_INVALIDITY_DATE && atEntry) {
|
|
67
|
-
var n =
|
|
67
|
+
var n = pkix.decodeNested(ext.value, ctx, "an invalidityDate extension value");
|
|
68
68
|
if (n.tagClass !== "universal" || n.tagNumber !== TAGS.GENERALIZED_TIME) {
|
|
69
69
|
throw new Error("invalidityDate must be a GeneralizedTime");
|
|
70
70
|
}
|
|
@@ -82,13 +82,13 @@ var REVOKED_ENTRY = schema.seq([
|
|
|
82
82
|
schema.optional("crlEntryExtensions", EXTENSIONS, { whenUniversal: [TAGS.SEQUENCE] }),
|
|
83
83
|
], {
|
|
84
84
|
assert: "sequence", arity: { min: 2 }, code: "crl/bad-revoked-entry", what: "RevokedCertificate",
|
|
85
|
-
build: function (m) {
|
|
85
|
+
build: function (m, ctx) {
|
|
86
86
|
return {
|
|
87
87
|
serialNumber: m.fields.userCertificate.value,
|
|
88
88
|
serialNumberHex: m.fields.userCertificate.node.content.toString("hex"),
|
|
89
89
|
revocationDate: m.fields.revocationDate.value,
|
|
90
90
|
crlEntryExtensions: m.fields.crlEntryExtensions.present
|
|
91
|
-
? m.fields.crlEntryExtensions.value.result.map(function (e) { return decodeExt(e, "entry"); })
|
|
91
|
+
? m.fields.crlEntryExtensions.value.result.map(function (e) { return decodeExt(e, "entry", ctx); })
|
|
92
92
|
: [],
|
|
93
93
|
};
|
|
94
94
|
},
|
|
@@ -111,7 +111,7 @@ var TBS_CERTLIST = schema.seq([
|
|
|
111
111
|
{ minTag: 0, maxTag: 0, unexpectedCode: "crl/bad-tbs", orderCode: "crl/bad-tbs" }),
|
|
112
112
|
], {
|
|
113
113
|
assert: "sequence", code: "crl/bad-tbs", what: "tbsCertList",
|
|
114
|
-
build: function (m) {
|
|
114
|
+
build: function (m, ctx) {
|
|
115
115
|
return {
|
|
116
116
|
version: m.fields.version.present ? m.fields.version.value : 1,
|
|
117
117
|
issuer: m.fields.issuer.value.result,
|
|
@@ -119,7 +119,7 @@ var TBS_CERTLIST = schema.seq([
|
|
|
119
119
|
nextUpdate: m.fields.nextUpdate.present ? m.fields.nextUpdate.value : null,
|
|
120
120
|
revokedCertificates: m.fields.revokedCertificates.present ? m.fields.revokedCertificates.value.result : [],
|
|
121
121
|
crlExtensions: m.fields.crlExtensions.present
|
|
122
|
-
? m.fields.crlExtensions.value.result.map(function (e) { return decodeExt(e, "crl"); })
|
|
122
|
+
? m.fields.crlExtensions.value.result.map(function (e) { return decodeExt(e, "crl", ctx); })
|
|
123
123
|
: [],
|
|
124
124
|
crlExtensionsPresent: m.fields.crlExtensions.present,
|
|
125
125
|
};
|
|
@@ -265,10 +265,10 @@ function entryExtensionCriticality(oidRegistry) {
|
|
|
265
265
|
* raw. Returns the record with its decoded `value`; throws `crl/bad-extension-value`. */
|
|
266
266
|
var OID_CERTIFICATE_ISSUER = oid.byName("certificateIssuer");
|
|
267
267
|
var CERTIFICATE_ISSUER_NAMES = pkix.generalNames(NS, { code: "crl/bad-extension-value" });
|
|
268
|
-
function readEntryExtension(ext) {
|
|
269
|
-
if (ext.oid !== OID_CERTIFICATE_ISSUER) return decodeExt(ext);
|
|
268
|
+
function readEntryExtension(ext, ctx) {
|
|
269
|
+
if (ext.oid !== OID_CERTIFICATE_ISSUER) return decodeExt(ext, undefined, ctx);
|
|
270
270
|
var names;
|
|
271
|
-
try { names = schema.walk(CERTIFICATE_ISSUER_NAMES,
|
|
271
|
+
try { names = schema.walk(CERTIFICATE_ISSUER_NAMES, pkix.decodeNested(ext.value, ctx, "a certificateIssuer extension value"), ctx || NS).result; }
|
|
272
272
|
catch (e) {
|
|
273
273
|
throw NS.E("crl/bad-extension-value", "malformed certificateIssuer extension value: " + ((e && e.message) || intrinsic.String(e)), e);
|
|
274
274
|
}
|
package/lib/schema-crmf.js
CHANGED
|
@@ -170,12 +170,12 @@ function popoPrivKey(type) {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
if (inner.tagNumber === 3) {
|
|
173
|
-
try { schema.embeddedDer(PKMAC_VALUE, asn1.sequenceTlv(inner), NS, { code: "crmf/bad-popo", what: "agreeMAC [3] PKMACValue" }); }
|
|
173
|
+
try { schema.embeddedDer(PKMAC_VALUE, asn1.sequenceTlv(inner), schema.withResources(NS, ctx), { code: "crmf/bad-popo", what: "agreeMAC [3] PKMACValue" }); }
|
|
174
174
|
catch (e) { throw ctx.E("crmf/bad-popo", "agreeMAC [3] must be a PKMACValue SEQUENCE { algId, BIT STRING } (RFC 4211 sec. 4.2)", e); }
|
|
175
175
|
}
|
|
176
176
|
if (inner.tagNumber === 4) {
|
|
177
177
|
var env;
|
|
178
|
-
try { env = cms.walkEnvelopedData(
|
|
178
|
+
try { env = cms.walkEnvelopedData(pkix.decodeNested(asn1.sequenceTlv(inner), ctx, "an encryptedKey [4] EnvelopedData"), ctx); }
|
|
179
179
|
catch (e) { throw ctx.E("crmf/bad-popo", "encryptedKey [4] must be a well-formed EnvelopedData (RFC 4211 sec. 4.2, RFC 5652 sec. 6.1)", e); }
|
|
180
180
|
if (env.encryptedContentInfo.contentType !== oid.byName("encKeyWithID")) {
|
|
181
181
|
throw ctx.E("crmf/bad-popo", "encryptedKey [4] EnvelopedData content type MUST be id-ct-encKeyWithID (RFC 4211 sec. 4.2)");
|
|
@@ -414,16 +414,21 @@ function matches(root) {
|
|
|
414
414
|
schema.isUniversal(tpl, TAGS.SEQUENCE) && !!tpl.children;
|
|
415
415
|
}
|
|
416
416
|
|
|
417
|
-
|
|
418
|
-
|
|
417
|
+
/** @internal `outer` is the walk context of the parse that reached these messages, when another
|
|
418
|
+
* format carries them. Only its caps and budget cross over: the messages are still read in this
|
|
419
|
+
* namespace, so a fault in one keeps the CRMF error class and code. */
|
|
420
|
+
function walkCertReqMessages(node, opts, outer) {
|
|
421
|
+
var ctx = schema.withResources(NS, outer);
|
|
419
422
|
if (opts && (opts.allowSigningAlg || opts.allowV1Version)) {
|
|
420
|
-
ctx = Object.assign({},
|
|
423
|
+
ctx = Object.assign({}, ctx);
|
|
421
424
|
if (opts.allowSigningAlg) ctx.allowSigningAlg = true;
|
|
422
425
|
if (opts.allowV1Version) ctx.allowV1Version = true;
|
|
423
426
|
}
|
|
424
427
|
return schema.walk(CERT_REQ_MESSAGES, node, ctx).result;
|
|
425
428
|
}
|
|
426
|
-
function walkCertTemplate(node
|
|
429
|
+
function walkCertTemplate(node, outer) {
|
|
430
|
+
return schema.walk(CERT_TEMPLATE, node, schema.withResources(NS, outer)).result;
|
|
431
|
+
}
|
|
427
432
|
|
|
428
433
|
module.exports = {
|
|
429
434
|
parse: parse,
|
package/lib/schema-csrattrs.js
CHANGED
|
@@ -158,12 +158,13 @@ var CERT_REQ_INFO_TEMPLATE = schema.seq([
|
|
|
158
158
|
hasExtReq = true;
|
|
159
159
|
extReqs += 1;
|
|
160
160
|
if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "a template id-ExtensionReq values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
|
|
161
|
-
extensions = schema.walk(EXTENSIONS,
|
|
161
|
+
extensions = schema.walk(EXTENSIONS, pkix.decodeNested(a.values[0], ctx, "a template id-ExtensionReq value"), ctx).result;
|
|
162
162
|
}
|
|
163
163
|
if (a.type === OID_EXT_REQ_TEMPLATE) {
|
|
164
164
|
extReqTemplates += 1;
|
|
165
165
|
if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "an id-aa-extensionReqTemplate values must be a SET of exactly one ExtensionReqTemplate (RFC 9908 sec. 3.4)");
|
|
166
|
-
extensionTemplates = extensionTemplates.concat(schema.walk(EXTENSION_REQ_TEMPLATE,
|
|
166
|
+
extensionTemplates = extensionTemplates.concat(schema.walk(EXTENSION_REQ_TEMPLATE,
|
|
167
|
+
pkix.decodeNested(a.values[0], ctx, "an id-aa-extensionReqTemplate value"), ctx).result);
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
if (extReqs > 1) throw NS.E("csrattrs/bad-template-attrs", "a template must not carry more than one id-ExtensionReq (RFC 9908 sec. 3.2)");
|
|
@@ -185,25 +186,26 @@ function _enrichAttribute(item, ctx) {
|
|
|
185
186
|
if (KEY_TYPE_OIDS.has(item.oid)) item.isKeyType = true;
|
|
186
187
|
if (item.oid === OID_EXTENSION_REQUEST) {
|
|
187
188
|
if (item.values.length !== 1) throw ctx.E("csrattrs/bad-extension-req", "an id-ExtensionReq attribute values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
|
|
188
|
-
item.extensions = schema.walk(EXTENSIONS,
|
|
189
|
+
item.extensions = schema.walk(EXTENSIONS, pkix.decodeNested(item.values[0], ctx, "an id-ExtensionReq value"), ctx).result;
|
|
189
190
|
} else if (item.oid === OID_EC_PUBLIC_KEY) {
|
|
190
191
|
if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute values must be empty or a SET of exactly one named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)");
|
|
191
192
|
if (item.values.length === 1) {
|
|
192
|
-
try { item.curve = asn1.read.oid(
|
|
193
|
+
try { item.curve = asn1.read.oid(pkix.decodeNested(item.values[0], ctx, "an ecPublicKey attribute value")); }
|
|
193
194
|
catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute value must be a named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)", e); }
|
|
194
195
|
}
|
|
195
196
|
} else if (item.oid === OID_RSA_ENCRYPTION) {
|
|
196
197
|
if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute values must be empty or a SET of exactly one INTEGER key size (RFC 9908 sec. 3.2)");
|
|
197
198
|
if (item.values.length === 1) {
|
|
198
199
|
var sz;
|
|
199
|
-
try { sz = asn1.read.integer(
|
|
200
|
+
try { sz = asn1.read.integer(pkix.decodeNested(item.values[0], ctx, "an rsaEncryption attribute value")); }
|
|
200
201
|
catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute value must be an INTEGER key size (RFC 9908 sec. 3.2)", e); }
|
|
201
202
|
if (sz < 1n || sz > 65536n) throw ctx.E("csrattrs/bad-key-type-attr", "the rsaEncryption key size " + sz + " is out of range (1..65536 bits)");
|
|
202
203
|
item.keySize = Number(sz);
|
|
203
204
|
}
|
|
204
205
|
} else if (item.oid === OID_TEMPLATE) {
|
|
205
206
|
if (item.values.length !== 1) throw ctx.E("csrattrs/bad-template", "a certificationRequestInfoTemplate attribute values must be a SET of exactly one template (RFC 9908 sec. 3.4)");
|
|
206
|
-
item.template = schema.walk(CERT_REQ_INFO_TEMPLATE,
|
|
207
|
+
item.template = schema.walk(CERT_REQ_INFO_TEMPLATE,
|
|
208
|
+
pkix.decodeNested(item.values[0], ctx, "a certificationRequestInfoTemplate value"), ctx).result;
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
|
package/lib/schema-engine.js
CHANGED
|
@@ -75,6 +75,66 @@ function _assertArity(schema, kids, ctx) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
|
|
78
|
+
var RESOURCE_REFUSALS = Object.assign(Object.create(null), {
|
|
79
|
+
"asn1/too-large": 1, "asn1/too-deep": 1, "asn1/too-many-items": 1,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/** @internal The codec's resource refusals, as distinct from its malformed-input refusals. A
|
|
83
|
+
* caller who tightened a cap has to be able to tell "your bytes are wrong" from "your cap is
|
|
84
|
+
* too small", and only the second is answered by raising the cap. */
|
|
85
|
+
function isResourceRefusal(e) {
|
|
86
|
+
return !!(e && typeof e.code === "string" && RESOURCE_REFUSALS[e.code] === 1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @internal Carries a parse's caps and budget onto another namespace. A format whose structure
|
|
90
|
+
* is carried inside another format walks it in its OWN namespace, so a refusal names the domain
|
|
91
|
+
* that owns the fault and keeps its own error class; the caps and the budget are the only things
|
|
92
|
+
* that cross the boundary. Returns `ns` unchanged when there is nothing to carry. */
|
|
93
|
+
function withResources(ns, source) {
|
|
94
|
+
if (!source || (source.caps == null && source.budget == null)) return ns;
|
|
95
|
+
var out = Object.create(null);
|
|
96
|
+
var keys = Object.keys(ns);
|
|
97
|
+
for (var i = 0; i < keys.length; i++) out[keys[i]] = ns[keys[i]];
|
|
98
|
+
out.caps = source.caps;
|
|
99
|
+
out.budget = source.budget;
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** @internal The decode a parse performs on a value it has already read out of its input: an
|
|
104
|
+
* embedded OCTET STRING payload, an encapsulated protocol body. `ctx` is the walk context the
|
|
105
|
+
* door built, so the caps a caller named at the door hold at every level rather than at the
|
|
106
|
+
* root alone, and a resource refusal down here trips the parse budget before the original
|
|
107
|
+
* error is re-thrown. The error itself is re-thrown unchanged, because a format's existing
|
|
108
|
+
* code for a malformed embedded value is one callers pin.
|
|
109
|
+
*
|
|
110
|
+
* `opts.ber` is read once into a local and carries the relaxed acceptance a format whose door
|
|
111
|
+
* is BER-tolerant already applies at the root. The decode options are built fresh per call. */
|
|
112
|
+
function decodeNested(bytes, ctx, label, opts) {
|
|
113
|
+
var caps = ctx ? ctx.caps : null;
|
|
114
|
+
var ber = !!(opts && opts.ber === true);
|
|
115
|
+
var decodeOpts = Object.create(null);
|
|
116
|
+
if (caps) {
|
|
117
|
+
decodeOpts.maxBytes = caps.maxBytes;
|
|
118
|
+
decodeOpts.maxDepth = caps.maxDepth;
|
|
119
|
+
decodeOpts.maxItems = caps.maxItems;
|
|
120
|
+
}
|
|
121
|
+
if (ber) decodeOpts.ber = true;
|
|
122
|
+
try {
|
|
123
|
+
// allow:bare-decode this IS the primitive every other nested decode routes through.
|
|
124
|
+
return asn1.decode(bytes, decodeOpts);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
if (isResourceRefusal(e) && ctx && ctx.budget) {
|
|
127
|
+
try {
|
|
128
|
+
ctx.budget.trip(label || "an embedded value");
|
|
129
|
+
} catch (_b) {
|
|
130
|
+
/* allow:swallow-unverified the latch is the point; the original error is re-thrown below */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
throw e;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// allow:bare-decode a round trip through the codec on an integer this module just encoded.
|
|
78
138
|
function _implicitIntContent(v) { return asn1.decode(asn1.build.integer(v)).content; }
|
|
79
139
|
function oidLeaf() { return { kind: "leaf", read: asn1.read.oid, write: function (v) { return asn1.build.oid(v); } }; }
|
|
80
140
|
function integerLeaf() { return { kind: "leaf", read: asn1.read.integer, write: function (v) { return asn1.build.integer(v); } }; }
|
|
@@ -436,6 +496,7 @@ function _encodeRepeat(schema, items, ctx) {
|
|
|
436
496
|
if (schema.unique) {
|
|
437
497
|
var seen = new Set();
|
|
438
498
|
parts.forEach(function (tlv) {
|
|
499
|
+
// allow:bare-decode a round trip through the codec on a TLV this encoder just produced.
|
|
439
500
|
var item = { node: asn1.decode(tlv) };
|
|
440
501
|
item.value = walk(schema.item, item.node, ctx);
|
|
441
502
|
var key = schema.unique(item);
|
|
@@ -500,7 +561,7 @@ function embeddedDer(schema, bytes, ctx, opts) {
|
|
|
500
561
|
}
|
|
501
562
|
var node;
|
|
502
563
|
try {
|
|
503
|
-
node =
|
|
564
|
+
node = decodeNested(bytes, ctx, opts.what || "embedded DER", { ber: !!opts.ber });
|
|
504
565
|
} catch (e) {
|
|
505
566
|
throw ctx.E(opts.code, (opts.what || "embedded DER") + " did not decode: " + e.message, e);
|
|
506
567
|
}
|
|
@@ -540,7 +601,9 @@ module.exports = {
|
|
|
540
601
|
bitString: bitString, implicitBitString: implicitBitString, implicitOctetString: implicitOctetString,
|
|
541
602
|
implicitNull: implicitNull, implicitInteger: implicitInteger, implicitBoolean: implicitBoolean,
|
|
542
603
|
any: any, decode: decode, time: time,
|
|
543
|
-
walk: walk, encode: encode, embeddedDer: embeddedDer,
|
|
604
|
+
walk: walk, encode: encode, embeddedDer: embeddedDer, decodeNested: decodeNested,
|
|
605
|
+
isResourceRefusal: isResourceRefusal, withResources: withResources,
|
|
606
|
+
assertMinimalNamedBits: assertMinimalNamedBits,
|
|
544
607
|
isUniversal: isUniversal, isContext: isContext,
|
|
545
608
|
isUniversalOneOf: isUniversalOneOf, isContextOneOf: isContextOneOf, isContextInRange: isContextInRange,
|
|
546
609
|
};
|
package/lib/schema-ocsp.js
CHANGED
|
@@ -98,9 +98,9 @@ function _rawSignature(field) {
|
|
|
98
98
|
var CERTS = schema.seqOf(certificateBytes(), { assert: "sequence", code: "ocsp/bad-certs", what: "certs", max: constants.LIMITS.OCSP_MAX_CERTS, maxCode: "ocsp/too-many-certs" });
|
|
99
99
|
|
|
100
100
|
/** @internal RFC 6960 sec. 4.4.4: ArchiveCutoff ::= GeneralizedTime, carried as a singleExtension. */
|
|
101
|
-
function _readArchiveCutoff(ext) {
|
|
101
|
+
function _readArchiveCutoff(ext, ctx) {
|
|
102
102
|
var node;
|
|
103
|
-
try { node =
|
|
103
|
+
try { node = pkix.decodeNested(ext.value, ctx, "an archiveCutoff extension value"); }
|
|
104
104
|
catch (e) { throw NS.E("ocsp/bad-archive-cutoff", "the archiveCutoff extension value did not decode: " + ((e && e.message) || _String(e)), e); }
|
|
105
105
|
if (!(node.tagClass === "universal" && node.tagNumber === asn1.TAGS.GENERALIZED_TIME)) {
|
|
106
106
|
throw NS.E("ocsp/bad-archive-cutoff", "the archiveCutoff extension value must be a GeneralizedTime (RFC 6960 sec. 4.4.4)");
|
|
@@ -112,10 +112,10 @@ function _readArchiveCutoff(ext) {
|
|
|
112
112
|
/** @internal RFC 6960 sec. 4.4.2: CrlID ::= SEQUENCE { crlUrl [0] EXPLICIT IA5String OPTIONAL,
|
|
113
113
|
* crlNum [1] EXPLICIT INTEGER OPTIONAL, crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }. Every
|
|
114
114
|
* field is optional and each may appear at most once, in tag order. */
|
|
115
|
-
function _readCrlId(ext) {
|
|
115
|
+
function _readCrlId(ext, ctx) {
|
|
116
116
|
var C = "ocsp/bad-crl-id";
|
|
117
117
|
var node;
|
|
118
|
-
try { node =
|
|
118
|
+
try { node = pkix.decodeNested(ext.value, ctx, "a crlID extension value"); }
|
|
119
119
|
catch (e) { throw NS.E(C, "the CRL references extension value did not decode: " + ((e && e.message) || _String(e)), e); }
|
|
120
120
|
if (!(node.tagClass === "universal" && node.tagNumber === asn1.TAGS.SEQUENCE && node.children)) {
|
|
121
121
|
throw NS.E(C, "CrlID must be a SEQUENCE (RFC 6960 sec. 4.4.2)");
|
|
@@ -154,15 +154,15 @@ function _readCrlId(ext) {
|
|
|
154
154
|
/** @internal The extensions this profile reads are decoded onto their entry beside the raw value,
|
|
155
155
|
* so a consumer gets the value by name and a malformed one is refused here rather than passed
|
|
156
156
|
* through as opaque bytes. The nonce is RFC 9654; the other two are RFC 6960 sec. 4.4. */
|
|
157
|
-
function _validateOcspExtensions(list) {
|
|
157
|
+
function _validateOcspExtensions(list, ctx) {
|
|
158
158
|
if (!list) return list;
|
|
159
159
|
for (var i = 0; i < list.length; i++) {
|
|
160
160
|
var ext = list[i];
|
|
161
|
-
if (ext.oid === OID_OCSP_ARCHIVE_CUTOFF) { ext.archiveCutoff = _readArchiveCutoff(ext); continue; }
|
|
162
|
-
if (ext.oid === OID_OCSP_CRL) { ext.crlReferences = _readCrlId(ext); continue; }
|
|
161
|
+
if (ext.oid === OID_OCSP_ARCHIVE_CUTOFF) { ext.archiveCutoff = _readArchiveCutoff(ext, ctx); continue; }
|
|
162
|
+
if (ext.oid === OID_OCSP_CRL) { ext.crlReferences = _readCrlId(ext, ctx); continue; }
|
|
163
163
|
if (ext.oid !== OID_OCSP_NONCE) continue;
|
|
164
164
|
var node;
|
|
165
|
-
try { node =
|
|
165
|
+
try { node = pkix.decodeNested(ext.value, ctx, "a nonce extension value"); }
|
|
166
166
|
catch (e) { throw NS.E("ocsp/bad-nonce", "the nonce extension value did not decode: " + ((e && e.message) || String(e)), e); }
|
|
167
167
|
if (!(node.tagClass === "universal" && node.tagNumber === asn1.TAGS.OCTET_STRING && node.content)) {
|
|
168
168
|
throw NS.E("ocsp/bad-nonce", "the nonce extension value must be an OCTET STRING (RFC 9654 sec. 2.1)");
|
|
@@ -244,13 +244,13 @@ var SINGLE_RESPONSE = schema.seq([
|
|
|
244
244
|
], { minTag: 0, maxTag: 1, unexpectedCode: "ocsp/bad-single-response", orderCode: "ocsp/bad-single-response" }),
|
|
245
245
|
], {
|
|
246
246
|
assert: "sequence", code: "ocsp/bad-single-response", what: "SingleResponse",
|
|
247
|
-
build: function (m) {
|
|
247
|
+
build: function (m, ctx) {
|
|
248
248
|
return {
|
|
249
249
|
certID: m.fields.certID.value.result,
|
|
250
250
|
certStatus: _shapeCertStatus(m.fields.certStatus),
|
|
251
251
|
thisUpdate: m.fields.thisUpdate.value,
|
|
252
252
|
nextUpdate: m.fields.nextUpdate.present ? m.fields.nextUpdate.value : null,
|
|
253
|
-
singleExtensions: m.fields.singleExtensions.present ? _validateOcspExtensions(m.fields.singleExtensions.value.result) : null,
|
|
253
|
+
singleExtensions: m.fields.singleExtensions.present ? _validateOcspExtensions(m.fields.singleExtensions.value.result, ctx) : null,
|
|
254
254
|
};
|
|
255
255
|
},
|
|
256
256
|
});
|
|
@@ -277,13 +277,13 @@ var RESPONSE_DATA = schema.seq([
|
|
|
277
277
|
], { minTag: 1, maxTag: 1, unexpectedCode: "ocsp/bad-response-data", orderCode: "ocsp/bad-response-data" }),
|
|
278
278
|
], {
|
|
279
279
|
assert: "sequence", code: "ocsp/bad-response-data", what: "ResponseData",
|
|
280
|
-
build: function (m) {
|
|
280
|
+
build: function (m, ctx) {
|
|
281
281
|
return {
|
|
282
282
|
version: m.fields.version.value,
|
|
283
283
|
responderID: _shapeResponderID(m.fields.responderID),
|
|
284
284
|
producedAt: m.fields.producedAt.value,
|
|
285
285
|
responses: m.fields.responses.value.items.map(function (it) { return it.value.result; }),
|
|
286
|
-
responseExtensions: m.fields.responseExtensions.present ? _validateOcspExtensions(m.fields.responseExtensions.value.result) : null,
|
|
286
|
+
responseExtensions: m.fields.responseExtensions.present ? _validateOcspExtensions(m.fields.responseExtensions.value.result, ctx) : null,
|
|
287
287
|
};
|
|
288
288
|
},
|
|
289
289
|
});
|
|
@@ -362,10 +362,10 @@ var REQUEST = schema.seq([
|
|
|
362
362
|
], { minTag: 0, maxTag: 0, unexpectedCode: "ocsp/bad-request", orderCode: "ocsp/bad-request" }),
|
|
363
363
|
], {
|
|
364
364
|
assert: "sequence", code: "ocsp/bad-request", what: "Request",
|
|
365
|
-
build: function (m) {
|
|
365
|
+
build: function (m, ctx) {
|
|
366
366
|
return {
|
|
367
367
|
certID: m.fields.reqCert.value.result,
|
|
368
|
-
singleRequestExtensions: m.fields.singleRequestExtensions.present ? _validateOcspExtensions(m.fields.singleRequestExtensions.value.result) : null,
|
|
368
|
+
singleRequestExtensions: m.fields.singleRequestExtensions.present ? _validateOcspExtensions(m.fields.singleRequestExtensions.value.result, ctx) : null,
|
|
369
369
|
};
|
|
370
370
|
},
|
|
371
371
|
});
|
|
@@ -396,13 +396,13 @@ var TBS_REQUEST = schema.seq([
|
|
|
396
396
|
], { minTag: 2, maxTag: 2, unexpectedCode: "ocsp/bad-tbs-request", orderCode: "ocsp/bad-tbs-request" }),
|
|
397
397
|
], {
|
|
398
398
|
assert: "sequence", code: "ocsp/bad-tbs-request", what: "TBSRequest",
|
|
399
|
-
build: function (m) {
|
|
399
|
+
build: function (m, ctx) {
|
|
400
400
|
var rn = m.fields.requestorName;
|
|
401
401
|
return {
|
|
402
402
|
version: m.fields.version.value,
|
|
403
403
|
requestorName: rn.present ? { bytes: rn.value.bytes, tagClass: rn.value.tagClass, tagNumber: rn.value.tagNumber, value: rn.value.value } : null,
|
|
404
404
|
requestList: m.fields.requestList.value.items.map(function (it) { return it.value.result; }),
|
|
405
|
-
requestExtensions: m.fields.requestExtensions.present ? _validateOcspExtensions(m.fields.requestExtensions.value.result) : null,
|
|
405
|
+
requestExtensions: m.fields.requestExtensions.present ? _validateOcspExtensions(m.fields.requestExtensions.value.result, ctx) : null,
|
|
406
406
|
};
|
|
407
407
|
},
|
|
408
408
|
});
|
|
@@ -592,6 +592,7 @@ module.exports = {
|
|
|
592
592
|
* reads. Throws the parser's own ocsp/* code for a malformed entry. */
|
|
593
593
|
readSingleExtensionsDer: function (derList) {
|
|
594
594
|
var node;
|
|
595
|
+
// allow:bare-decode reached from the signer, not from a parse, so no parse context carries caps here.
|
|
595
596
|
try { node = asn1.decode(asn1.build.sequence(intrinsic.map(derList, function (d) { return asn1.build.raw(d); }))); }
|
|
596
597
|
catch (e) { throw NS.E("ocsp/bad-single-response", "a pre-encoded singleExtension is not DER", e); }
|
|
597
598
|
return _validateOcspExtensions(schema.walk(EXTENSIONS, node, NS).result);
|