@blamejs/pki 0.8.59 → 0.8.60
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 +33 -0
- package/lib/acme.js +15 -7
- package/lib/alt-sig.js +3 -1
- package/lib/asn1-der.js +82 -34
- package/lib/attrcert-sign.js +19 -16
- package/lib/byte-writer.js +63 -13
- package/lib/cbor-det.js +9 -3
- package/lib/cmc-build.js +12 -9
- package/lib/cmp-build.js +35 -33
- package/lib/cmp-session.js +19 -9
- package/lib/cms-decrypt.js +22 -8
- package/lib/cms-encrypt.js +23 -17
- package/lib/cms-sign.js +65 -43
- package/lib/cms-verify.js +8 -4
- package/lib/crl-sign.js +24 -17
- package/lib/csr-sign.js +5 -2
- package/lib/ct.js +27 -16
- package/lib/est.js +12 -9
- package/lib/guard-bytes.js +5 -1
- package/lib/guard-der.js +6 -1
- package/lib/guard-intrinsic.js +12 -4
- package/lib/guard-list.js +64 -0
- package/lib/guard-name.js +1 -1
- package/lib/hpke.js +10 -3
- package/lib/http-transport.js +12 -3
- package/lib/inspect.js +10 -2
- package/lib/jose.js +3 -1
- package/lib/lint.js +236 -152
- package/lib/mime.js +9 -5
- package/lib/ocsp.js +25 -22
- package/lib/path-validate.js +43 -13
- package/lib/pbes2.js +6 -2
- package/lib/pkcs11-uri.js +3 -1
- package/lib/pkcs12-build.js +14 -11
- package/lib/pki-build.js +14 -10
- package/lib/possession.js +3 -1
- package/lib/rc2.js +6 -2
- package/lib/revocation-fetch.js +78 -19
- package/lib/scep.js +14 -6
- package/lib/schema-attrcert.js +4 -2
- package/lib/schema-c509.js +94 -78
- package/lib/schema-cmc.js +5 -2
- package/lib/schema-cmp.js +6 -3
- package/lib/schema-cms.js +7 -4
- package/lib/schema-crl.js +1 -1
- package/lib/schema-crmf.js +1 -1
- package/lib/schema-csr.js +3 -3
- package/lib/schema-engine.js +36 -18
- package/lib/schema-pkcs1.js +7 -3
- package/lib/schema-pkcs12.js +9 -6
- package/lib/schema-pkix.js +19 -3
- package/lib/schema-sec1.js +4 -1
- package/lib/schema-tsp.js +4 -1
- package/lib/shbs.js +7 -3
- package/lib/smime.js +18 -14
- package/lib/tlog.js +17 -11
- package/lib/tuf.js +3 -1
- package/lib/validator-keydesc.js +4 -1
- package/lib/validator-tls.js +7 -2
- package/lib/webcrypto.js +9 -3
- package/lib/x509-sign.js +20 -15
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/cmc-build.js
CHANGED
|
@@ -22,6 +22,9 @@ var key = require("./key");
|
|
|
22
22
|
var _createPublicKey = nodeCrypto.createPublicKey;
|
|
23
23
|
var guard = require("./guard-all");
|
|
24
24
|
var intrinsic = require("./guard-intrinsic");
|
|
25
|
+
/** @internal The append every list here is built with: `push` stores at the index and a store
|
|
26
|
+
* consults a setter inherited there, and these lists become the controls a request carries. */
|
|
27
|
+
var _push = intrinsic.append;
|
|
25
28
|
var _hasOwn = intrinsic.hasOwn;
|
|
26
29
|
var _isArray = intrinsic.isArray;
|
|
27
30
|
var _isBuffer = intrinsic.isBuffer;
|
|
@@ -449,7 +452,7 @@ function _assertSecret(secret, what) {
|
|
|
449
452
|
}
|
|
450
453
|
|
|
451
454
|
function _ownSecret(buf, owned) {
|
|
452
|
-
owned
|
|
455
|
+
_push(owned,buf);
|
|
453
456
|
return buf;
|
|
454
457
|
}
|
|
455
458
|
|
|
@@ -804,15 +807,15 @@ async function _build(spec, signer, opts) {
|
|
|
804
807
|
|
|
805
808
|
_assertNoDuplicateBinding(callerControls, spec);
|
|
806
809
|
if (spec.transactionId != null) {
|
|
807
|
-
controls
|
|
810
|
+
_push(controls,encodeControl(OID_TRANSACTION_ID,
|
|
808
811
|
[b.integer(_asBigInt(spec.transactionId, "spec.transactionId"))], ids));
|
|
809
812
|
}
|
|
810
813
|
if (spec.senderNonce != null) {
|
|
811
|
-
controls
|
|
814
|
+
_push(controls,encodeControl(OID_SENDER_NONCE,
|
|
812
815
|
[b.octetString(_der(spec.senderNonce, "spec.senderNonce"))], ids));
|
|
813
816
|
}
|
|
814
817
|
if (spec.dataReturn != null) {
|
|
815
|
-
controls
|
|
818
|
+
_push(controls,encodeControl(OID_DATA_RETURN,
|
|
816
819
|
[b.octetString(_der(spec.dataReturn, "spec.dataReturn"))], ids));
|
|
817
820
|
}
|
|
818
821
|
|
|
@@ -839,8 +842,8 @@ async function _build(spec, signer, opts) {
|
|
|
839
842
|
if (identity != null && typeof identity !== "string") {
|
|
840
843
|
throw E("cmc/bad-input", "identityProof.identity is the UTF8String the Identification control carries");
|
|
841
844
|
}
|
|
842
|
-
if (identity != null) controls
|
|
843
|
-
controls
|
|
845
|
+
if (identity != null) _push(controls,encodeControl(OID_IDENTIFICATION, [b.utf8(identity)], ids));
|
|
846
|
+
_push(controls,encodeControl(OID_IDENTITY_PROOF_V2,
|
|
844
847
|
[identityProofV2(spec.identityProof.secret, reqSequenceBytes, carriedIdentity)], ids));
|
|
845
848
|
}
|
|
846
849
|
|
|
@@ -933,8 +936,8 @@ async function _build(spec, signer, opts) {
|
|
|
933
936
|
throw E("cmc/bad-input", "popLinkRandomBytes must be a positive integer");
|
|
934
937
|
}
|
|
935
938
|
var R = nodeCrypto.randomBytes(rBytes);
|
|
936
|
-
controls
|
|
937
|
-
controls
|
|
939
|
+
_push(controls,encodeControl(OID_POP_LINK_RANDOM, [b.octetString(R)], ids));
|
|
940
|
+
_push(controls,encodeControl(O("id-cmc-popLinkWitnessV2"),
|
|
938
941
|
[popLinkWitnessV2(spec.popLink.secret, R)], ids));
|
|
939
942
|
}
|
|
940
943
|
|
|
@@ -1016,7 +1019,7 @@ function _copySigners(signer, owned) {
|
|
|
1016
1019
|
return c;
|
|
1017
1020
|
}
|
|
1018
1021
|
function _own(buf, isSecret) {
|
|
1019
|
-
if (isSecret && owned) owned
|
|
1022
|
+
if (isSecret && owned) _push(owned,buf);
|
|
1020
1023
|
return buf;
|
|
1021
1024
|
}
|
|
1022
1025
|
return Array.isArray(signer) ? guard.list.copyMap(signer, one) : one(signer);
|
package/lib/cmp-build.js
CHANGED
|
@@ -56,7 +56,9 @@ var _bufferConcat = intrinsic.bufferConcat;
|
|
|
56
56
|
var _map = intrinsic.map;
|
|
57
57
|
var _keys = intrinsic.keys;
|
|
58
58
|
var _forEach = intrinsic.forEach;
|
|
59
|
-
|
|
59
|
+
/** @internal `append`, not a captured `push`: a store at an index walks the prototype chain for a
|
|
60
|
+
* setter, so an accessor there takes the element being appended. `append` defines it. */
|
|
61
|
+
var _push = intrinsic.append;
|
|
60
62
|
var _stringify = intrinsic.stringify;
|
|
61
63
|
var _bigInt = intrinsic.BigInt;
|
|
62
64
|
var _Date = intrinsic.Date;
|
|
@@ -167,7 +169,7 @@ function _encodeInfoTypeAndValue(itav) {
|
|
|
167
169
|
if (typeof itav.infoType !== "string" || O(itav.infoType) == null) throw _err("cmp/bad-name", "unknown infoType " + guard.text.showValue(itav.infoType));
|
|
168
170
|
var children = [b.oid(O(itav.infoType))];
|
|
169
171
|
var val = _encodeInfoValue(itav);
|
|
170
|
-
if (val != null) children
|
|
172
|
+
if (val != null) _push(children,val);
|
|
171
173
|
return b.sequence(children);
|
|
172
174
|
}
|
|
173
175
|
|
|
@@ -238,16 +240,16 @@ function _encodeHeader(headerSpec, protectionAlgDer, pvno) {
|
|
|
238
240
|
];
|
|
239
241
|
if (headerSpec.messageTime != null) {
|
|
240
242
|
guard.time.assertEncodable(headerSpec.messageTime, _err, "cmp/bad-input", "header.messageTime");
|
|
241
|
-
children
|
|
243
|
+
_push(children,b.explicit(0, b.generalizedTime(headerSpec.messageTime)));
|
|
242
244
|
}
|
|
243
|
-
if (protectionAlgDer != null) children
|
|
244
|
-
if (headerSpec.senderKID != null) children
|
|
245
|
-
if (headerSpec.recipKID != null) children
|
|
246
|
-
if (headerSpec.transactionID != null) children
|
|
247
|
-
if (headerSpec.senderNonce != null) children
|
|
248
|
-
if (headerSpec.recipNonce != null) children
|
|
249
|
-
if (headerSpec.freeText != null) children
|
|
250
|
-
if (headerSpec.generalInfo != null) children
|
|
245
|
+
if (protectionAlgDer != null) _push(children,b.explicit(1, b.raw(protectionAlgDer)));
|
|
246
|
+
if (headerSpec.senderKID != null) _push(children,b.explicit(2, _reqOctets(headerSpec.senderKID, "header.senderKID")));
|
|
247
|
+
if (headerSpec.recipKID != null) _push(children,b.explicit(3, _reqOctets(headerSpec.recipKID, "header.recipKID")));
|
|
248
|
+
if (headerSpec.transactionID != null) _push(children,b.explicit(4, _reqOctets(headerSpec.transactionID, "header.transactionID")));
|
|
249
|
+
if (headerSpec.senderNonce != null) _push(children,b.explicit(5, _reqOctets(headerSpec.senderNonce, "header.senderNonce")));
|
|
250
|
+
if (headerSpec.recipNonce != null) _push(children,b.explicit(6, _reqOctets(headerSpec.recipNonce, "header.recipNonce")));
|
|
251
|
+
if (headerSpec.freeText != null) _push(children,b.explicit(7, _encodePkiFreeText(headerSpec.freeText, "cmp/bad-freetext", "header.freeText")));
|
|
252
|
+
if (headerSpec.generalInfo != null) _push(children,b.explicit(8, _encodeGeneralInfo(headerSpec.generalInfo, "cmp/bad-general-info", "header.generalInfo")));
|
|
251
253
|
return b.sequence(children);
|
|
252
254
|
}
|
|
253
255
|
|
|
@@ -267,8 +269,8 @@ function _encodePkiStatusInfo(si, code) {
|
|
|
267
269
|
if (!si || typeof si !== "object" || Buffer.isBuffer(si)) throw _err(code, "a PKIStatusInfo must be an object { status, statusString?, failInfo? }");
|
|
268
270
|
if (typeof si.status !== "number" || !Number.isInteger(si.status) || si.status < 0 || si.status > 6) throw _err(code, "statusInfo.status must be a PKIStatus 0..6 (RFC 9810 sec. 5.2.3)");
|
|
269
271
|
var children = [b.integer(BigInt(si.status))];
|
|
270
|
-
if (si.statusString != null) children
|
|
271
|
-
if (si.failInfo != null) children
|
|
272
|
+
if (si.statusString != null) _push(children,_encodePkiFreeText(si.statusString, code, "statusInfo.statusString"));
|
|
273
|
+
if (si.failInfo != null) _push(children,_encodeFailInfo(si.failInfo, code));
|
|
272
274
|
return b.sequence(children);
|
|
273
275
|
}
|
|
274
276
|
|
|
@@ -278,10 +280,10 @@ function _encodeCertStatus(cs, state) {
|
|
|
278
280
|
_reqOctets(cs.certHash, "certConf certHash"),
|
|
279
281
|
b.integer(_reqIdInt(cs.certReqId, "cmp/bad-cert-status", "CertStatus certReqId")),
|
|
280
282
|
];
|
|
281
|
-
if (cs.statusInfo != null) children
|
|
283
|
+
if (cs.statusInfo != null) _push(children,_encodePkiStatusInfo(cs.statusInfo, "cmp/bad-cert-status"));
|
|
282
284
|
if (cs.hashAlg != null) {
|
|
283
285
|
if (typeof cs.hashAlg !== "string" || !CERT_CONF_HASH_ALGS[cs.hashAlg]) throw _err("cmp/bad-name", "certConf hashAlg must be a hash algorithm (sha256 / sha384 / sha512 / sha3-256 / sha3-512 / sha1); got " + guard.text.showValue(cs.hashAlg));
|
|
284
|
-
children
|
|
286
|
+
_push(children,b.explicit(0, _algIdNoParams(cs.hashAlg)));
|
|
285
287
|
state.usesCmp2021 = true;
|
|
286
288
|
}
|
|
287
289
|
return b.sequence(children);
|
|
@@ -317,7 +319,7 @@ function _encodeRevDetails(rd) {
|
|
|
317
319
|
certDetails = b.raw(crmf.buildCertTemplate(rd.certDetails));
|
|
318
320
|
}
|
|
319
321
|
var children = [certDetails];
|
|
320
|
-
if (rd.crlEntryDetails != null) children
|
|
322
|
+
if (rd.crlEntryDetails != null) _push(children,b.raw(_encodeCrlEntryDetails(rd.crlEntryDetails)));
|
|
321
323
|
return b.sequence(children);
|
|
322
324
|
}
|
|
323
325
|
|
|
@@ -419,12 +421,12 @@ function _encodeCertifiedKeyPair(ckp, state) {
|
|
|
419
421
|
var children = [_encodeCertOrEncCert(ckp, state)];
|
|
420
422
|
if (ckp.privateKey != null) {
|
|
421
423
|
var pk = _b.reqDer(ckp.privateKey, "certifiedKeyPair.privateKey (a pre-encoded EncryptedKey DER)");
|
|
422
|
-
children
|
|
424
|
+
_push(children,b.explicit(0, b.raw(pk)));
|
|
423
425
|
var pkNode;
|
|
424
426
|
try { pkNode = asn1.decode(pk); } catch (e) { throw _err("cmp/bad-cert-response", "certifiedKeyPair.privateKey is not valid DER", e); }
|
|
425
427
|
if (pkNode.tagClass === "context" && pkNode.tagNumber === 0) state.usesCmp2021 = true;
|
|
426
428
|
}
|
|
427
|
-
if (ckp.publicationInfo != null) children
|
|
429
|
+
if (ckp.publicationInfo != null) _push(children,b.explicit(1, b.raw(_b.reqDer(ckp.publicationInfo, "certifiedKeyPair.publicationInfo (a pre-encoded DER)"))));
|
|
428
430
|
return b.sequence(children);
|
|
429
431
|
}
|
|
430
432
|
|
|
@@ -435,8 +437,8 @@ function _encodeCertResponse(cr, state) {
|
|
|
435
437
|
if (hasCkp && cr.status.failInfo != null) throw _err("cmp/bad-cert-response", "a CertResponse must not carry both failInfo and certifiedKeyPair");
|
|
436
438
|
if (hasCkp && cr.status.status !== 0 && cr.status.status !== 1) throw _err("cmp/bad-cert-response", "a CertResponse certifiedKeyPair is allowed only under a granting status (accepted / grantedWithMods)");
|
|
437
439
|
var children = [b.integer(_reqIdInt(cr.certReqId, "cmp/bad-cert-response", "CertResponse certReqId")), _encodePkiStatusInfo(cr.status, "cmp/bad-cert-response")];
|
|
438
|
-
if (hasCkp) children
|
|
439
|
-
if (cr.rspInfo != null) children
|
|
440
|
+
if (hasCkp) _push(children,_encodeCertifiedKeyPair(cr.certifiedKeyPair, state));
|
|
441
|
+
if (cr.rspInfo != null) _push(children,_reqOctets(cr.rspInfo, "CertResponse.rspInfo"));
|
|
440
442
|
return b.sequence(children);
|
|
441
443
|
}
|
|
442
444
|
|
|
@@ -446,9 +448,9 @@ function _encodeCertRepMessage(spec, state, arm) {
|
|
|
446
448
|
var children = [];
|
|
447
449
|
if (spec.caPubs != null) {
|
|
448
450
|
if (!Array.isArray(spec.caPubs) || !spec.caPubs.length) throw _err("cmp/bad-cert-rep", arm + ".caPubs must be a non-empty array of certificate DERs");
|
|
449
|
-
children
|
|
451
|
+
_push(children,b.explicit(1, b.sequence(spec.caPubs.map(function (c) { return _certRaw(c, "cmp/bad-cert-rep", "a caPubs entry"); }))));
|
|
450
452
|
}
|
|
451
|
-
children
|
|
453
|
+
_push(children,b.sequence(spec.response.map(function (cr) { return _encodeCertResponse(cr, state); })));
|
|
452
454
|
return b.sequence(children);
|
|
453
455
|
}
|
|
454
456
|
|
|
@@ -468,11 +470,11 @@ function _encodeRevRepContent(spec) {
|
|
|
468
470
|
var children = [b.sequence(spec.status.map(function (si) { return _encodePkiStatusInfo(si, "cmp/bad-rev-rep"); }))];
|
|
469
471
|
if (spec.revCerts != null) {
|
|
470
472
|
if (!Array.isArray(spec.revCerts) || !spec.revCerts.length) throw _err("cmp/bad-rev-rep", "rp.revCerts must be a non-empty array of CertId");
|
|
471
|
-
children
|
|
473
|
+
_push(children,b.explicit(0, b.sequence(spec.revCerts.map(_encodeCertIdRr))));
|
|
472
474
|
}
|
|
473
475
|
if (spec.crls != null) {
|
|
474
476
|
if (!Array.isArray(spec.crls) || !spec.crls.length) throw _err("cmp/bad-rev-rep", "rp.crls must be a non-empty array of CertificateList DERs");
|
|
475
|
-
children
|
|
477
|
+
_push(children,b.explicit(1, b.sequence(spec.crls.map(function (c) {
|
|
476
478
|
var der = _b.reqDerSequence(c, "crls entry (a CertificateList DER)");
|
|
477
479
|
try { crl.parse(der); }
|
|
478
480
|
catch (e) { if (e instanceof CmpError) throw e; throw _err("cmp/bad-rev-rep", "a crls entry is not a valid CRL (CertificateList)", e); }
|
|
@@ -486,8 +488,8 @@ function _encodeErrorMsgContent(spec) {
|
|
|
486
488
|
if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("cmp/bad-error", "error must be an object { pKIStatusInfo, errorCode?, errorDetails? }");
|
|
487
489
|
if (spec.pKIStatusInfo == null) throw _err("cmp/bad-error", "error.pKIStatusInfo is required");
|
|
488
490
|
var children = [_encodePkiStatusInfo(spec.pKIStatusInfo, "cmp/bad-error")];
|
|
489
|
-
if (spec.errorCode != null) children
|
|
490
|
-
if (spec.errorDetails != null) children
|
|
491
|
+
if (spec.errorCode != null) _push(children,b.integer(_reqIdInt(spec.errorCode, "cmp/bad-error", "error.errorCode")));
|
|
492
|
+
if (spec.errorDetails != null) _push(children,_encodePkiFreeText(spec.errorDetails, "cmp/bad-error", "error.errorDetails"));
|
|
491
493
|
return b.sequence(children);
|
|
492
494
|
}
|
|
493
495
|
|
|
@@ -497,7 +499,7 @@ function _encodePollRepContent(list) {
|
|
|
497
499
|
if (!pr || typeof pr !== "object" || Buffer.isBuffer(pr)) throw _err("cmp/bad-poll-rep", "each pollRep entry must be an object");
|
|
498
500
|
if (typeof pr.checkAfter !== "number" || !Number.isInteger(pr.checkAfter) || pr.checkAfter < 0 || pr.checkAfter > 0x7fffffff) throw _err("cmp/bad-poll-rep", "pollRep checkAfter must be a non-negative uint31 delay in seconds (RFC 9810 sec. 5.3.22)");
|
|
499
501
|
var kids = [b.integer(_reqIdInt(pr.certReqId, "cmp/bad-poll-rep", "pollRep certReqId")), b.integer(BigInt(pr.checkAfter))];
|
|
500
|
-
if (pr.reason != null) kids
|
|
502
|
+
if (pr.reason != null) _push(kids,_encodePkiFreeText(pr.reason, "cmp/bad-poll-rep", "pollRep reason"));
|
|
501
503
|
return b.sequence(kids);
|
|
502
504
|
}));
|
|
503
505
|
}
|
|
@@ -506,14 +508,14 @@ function _encodeKeyRecRepContent(spec, state) {
|
|
|
506
508
|
if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("cmp/bad-key-rec-rep", "krp must be an object { status, newSigCert?, caCerts?, keyPairHist? }");
|
|
507
509
|
if (spec.status == null) throw _err("cmp/bad-key-rec-rep", "krp.status is required");
|
|
508
510
|
var children = [_encodePkiStatusInfo(spec.status, "cmp/bad-key-rec-rep")];
|
|
509
|
-
if (spec.newSigCert != null) children
|
|
511
|
+
if (spec.newSigCert != null) _push(children,b.explicit(0, _certRaw(spec.newSigCert, "cmp/bad-key-rec-rep", "krp.newSigCert")));
|
|
510
512
|
if (spec.caCerts != null) {
|
|
511
513
|
if (!Array.isArray(spec.caCerts) || !spec.caCerts.length) throw _err("cmp/bad-key-rec-rep", "krp.caCerts must be a non-empty array of certificate DERs");
|
|
512
|
-
children
|
|
514
|
+
_push(children,b.explicit(1, b.sequence(spec.caCerts.map(function (c) { return _certRaw(c, "cmp/bad-key-rec-rep", "a krp.caCerts entry"); }))));
|
|
513
515
|
}
|
|
514
516
|
if (spec.keyPairHist != null) {
|
|
515
517
|
if (!Array.isArray(spec.keyPairHist) || !spec.keyPairHist.length) throw _err("cmp/bad-key-rec-rep", "krp.keyPairHist must be a non-empty array of CertifiedKeyPair");
|
|
516
|
-
children
|
|
518
|
+
_push(children,b.explicit(2, b.sequence(spec.keyPairHist.map(function (ckp) { return _encodeCertifiedKeyPair(ckp, state); }))));
|
|
517
519
|
}
|
|
518
520
|
return b.sequence(children);
|
|
519
521
|
}
|
|
@@ -891,7 +893,7 @@ async function _build(message, opts) {
|
|
|
891
893
|
var protectionBits = await prot.computeBits(protectedPartDer);
|
|
892
894
|
var msgChildren = [headerTLV, bodyTLV, b.explicit(0, protectionBits)];
|
|
893
895
|
var extraCertsDers = _collectExtraCerts(opts, prot.certDer);
|
|
894
|
-
if (extraCertsDers.length) msgChildren
|
|
896
|
+
if (extraCertsDers.length) _push(msgChildren,b.explicit(1, b.sequence(extraCertsDers)));
|
|
895
897
|
var der = b.sequence(msgChildren);
|
|
896
898
|
|
|
897
899
|
cmp.parse(der);
|
|
@@ -905,14 +907,14 @@ async function _build(message, opts) {
|
|
|
905
907
|
|
|
906
908
|
function _collectExtraCerts(opts, protCertDer) {
|
|
907
909
|
var out = [];
|
|
908
|
-
if (protCertDer != null) out
|
|
910
|
+
if (protCertDer != null) _push(out,b.raw(protCertDer));
|
|
909
911
|
if (opts.extraCerts != null) {
|
|
910
912
|
if (!Array.isArray(opts.extraCerts)) throw _err("cmp/bad-extra-certs", "opts.extraCerts must be an array of certificate DERs");
|
|
911
913
|
opts.extraCerts.forEach(function (c) {
|
|
912
914
|
var der = _b.reqDerSequence(c, "extraCerts entry (a Certificate DER)");
|
|
913
915
|
try { x509.parse(der); }
|
|
914
916
|
catch (e) { if (e instanceof CmpError) throw e; throw _err("cmp/bad-extra-certs", "an extraCerts entry is not a valid X.509 certificate", e); }
|
|
915
|
-
out
|
|
917
|
+
_push(out,b.raw(der));
|
|
916
918
|
});
|
|
917
919
|
}
|
|
918
920
|
return out;
|
package/lib/cmp-session.js
CHANGED
|
@@ -15,6 +15,10 @@ var crmfSign = require("./crmf-sign");
|
|
|
15
15
|
var cmpBuild = require("./cmp-build");
|
|
16
16
|
var csr = require("./schema-csr");
|
|
17
17
|
var guard = require("./guard-all");
|
|
18
|
+
/** @internal The append every list here is built with: `push` stores at the index and a store
|
|
19
|
+
* consults a setter inherited there, and one of these lists is the accumulated CA certificates a
|
|
20
|
+
* later leg is authenticated against. */
|
|
21
|
+
var _push = guard.list.append;
|
|
18
22
|
var compositeSig = require("./composite-sig");
|
|
19
23
|
var constants = require("./constants");
|
|
20
24
|
var webcrypto = require("./webcrypto");
|
|
@@ -34,7 +38,7 @@ function setEngine(engine) { _engine = engine; }
|
|
|
34
38
|
var HASHLESS_SIG_OIDS = Object.create(null);
|
|
35
39
|
(function () {
|
|
36
40
|
var names = ["Ed25519", "Ed448", "id-ml-dsa-44", "id-ml-dsa-65", "id-ml-dsa-87"];
|
|
37
|
-
["sha2", "shake"].forEach(function (h) { ["128s", "128f", "192s", "192f", "256s", "256f"].forEach(function (s) { names
|
|
41
|
+
["sha2", "shake"].forEach(function (h) { ["128s", "128f", "192s", "192f", "256s", "256f"].forEach(function (s) { _push(names,"id-slh-dsa-" + h + "-" + s); }); });
|
|
38
42
|
names.forEach(function (n) { var o = oid.byName(n); if (o) HASHLESS_SIG_OIDS[o] = 1; });
|
|
39
43
|
})();
|
|
40
44
|
var SIG_OID_TO_HASH = Object.create(null);
|
|
@@ -136,11 +140,11 @@ function _asCertList(v) { return v == null ? [] : (Array.isArray(v) ? guard.list
|
|
|
136
140
|
function _boundedPool(base, added) {
|
|
137
141
|
var ceiling = constants.LIMITS.PATH_BUILD_MAX_CANDIDATES;
|
|
138
142
|
var seen = Object.create(null), distinctBase = [];
|
|
139
|
-
base.forEach(function (c) { var k = _certIdentity(c); if (k == null) { distinctBase
|
|
143
|
+
base.forEach(function (c) { var k = _certIdentity(c); if (k == null) { _push(distinctBase,c); return; } if (!seen[k]) { seen[k] = 1; _push(distinctBase,c); } });
|
|
140
144
|
var room = ceiling - distinctBase.length;
|
|
141
145
|
if (room <= 0) return distinctBase;
|
|
142
146
|
var useful = [];
|
|
143
|
-
added.forEach(function (c) { var k = _certIdentity(c); if (k != null && seen[k]) return; if (k != null) seen[k] = 1; useful
|
|
147
|
+
added.forEach(function (c) { var k = _certIdentity(c); if (k != null && seen[k]) return; if (k != null) seen[k] = 1; _push(useful,c); });
|
|
144
148
|
return distinctBase.concat(useful.slice(0, room));
|
|
145
149
|
}
|
|
146
150
|
function _certIdentity(cert) {
|
|
@@ -228,7 +232,7 @@ function _responseExtraCerts(responseBytes) {
|
|
|
228
232
|
seen[key] = true;
|
|
229
233
|
try { x509.parse(c); }
|
|
230
234
|
catch (_e) { continue; }
|
|
231
|
-
out
|
|
235
|
+
_push(out,Buffer.from(c));
|
|
232
236
|
}
|
|
233
237
|
return out;
|
|
234
238
|
}
|
|
@@ -682,7 +686,13 @@ function session(opts) {
|
|
|
682
686
|
if (!Buffer.isBuffer(c)) return;
|
|
683
687
|
var k = c.toString("base64");
|
|
684
688
|
if (caPubsSeen[k]) {
|
|
685
|
-
|
|
689
|
+
/** @internal The entry is read, removed and appended as three steps rather than through
|
|
690
|
+
* `splice`. `splice` RETURNS what it removed, so it builds that result through
|
|
691
|
+
* `ArraySpeciesCreate`, which reads the receiver's `constructor` and then its
|
|
692
|
+
* `Symbol.species`: a getter installed on `Array.prototype.constructor` is handed this
|
|
693
|
+
* accumulator as its `this` while the move is in progress, and the list holds the CA
|
|
694
|
+
* certificates a later leg is authenticated against. */
|
|
695
|
+
if (isGrantLeg) { for (var pi = 0; pi < caPubsAccum.length; pi++) { if (caPubsAccum[pi].toString("base64") === k) { var moved = caPubsAccum[pi]; guard.list.removeAt(caPubsAccum, pi); guard.list.append(caPubsAccum, moved); if (pi < caPubsWaitingCount) caPubsWaitingCount--; break; } } }
|
|
686
696
|
return;
|
|
687
697
|
}
|
|
688
698
|
try { x509.parse(c); } catch (e) { throw _err("cmp/bad-cert-response", "an authenticated caPubs entry is not a valid X.509 certificate", e); }
|
|
@@ -963,10 +973,10 @@ function session(opts) {
|
|
|
963
973
|
async function _validateLeaf(leaf, caPubs) {
|
|
964
974
|
if (_engine == null || opts.trustAnchors == null) return;
|
|
965
975
|
var caPubsList = [];
|
|
966
|
-
if (Array.isArray(caPubs)) caPubs.forEach(function (c) { if (Buffer.isBuffer(c)) caPubsList
|
|
976
|
+
if (Array.isArray(caPubs)) caPubs.forEach(function (c) { if (Buffer.isBuffer(c)) _push(caPubsList,c); });
|
|
967
977
|
var added = _asCertList(opts.intermediates);
|
|
968
|
-
if (Buffer.isBuffer(cachedSignerCert)) added
|
|
969
|
-
cachedChain.forEach(function (c) { if (Buffer.isBuffer(c)) added
|
|
978
|
+
if (Buffer.isBuffer(cachedSignerCert)) _push(added,cachedSignerCert);
|
|
979
|
+
cachedChain.forEach(function (c) { if (Buffer.isBuffer(c)) _push(added,c); });
|
|
970
980
|
var pool = _boundedPool(caPubsList, added);
|
|
971
981
|
var res;
|
|
972
982
|
try { res = await _engine.build(leaf, { trustAnchors: _asCertList(opts.trustAnchors), intermediates: pool, validate: true, time: opts.time != null ? opts.time : new Date() }); }
|
|
@@ -1395,7 +1405,7 @@ function session(opts) {
|
|
|
1395
1405
|
if (limit.total !== null && total > limit.total) {
|
|
1396
1406
|
throw _err("cmp/bad-input", "the resumeToken " + name + " exceeds the " + limit.total + "-byte pool a transaction holds");
|
|
1397
1407
|
}
|
|
1398
|
-
out
|
|
1408
|
+
_push(out,der);
|
|
1399
1409
|
}
|
|
1400
1410
|
return out;
|
|
1401
1411
|
}
|
package/lib/cms-decrypt.js
CHANGED
|
@@ -121,10 +121,10 @@ function _selectCandidates(recips, km, opts) {
|
|
|
121
121
|
for (var k = 0; k < recips.length; k++) {
|
|
122
122
|
var r = recips[k];
|
|
123
123
|
if (want === "asym" && (r.type === "ktri" || r.type === "kari" || r.type === "ori")) {
|
|
124
|
-
if (cert && _ridMatches(r, cert))
|
|
125
|
-
} else if (want === "pwri" && r.type === "pwri") {
|
|
124
|
+
if (cert && _ridMatches(r, cert)) intrinsic.append(out, { ri: r, index: k });
|
|
125
|
+
} else if (want === "pwri" && r.type === "pwri") { intrinsic.append(out, { ri: r, index: k }); }
|
|
126
126
|
else if (want === "kekri" && r.type === "kekri") {
|
|
127
|
-
if (km.kekId == null || _kekIdMatches(r, km.kekId))
|
|
127
|
+
if (km.kekId == null || _kekIdMatches(r, km.kekId)) intrinsic.append(out, { ri: r, index: k });
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
if (!out.length) throw _err("cms/no-matching-recipient", "no recipient matches the supplied key material");
|
|
@@ -563,19 +563,23 @@ async function _aesKwUnwrap(kek, wrapped) {
|
|
|
563
563
|
guard.secret.zeroize(new Uint8Array(rawAb), CmsError, "cms/bad-input", "the unwrapped content key");
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
|
+
/** @internal Both KDF-input structures APPEND by defining the index. A store at an index the list
|
|
567
|
+
* has no own property at consults a setter inherited from the array prototype, so an accessor there
|
|
568
|
+
* would decide the SharedInfo these bytes become and derive a different KEK from the same shared
|
|
569
|
+
* secret. */
|
|
566
570
|
function _eccSharedInfo(wrapName, ukm, kekBytes) {
|
|
567
571
|
var kids = [b.sequence([b.oid(O(wrapName))])];
|
|
568
|
-
if (ukm)
|
|
572
|
+
if (ukm) intrinsic.append(kids, b.explicit(0, b.octetString(ukm)));
|
|
569
573
|
/** @internal The SuppPubInfo key length is written with the capture, for the same reason the
|
|
570
574
|
* encrypt side does it: this is KDF input, and a replaced write derives a different KEK from the
|
|
571
575
|
* same shared secret. */
|
|
572
576
|
var supp = Buffer.alloc(4); intrinsic.writeUInt32BE(supp, kekBytes * 8, 0);
|
|
573
|
-
|
|
577
|
+
intrinsic.append(kids, b.explicit(2, b.octetString(supp)));
|
|
574
578
|
return b.sequence(kids);
|
|
575
579
|
}
|
|
576
580
|
function _kemOtherInfo(wrapName, kekBytes, ukm) {
|
|
577
581
|
var kids = [b.sequence([b.oid(O(wrapName))]), b.integer(BigInt(kekBytes))];
|
|
578
|
-
if (ukm)
|
|
582
|
+
if (ukm) intrinsic.append(kids, b.explicit(0, b.octetString(ukm)));
|
|
579
583
|
return b.sequence(kids);
|
|
580
584
|
}
|
|
581
585
|
function _pwriUnwrap(kek, wrapped, iv, keyBits) {
|
|
@@ -648,7 +652,7 @@ function _originatorSpki(originator) {
|
|
|
648
652
|
if (!originator || originator.form !== "originatorKey") throw _err("cms/unsupported-algorithm", "kari requires an originatorKey (ephemeral-static ECDH)");
|
|
649
653
|
var v = originator.value;
|
|
650
654
|
var algKids = [b.oid(v.algorithm.oid)];
|
|
651
|
-
if (v.algorithm.parameters != null)
|
|
655
|
+
if (v.algorithm.parameters != null) intrinsic.append(algKids, b.raw(v.algorithm.parameters));
|
|
652
656
|
return b.sequence([b.sequence(algKids), b.bitString(v.publicKey.bytes, v.publicKey.unusedBits)]);
|
|
653
657
|
}
|
|
654
658
|
var MONT = intrinsic.create(null); MONT[O("X25519")] = { name: "X25519", hkdf: "SHA-256" }; MONT[O("X448")] = { name: "X448", hkdf: "SHA-512" };
|
|
@@ -710,7 +714,17 @@ async function _verifyAuthenticatedData(parsed, km, opts, requireProtection) {
|
|
|
710
714
|
guard.der.assertParams(parsed.digestAlgorithm.parameters, "absentOrNull", _err,
|
|
711
715
|
"cms/unsupported-algorithm", parsed.digestAlgorithm.name + " digestAlgorithm (RFC 5754 sec. 2)");
|
|
712
716
|
preimage = _explicitSetOf(parsed.authAttrsBytes);
|
|
713
|
-
|
|
717
|
+
/** @internal The selection returns the first matching attribute or null. `filter(...)[0]` indexes
|
|
718
|
+
* a result that is EMPTY when the attribute is absent, and index 0 of an empty array answers
|
|
719
|
+
* from the array prototype, so a value installed there would supply the digest this comparison
|
|
720
|
+
* is made against. The refusal restates an invariant the parse already holds: an
|
|
721
|
+
* AuthenticatedData with authAttrs is walked through the content-binding check, which requires
|
|
722
|
+
* the message-digest attribute (`cms/missing-message-digest`), so this is not reachable from a
|
|
723
|
+
* message and is here so the read below cannot be made on something that is not an attribute. */
|
|
724
|
+
var mdAttr = guard.list.firstMatch(parsed.authAttrs || [], function (a) { return a.type === O("messageDigest"); });
|
|
725
|
+
if (!mdAttr || mdAttr.values.length !== 1) {
|
|
726
|
+
throw _err("cms/bad-auth-attrs", "authenticated attributes must carry exactly one message-digest attribute (RFC 5652 sec. 9.2)");
|
|
727
|
+
}
|
|
714
728
|
mdCheck = { hash: dHash, declared: asn1.read.octetString(asn1.decode(mdAttr.values[0])) };
|
|
715
729
|
/** @internal RFC 6211 sec. 3.2 on this content type: the two comparisons are what make the
|
|
716
730
|
* outer `digestAlgorithm` and `macAlgorithm` fields mean anything, since the MAC input is the
|
package/lib/cms-encrypt.js
CHANGED
|
@@ -14,6 +14,10 @@ var webcrypto = require("./webcrypto");
|
|
|
14
14
|
var frameworkError = require("./framework-error");
|
|
15
15
|
var guard = require("./guard-all");
|
|
16
16
|
var intrinsic = require("./guard-intrinsic");
|
|
17
|
+
/** @internal The append every list here is built with: `push` stores at the index and a store
|
|
18
|
+
* consults a setter inherited there. These lists become a recipient info and the key-derivation
|
|
19
|
+
* input beside it. */
|
|
20
|
+
var _push = intrinsic.append;
|
|
17
21
|
var pbes2 = require("./pbes2");
|
|
18
22
|
var compositeKem = require("./composite-kem");
|
|
19
23
|
var b = asn1.build;
|
|
@@ -66,7 +70,7 @@ function _wrapOidForKek(keyBytes) {
|
|
|
66
70
|
|
|
67
71
|
function _gcmParams(nonce, icvLen) {
|
|
68
72
|
var kids = [b.octetString(nonce)];
|
|
69
|
-
if (icvLen !== 12) kids
|
|
73
|
+
if (icvLen !== 12) _push(kids,b.integer(BigInt(icvLen)));
|
|
70
74
|
return b.sequence(kids);
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -124,12 +128,12 @@ MONT_KA[O("X448")] = { name: "X448", hkdf: "SHA-512", scheme: "dhSinglePass-stdD
|
|
|
124
128
|
|
|
125
129
|
function _eccSharedInfo(wrapName, ukm, kekBytes) {
|
|
126
130
|
var kids = [_algId(wrapName, "absent")];
|
|
127
|
-
if (ukm) kids
|
|
131
|
+
if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
|
|
128
132
|
/** @internal The SuppPubInfo key length is written with the capture. It is KDF input, so it is part
|
|
129
133
|
* of what the key-encryption key derives from, and a replaced write derives a different KEK from
|
|
130
134
|
* the same shared secret. */
|
|
131
135
|
var supp = Buffer.alloc(4); intrinsic.writeUInt32BE(supp, kekBytes * 8, 0);
|
|
132
|
-
kids
|
|
136
|
+
_push(kids,b.explicit(2, b.octetString(supp)));
|
|
133
137
|
return b.sequence(kids);
|
|
134
138
|
}
|
|
135
139
|
async function _buildKari(cek, cert, opts) {
|
|
@@ -179,8 +183,9 @@ async function _buildKari(cek, cert, opts) {
|
|
|
179
183
|
var rek = b.sequence([b.sequence([ridNode, b.octetString(encryptedKey)])]);
|
|
180
184
|
var kekAlg = b.sequence([b.oid(O(origKeyAlgId.scheme)), _algId(wrapName, "absent")]);
|
|
181
185
|
var kariKids = [b.integer(3n), b.explicit(0, originatorKey)];
|
|
182
|
-
if (ukm) kariKids
|
|
183
|
-
kariKids
|
|
186
|
+
if (ukm) _push(kariKids,b.explicit(1, b.octetString(ukm)));
|
|
187
|
+
_push(kariKids,kekAlg);
|
|
188
|
+
_push(kariKids,rek);
|
|
184
189
|
return { tag: 1, node: b.sequence(kariKids) };
|
|
185
190
|
} finally {
|
|
186
191
|
guard.secret.zeroizeAll([z, mz, kek], CmsError, "cms/bad-input", "the key-agreement shared secret");
|
|
@@ -227,7 +232,7 @@ var KEM_WC = intrinsic.create(null); KEM_WC[O("id-ml-kem-512")] = "ML-KEM-512";
|
|
|
227
232
|
|
|
228
233
|
function _kemOtherInfo(wrapName, kekBytes, ukm) {
|
|
229
234
|
var kids = [_algId(wrapName, "absent"), b.integer(BigInt(kekBytes))];
|
|
230
|
-
if (ukm) kids
|
|
235
|
+
if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
|
|
231
236
|
return b.sequence(kids);
|
|
232
237
|
}
|
|
233
238
|
async function _kemEncapsulate(keyOid, cert) {
|
|
@@ -258,8 +263,9 @@ async function _buildKemri(cek, cert, opts) {
|
|
|
258
263
|
var encryptedKey = await _aesKwWrap(kek, cek);
|
|
259
264
|
var rid = _rid(cert, opts.keyIdentifier);
|
|
260
265
|
var kemriKids = [b.integer(0n), rid.node, _algId(oid.name(keyOid), "absent"), b.octetString(kemct), _algId("hkdfWithSha256", "absent"), b.integer(BigInt(kekBytes))];
|
|
261
|
-
if (ukm) kemriKids
|
|
262
|
-
kemriKids
|
|
266
|
+
if (ukm) _push(kemriKids,b.explicit(0, b.octetString(ukm)));
|
|
267
|
+
_push(kemriKids,_algId(wrapName, "absent"));
|
|
268
|
+
_push(kemriKids,b.octetString(encryptedKey));
|
|
263
269
|
var kemri = b.sequence(kemriKids);
|
|
264
270
|
return { tag: 4, node: b.sequence([b.oid(O("kem")), kemri]) };
|
|
265
271
|
} finally {
|
|
@@ -446,7 +452,7 @@ async function _encryptImpl(content, recipients, opts) {
|
|
|
446
452
|
if (!recipients.length) throw _err("cms/bad-input", "at least one recipient is required (RFC 5652 sec. 6.1)");
|
|
447
453
|
var recips = [];
|
|
448
454
|
var consumed = intrinsic.create(null);
|
|
449
|
-
for (var i = 0; i < recipients.length; i++) recips
|
|
455
|
+
for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(cek, recipients[i], opts, consumed));
|
|
450
456
|
_assertDefaultsConsumed(opts, consumed);
|
|
451
457
|
var riNodes = recips.map(_taggedRecipient);
|
|
452
458
|
|
|
@@ -535,8 +541,8 @@ async function _authEnvelopedData(contentBytes, contentStream, cek, ca, contentT
|
|
|
535
541
|
}
|
|
536
542
|
var eci = b.sequence([b.oid(O(contentType)), b.sequence([b.oid(O(ca.oid)), _gcmParams(nonce, 16)]), b.contextPrimitive(0, g.ct)]);
|
|
537
543
|
var kids = [b.integer(0n), b.setOf(riNodes), eci];
|
|
538
|
-
if (authAttrsDer) kids
|
|
539
|
-
kids
|
|
544
|
+
if (authAttrsDer) _push(kids,authAttrsDer);
|
|
545
|
+
_push(kids,b.octetString(g.tag));
|
|
540
546
|
void recips;
|
|
541
547
|
return b.sequence(kids);
|
|
542
548
|
}
|
|
@@ -680,7 +686,7 @@ async function _authenticateImpl(content, recipients, opts) {
|
|
|
680
686
|
try {
|
|
681
687
|
var recips = [];
|
|
682
688
|
var consumedAuth = {};
|
|
683
|
-
for (var i = 0; i < recipients.length; i++) recips
|
|
689
|
+
for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(macKey, recipients[i], opts, consumedAuth));
|
|
684
690
|
_assertDefaultsConsumed(opts, consumedAuth);
|
|
685
691
|
var riNodes = recips.map(_taggedRecipient);
|
|
686
692
|
|
|
@@ -705,7 +711,7 @@ async function _authenticateImpl(content, recipients, opts) {
|
|
|
705
711
|
* MAC algorithm substitution attack, which is difficult because the attacker does not know
|
|
706
712
|
* the authentication key". Built from the same values the two outer fields are built from. */
|
|
707
713
|
if (protectionOid) {
|
|
708
|
-
intrinsic.
|
|
714
|
+
intrinsic.append(pairs, b.sequence([
|
|
709
715
|
b.oid(protectionOid),
|
|
710
716
|
b.setOf([b.sequence([_algId(digestName), b.implicit(2, _algId(mac.oid))])]),
|
|
711
717
|
]));
|
|
@@ -732,10 +738,10 @@ async function _authenticateImpl(content, recipients, opts) {
|
|
|
732
738
|
|
|
733
739
|
var eci = b.sequence([b.oid(O(contentType)), b.explicit(0, b.octetString(contentBytes))]);
|
|
734
740
|
var kids = [b.integer(0n), b.setOf(riNodes), _algId(mac.oid)];
|
|
735
|
-
if (digestAlgTagged) kids
|
|
736
|
-
kids
|
|
737
|
-
if (authAttrsDer) kids
|
|
738
|
-
kids
|
|
741
|
+
if (digestAlgTagged) _push(kids,digestAlgTagged);
|
|
742
|
+
_push(kids,eci);
|
|
743
|
+
if (authAttrsDer) _push(kids,authAttrsDer);
|
|
744
|
+
_push(kids,b.octetString(macValue));
|
|
739
745
|
var ci = b.sequence([b.oid(O("authData")), b.explicit(0, b.sequence(kids))]);
|
|
740
746
|
try { schemaCms.parse(ci); } catch (e) { throw (e instanceof CmsError) ? e : _err("cms/bad-input", "the supplied authenticated attributes produced an invalid AuthenticatedData", e); }
|
|
741
747
|
return opts.pem ? schemaCms.pemEncode(ci, "CMS") : ci;
|