@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/cms-sign.js
CHANGED
|
@@ -15,6 +15,12 @@ var webcrypto = require("./webcrypto");
|
|
|
15
15
|
var signScheme = require("./sign-scheme");
|
|
16
16
|
var guard = require("./guard-all");
|
|
17
17
|
var intrinsic = require("./guard-intrinsic");
|
|
18
|
+
/** @internal `append`, not a captured `push`: appending with `push` STORES at the index, and a store
|
|
19
|
+
* walks the prototype chain for a setter, so an accessor installed at an array index receives each
|
|
20
|
+
* element as it is appended and can define something else in its place. The lists built here become
|
|
21
|
+
* a message's signed attributes, its certificate set and its signer infos. `append` defines the
|
|
22
|
+
* index on the array itself. */
|
|
23
|
+
var _push = intrinsic.append;
|
|
18
24
|
/** @internal `resolve` and `all` build their promise from the RECEIVER, so reading the global binding
|
|
19
25
|
* at the call hands the construction to whatever that binding holds. Each signer's digest and
|
|
20
26
|
* signature are awaited through one of these, and a replacement that settles without awaiting emits a
|
|
@@ -73,7 +79,11 @@ function _digest(digestName, content) {
|
|
|
73
79
|
|
|
74
80
|
|
|
75
81
|
function _skiValue(cert) {
|
|
76
|
-
|
|
82
|
+
/** @internal The selection returns the first matching row or null, because `filter(...)[0]` indexes
|
|
83
|
+
* a result that is EMPTY when the extension is absent, and index 0 of an empty array answers from
|
|
84
|
+
* the array prototype: the refusal below would then not be reached for a certificate that carries
|
|
85
|
+
* no SKI. */
|
|
86
|
+
var ext = guard.list.firstMatch(cert.extensions || [], function (e) { return e.oid === OID_SKI; });
|
|
77
87
|
if (!ext) throw _err("cms/no-ski", "a subjectKeyIdentifier signer identifier requires the signer certificate to carry an SKI extension");
|
|
78
88
|
try { return asn1.read.octetString(asn1.decode(ext.value)); }
|
|
79
89
|
catch (e) { throw _err("cms/no-ski", "the signer certificate's subjectKeyIdentifier extension value is not an OCTET STRING", e); }
|
|
@@ -216,10 +226,10 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
|
|
|
216
226
|
{ type: O("contentType"), values: [b.oid(eContentType)] },
|
|
217
227
|
{ type: O("messageDigest"), values: [b.octetString(md)] },
|
|
218
228
|
];
|
|
219
|
-
if (opts.signingTime !== false)
|
|
229
|
+
if (opts.signingTime !== false) _push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
|
|
220
230
|
var apOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
|
|
221
231
|
if (apOid) {
|
|
222
|
-
|
|
232
|
+
_push(pairs, _algorithmProtectionPair(apOid,
|
|
223
233
|
rc.scheme.digestAlgId, rc.scheme.sigAlgId, 1));
|
|
224
234
|
}
|
|
225
235
|
pairs = intrinsic.concat(pairs, _resolveAttrPairs(opts.additionalSignedAttributes, "a signed attribute value"));
|
|
@@ -230,10 +240,13 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
|
|
|
230
240
|
var sig = await signScheme.signOverTbs(rc.scheme, rc.soKey, signedBytes, _signE);
|
|
231
241
|
await _assertKeyMatchesSpki(rc.keyOnly, rc.soKey, rc.soSpki, rc.scheme, sig, signedBytes, rc.cert);
|
|
232
242
|
var fields = [b.integer(BigInt(rc.version)), rc.sid, rc.scheme.digestAlgId];
|
|
233
|
-
if (toSign.wire)
|
|
234
|
-
|
|
243
|
+
if (toSign.wire) _push(fields, toSign.wire);
|
|
244
|
+
/** @internal Two appends, because `append` takes one value where `push` took many: the algorithm
|
|
245
|
+
* identifier and the signature it describes are adjacent fields of the same SignerInfo. */
|
|
246
|
+
_push(fields, rc.scheme.sigAlgId);
|
|
247
|
+
_push(fields, b.octetString(sig));
|
|
235
248
|
var ua = _buildUnsignedAttrs(opts.unsignedAttributes);
|
|
236
|
-
if (ua)
|
|
249
|
+
if (ua) _push(fields, ua);
|
|
237
250
|
return { si: b.sequence(fields), digestAlgId: rc.scheme.digestAlgId, version: rc.version, certDer: rc.certDer };
|
|
238
251
|
}
|
|
239
252
|
|
|
@@ -367,7 +380,7 @@ async function _signStream(stream, signers, opts) {
|
|
|
367
380
|
if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertEncodable(opts.signingTime, _err, "cms/bad-input", "signingTime");
|
|
368
381
|
var rcs = intrinsic.map(list, function (s) { return _resolveSignerContext(s, opts); });
|
|
369
382
|
var digestNames = [], seenDigest = intrinsic.create(null);
|
|
370
|
-
intrinsic.forEach(rcs, function (r) { if (!seenDigest[r.scheme.digest]) { seenDigest[r.scheme.digest] = 1;
|
|
383
|
+
intrinsic.forEach(rcs, function (r) { if (!seenDigest[r.scheme.digest]) { seenDigest[r.scheme.digest] = 1; _push(digestNames, r.scheme.digest); } });
|
|
371
384
|
var wcNames = intrinsic.map(digestNames, function (n) { return DIGEST_HASH[n]; });
|
|
372
385
|
var digests;
|
|
373
386
|
try {
|
|
@@ -379,7 +392,7 @@ async function _signStream(stream, signers, opts) {
|
|
|
379
392
|
intrinsic.forEach(digestNames, function (n, i) { byName[n] = intrinsic.bufferFrom(digests[i]); });
|
|
380
393
|
var built = [];
|
|
381
394
|
for (var _ip = 0; _ip < rcs.length; _ip++) {
|
|
382
|
-
|
|
395
|
+
_push(built, await _finishSignerInfo(rcs[_ip], byName[rcs[_ip].scheme.digest], null, eContentType, opts));
|
|
383
396
|
}
|
|
384
397
|
return _assembleSignedData(built, eContentType, opts, null);
|
|
385
398
|
}
|
|
@@ -420,19 +433,19 @@ function _sign(content, signers, opts) {
|
|
|
420
433
|
|
|
421
434
|
function _assembleSignedData(built, eContentType, opts, contentBuf) {
|
|
422
435
|
var seen = intrinsic.create(null), digestAlgs = [];
|
|
423
|
-
intrinsic.forEach(built, function (x) { var k = intrinsic.bufToString(x.digestAlgId, "hex"); if (!seen[k]) { seen[k] = 1;
|
|
436
|
+
intrinsic.forEach(built, function (x) { var k = intrinsic.bufToString(x.digestAlgId, "hex"); if (!seen[k]) { seen[k] = 1; _push(digestAlgs, x.digestAlgId); } });
|
|
424
437
|
var v3 = intrinsic.some(built, function (x) { return x.version === 3; }) || eContentType !== OID_DATA;
|
|
425
438
|
var version = v3 ? 3 : 1;
|
|
426
439
|
var encapFields = [b.oid(eContentType)];
|
|
427
|
-
if (!opts.detached)
|
|
440
|
+
if (!opts.detached) _push(encapFields, b.explicit(0, b.octetString(contentBuf)));
|
|
428
441
|
var encap = b.sequence(encapFields);
|
|
429
442
|
var sdFields = [b.integer(BigInt(version)), b.set(digestAlgs), encap];
|
|
430
443
|
if (opts.certificates !== false) {
|
|
431
444
|
var certDers = intrinsic.sort(_dedupe(intrinsic.filter(intrinsic.map(built, function (x) { return x.certDer; }),
|
|
432
445
|
function (d) { return d != null; })), intrinsic.compare);
|
|
433
|
-
if (certDers.length)
|
|
446
|
+
if (certDers.length) _push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
|
|
434
447
|
}
|
|
435
|
-
|
|
448
|
+
_push(sdFields, b.set(intrinsic.map(built, function (x) { return x.si; })));
|
|
436
449
|
var signedData = b.sequence(sdFields);
|
|
437
450
|
var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
|
|
438
451
|
return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
|
|
@@ -450,7 +463,7 @@ function _digestAlgIdentifier(der) {
|
|
|
450
463
|
|
|
451
464
|
function _dedupe(ders) {
|
|
452
465
|
var seen = intrinsic.create(null), out = [];
|
|
453
|
-
intrinsic.forEach(ders, function (d) { var k = intrinsic.bufToString(d, "hex"); if (!seen[k]) { seen[k] = 1;
|
|
466
|
+
intrinsic.forEach(ders, function (d) { var k = intrinsic.bufToString(d, "hex"); if (!seen[k]) { seen[k] = 1; _push(out, d); } });
|
|
454
467
|
return out;
|
|
455
468
|
}
|
|
456
469
|
|
|
@@ -496,9 +509,9 @@ function certsOnly(certs, opts) {
|
|
|
496
509
|
var crlDers = intrinsic.sort(_dedupe(intrinsic.map(crlList, function (c) { return _normEntityDer(c, "a CRL", "X509 CRL", _parseCrl); })), intrinsic.compare);
|
|
497
510
|
var encap = b.sequence([b.oid(OID_DATA)]);
|
|
498
511
|
var sdFields = [b.integer(1n), b.set([]), encap];
|
|
499
|
-
if (certDers.length)
|
|
500
|
-
if (crlDers.length)
|
|
501
|
-
|
|
512
|
+
if (certDers.length) _push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
|
|
513
|
+
if (crlDers.length) _push(sdFields, b.contextConstructed(1, intrinsic.bufferConcat(crlDers)));
|
|
514
|
+
_push(sdFields, b.set([]));
|
|
502
515
|
var signedData = b.sequence(sdFields);
|
|
503
516
|
var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
|
|
504
517
|
return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
|
|
@@ -512,7 +525,7 @@ function _toBuf(v, what) {
|
|
|
512
525
|
|
|
513
526
|
function _resolveSignerIndices(spec, n) {
|
|
514
527
|
if (spec == null) { if (n < 1) throw _err("cms/bad-input", "the SignedData carries no SignerInfo to countersign"); return [0]; }
|
|
515
|
-
if (spec === "all") { var all = []; for (var i = 0; i < n; i++) all
|
|
528
|
+
if (spec === "all") { var all = []; for (var i = 0; i < n; i++) _push(all, i); return all; }
|
|
516
529
|
var arr = Array.isArray(spec) ? spec : [spec];
|
|
517
530
|
if (!arr.length) throw _err("cms/bad-input", "signerIndex must select at least one signer");
|
|
518
531
|
arr.forEach(function (i) { if (typeof i !== "number" || !Number.isInteger(i) || i < 0 || i >= n) throw _err("cms/bad-input", "signerIndex out of range: " + i); });
|
|
@@ -534,10 +547,10 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
|
|
|
534
547
|
if (opts.signedAttributes === false) return null;
|
|
535
548
|
return intrinsic.chain(_digest(scheme.digest, targetSigOctets), function (md) {
|
|
536
549
|
var pairs = [{ type: O("messageDigest"), values: [b.octetString(md)] }];
|
|
537
|
-
if (opts.signingTime !== false) pairs
|
|
550
|
+
if (opts.signingTime !== false) _push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
|
|
538
551
|
var csApOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
|
|
539
552
|
if (csApOid) {
|
|
540
|
-
|
|
553
|
+
_push(pairs, _algorithmProtectionPair(csApOid, scheme.digestAlgId, scheme.sigAlgId, 1));
|
|
541
554
|
}
|
|
542
555
|
var extra = _resolveAttrPairs(opts.additionalSignedAttributes, "a countersignature signed attribute value");
|
|
543
556
|
extra.forEach(function (p) { if (p.type === O("contentType")) throw _err("cms/bad-input", "a countersignature must not carry a content-type attribute (RFC 5652 sec. 11.4)"); });
|
|
@@ -556,8 +569,9 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
|
|
|
556
569
|
});
|
|
557
570
|
return intrinsic.chain(selfChecked, function () {
|
|
558
571
|
var fields = [b.integer(BigInt(sidv.version)), sidv.sid, scheme.digestAlgId];
|
|
559
|
-
if (attrs) fields
|
|
560
|
-
fields
|
|
572
|
+
if (attrs) _push(fields, attrs.wire);
|
|
573
|
+
_push(fields, scheme.sigAlgId);
|
|
574
|
+
_push(fields, b.octetString(sig));
|
|
561
575
|
return { value: b.sequence(fields), certDer: certDer, digestAlgId: scheme.digestAlgId };
|
|
562
576
|
});
|
|
563
577
|
});
|
|
@@ -568,13 +582,17 @@ function _mergeCountersig(uaNode, newCsValues) {
|
|
|
568
582
|
var CS = O("countersignature");
|
|
569
583
|
var others = [], csValues = [];
|
|
570
584
|
if (uaNode) uaNode.children.forEach(function (attr) {
|
|
571
|
-
if (asn1.read.oid(attr.children[0]) === CS) attr.children[1].children
|
|
572
|
-
else others
|
|
585
|
+
if (asn1.read.oid(attr.children[0]) === CS) intrinsic.forEach(attr.children[1].children, function (v) { _push(csValues, v.bytes); });
|
|
586
|
+
else _push(others, attr.bytes);
|
|
573
587
|
});
|
|
574
|
-
|
|
588
|
+
intrinsic.forEach(newCsValues, function (v) { _push(csValues, v); });
|
|
575
589
|
var csAttr = b.sequence([b.oid(CS), b.set(csValues)]);
|
|
576
|
-
|
|
577
|
-
|
|
590
|
+
/** @internal `concatList`, not `concat`: `Array.prototype.concat` builds its result through the
|
|
591
|
+
* species constructor, so a species answering with a Proxy intercepted the countersignature
|
|
592
|
+
* attribute as it was inserted and the merged value went out without it. `concatList` copies own
|
|
593
|
+
* indexes into an array it made itself. */
|
|
594
|
+
var setOf = b.set(intrinsic.concatList(others, [csAttr]));
|
|
595
|
+
var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
|
|
578
596
|
return wire;
|
|
579
597
|
}
|
|
580
598
|
|
|
@@ -583,7 +601,7 @@ function _appendCountersigs(siNode, newCsValues) {
|
|
|
583
601
|
var last = kids[kids.length - 1];
|
|
584
602
|
var hasUa = last.tagClass === "context" && last.tagNumber === 1;
|
|
585
603
|
var base = (hasUa ? kids.slice(0, kids.length - 1) : kids).map(function (k) { return k.bytes; });
|
|
586
|
-
base
|
|
604
|
+
_push(base, _mergeCountersig(hasUa ? last : null, newCsValues));
|
|
587
605
|
return b.sequence(base);
|
|
588
606
|
}
|
|
589
607
|
|
|
@@ -603,7 +621,7 @@ function _spliceNested(siNode, j, newCsValues) {
|
|
|
603
621
|
if (!found) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
|
|
604
622
|
var setOf = b.set(attrs); var wire = Buffer.from(setOf); wire[0] = 0xA1;
|
|
605
623
|
var base = kids.slice(0, kids.length - 1).map(function (k) { return k.bytes; });
|
|
606
|
-
base
|
|
624
|
+
_push(base, wire);
|
|
607
625
|
return b.sequence(base);
|
|
608
626
|
}
|
|
609
627
|
|
|
@@ -619,7 +637,11 @@ function _targetPreimage(siNode, opts) {
|
|
|
619
637
|
var last = siNode.children[siNode.children.length - 1];
|
|
620
638
|
var CS = O("countersignature");
|
|
621
639
|
if (!last || last.tagClass !== "context" || last.tagNumber !== 1) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
|
|
622
|
-
|
|
640
|
+
/** @internal The selection returns the first matching attribute or null, because `filter(...)[0]`
|
|
641
|
+
* indexes a result that is EMPTY when the signer carries no countersignature attribute, and index
|
|
642
|
+
* 0 of an empty array answers from the array prototype: the refusal below would then not be
|
|
643
|
+
* reached and the signature bytes would be taken from whatever the accessor answered with. */
|
|
644
|
+
var attr = guard.list.firstMatch(last.children, function (a) { return asn1.read.oid(a.children[0]) === CS; });
|
|
623
645
|
if (!attr) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
|
|
624
646
|
var values = attr.children[1].children;
|
|
625
647
|
var j = opts.countersignatureOf;
|
|
@@ -653,15 +675,15 @@ function _countersign(cmsInput, signers, opts) {
|
|
|
653
675
|
var jobs = [];
|
|
654
676
|
targets.forEach(function (t) {
|
|
655
677
|
var preimage = _targetPreimage(siSet.children[t], opts);
|
|
656
|
-
|
|
678
|
+
intrinsic.forEach(list, function (cs) { _push(jobs, { t: t, p: _buildCountersignature(preimage, cs, opts) }); });
|
|
657
679
|
});
|
|
658
680
|
return intrinsic.chain(intrinsic.allOf(intrinsic.mapList(jobs, function (j) { return j.p; })), function (built) {
|
|
659
681
|
var byTarget = intrinsic.create(null), certDers = [], csDigestAlgs = [];
|
|
660
682
|
intrinsic.forEach(built, function (res, i) {
|
|
661
683
|
var slot = byTarget[jobs[i].t] || (byTarget[jobs[i].t] = []);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
684
|
+
_push(slot, res.value);
|
|
685
|
+
_push(certDers, res.certDer);
|
|
686
|
+
_push(csDigestAlgs, res.digestAlgId);
|
|
665
687
|
});
|
|
666
688
|
|
|
667
689
|
var newSiSet = b.set(siSet.children.map(function (siNode, idx) {
|
|
@@ -675,8 +697,8 @@ function _countersign(cmsInput, signers, opts) {
|
|
|
675
697
|
else if (sdKids[i].tagClass === "context" && sdKids[i].tagNumber === 1) crlsNode = sdKids[i];
|
|
676
698
|
}
|
|
677
699
|
var existing = [];
|
|
678
|
-
if (certsNode) certsNode.children
|
|
679
|
-
if (opts.certificates !== false)
|
|
700
|
+
if (certsNode) intrinsic.forEach(certsNode.children, function (c) { _push(existing, c.bytes); });
|
|
701
|
+
if (opts.certificates !== false) intrinsic.forEach(certDers, function (d) { _push(existing, d); });
|
|
680
702
|
/** @internal The DER SET ordering through the captured copy, sort AND comparator: read off its own
|
|
681
703
|
* home, any of the three decides which certificate lands where in the set this message carries. */
|
|
682
704
|
var allCerts = guard.list.sortedCopy(_dedupe(existing), intrinsic.compare);
|
|
@@ -693,20 +715,20 @@ function _countersign(cmsInput, signers, opts) {
|
|
|
693
715
|
* comparison would list it a second time. */
|
|
694
716
|
var listed = [];
|
|
695
717
|
intrinsic.forEach(intrinsic.isArray(parsed.digestAlgorithms) ? parsed.digestAlgorithms : [],
|
|
696
|
-
function (a) {
|
|
718
|
+
function (a) { _push(listed, a); });
|
|
697
719
|
var digestAlgs = intrinsic.map(sdKids[1].children, function (d) { return d.bytes; });
|
|
698
720
|
intrinsic.forEach(csDigestAlgs, function (der) {
|
|
699
721
|
var info = _digestAlgIdentifier(der);
|
|
700
722
|
var already = false;
|
|
701
723
|
intrinsic.forEach(listed, function (alg) { if (cms.sameDigestAlgorithm(alg, info)) already = true; });
|
|
702
724
|
if (already) return;
|
|
703
|
-
|
|
704
|
-
|
|
725
|
+
_push(listed, info);
|
|
726
|
+
_push(digestAlgs, der);
|
|
705
727
|
});
|
|
706
728
|
var newSdFields = [sdKids[0].bytes, b.set(digestAlgs), sdKids[2].bytes];
|
|
707
|
-
if (allCerts.length) newSdFields
|
|
708
|
-
if (crlsNode) newSdFields
|
|
709
|
-
newSdFields
|
|
729
|
+
if (allCerts.length) _push(newSdFields, b.contextConstructed(0, intrinsic.bufferConcat(allCerts)));
|
|
730
|
+
if (crlsNode) _push(newSdFields, crlsNode.bytes);
|
|
731
|
+
_push(newSdFields, newSiSet);
|
|
710
732
|
var newCi = b.sequence([root.children[0].bytes, b.explicit(0, b.sequence(newSdFields))]);
|
|
711
733
|
return opts.pem ? pkix.pemEncode(newCi, "CMS", frameworkError.PemError) : newCi;
|
|
712
734
|
});
|
|
@@ -732,7 +754,7 @@ function _appendUnsignedAttr(siNode, attrDer) {
|
|
|
732
754
|
var existing = hasUa ? intrinsic.map(last.children, function (a) { return a.bytes; }) : [];
|
|
733
755
|
var setOf = b.set(intrinsic.concat(existing, [attrDer]));
|
|
734
756
|
var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
|
|
735
|
-
|
|
757
|
+
_push(base, wire);
|
|
736
758
|
return b.sequence(base);
|
|
737
759
|
}
|
|
738
760
|
|
|
@@ -955,7 +977,7 @@ function _attachTimestamp(input, token, opts) {
|
|
|
955
977
|
}));
|
|
956
978
|
var sdKids = t.sd.children;
|
|
957
979
|
var newSdFields = intrinsic.map(intrinsic.arraySlice(sdKids, 0, sdKids.length - 1), function (k) { return k.bytes; });
|
|
958
|
-
|
|
980
|
+
_push(newSdFields, newSiSet);
|
|
959
981
|
var out = b.sequence([t.root.children[0].bytes, b.explicit(0, b.sequence(newSdFields))]);
|
|
960
982
|
return opts.pem ? pkix.pemEncode(out, "CMS", frameworkError.PemError) : out;
|
|
961
983
|
}
|
package/lib/cms-verify.js
CHANGED
|
@@ -203,7 +203,11 @@ function _preferBoundCandidate(si, candidates) {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
function _certSki(cert) {
|
|
206
|
-
|
|
206
|
+
/** @internal The selection returns the first matching row or null. `filter(...)[0]` indexes a
|
|
207
|
+
* result that is EMPTY when the extension is absent, and index 0 of an empty array answers from
|
|
208
|
+
* the array prototype, so a value installed there reads at the test below as an extension the
|
|
209
|
+
* certificate does not carry. */
|
|
210
|
+
var ext = guard.list.firstMatch(cert.extensions || [], function (e) { return e.oid === oid.byName("subjectKeyIdentifier"); });
|
|
207
211
|
if (!ext) return null;
|
|
208
212
|
try {
|
|
209
213
|
return asn1.read.octetString(asn1.decode(ext.value));
|
|
@@ -359,7 +363,7 @@ async function _computeCountersigBytes(si, csTarget) {
|
|
|
359
363
|
attrs = _decodeSignedAttrs(reTagged);
|
|
360
364
|
} catch (e) { if (e instanceof CmsError) throw e; throw _err("cms/bad-signed-attrs", "the countersignature signedAttrs is not a valid SET OF Attribute", e); }
|
|
361
365
|
if (intrinsic.filter(attrs, function (a) { return a.type === OID_CONTENT_TYPE; }).length) throw _err("cms/misplaced-attr", "a countersignature must not carry a content-type attribute (RFC 5652 sec. 11.4)");
|
|
362
|
-
var mdAttr =
|
|
366
|
+
var mdAttr = guard.list.firstMatch(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; });
|
|
363
367
|
if (!mdAttr || mdAttr.values.length !== 1) throw _err("cms/bad-signed-attrs", "a countersignature's signedAttrs must carry exactly one message-digest attribute (RFC 5652 sec. 11.4)");
|
|
364
368
|
var declared;
|
|
365
369
|
try {
|
|
@@ -402,7 +406,7 @@ async function _computeSignedBytes(si, content, eContentType, digestByName) {
|
|
|
402
406
|
ctOid = asn1.read.oid(ctAttr[0].values[0]);
|
|
403
407
|
} catch (e) { throw _err("cms/bad-signed-attrs", "the content-type attribute value is not an OBJECT IDENTIFIER", e); }
|
|
404
408
|
if (ctOid !== eContentType) return { mismatch: { code: "cms/content-type-mismatch", message: "the content-type signed attribute does not match the SignedData eContentType (RFC 5652 sec. 5.3)" } };
|
|
405
|
-
var mdAttr =
|
|
409
|
+
var mdAttr = guard.list.firstMatch(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; });
|
|
406
410
|
if (!mdAttr || mdAttr.values.length !== 1) throw _err("cms/bad-signed-attrs", "signedAttrs must carry exactly one message-digest attribute (RFC 5652 sec. 5.4)");
|
|
407
411
|
var declared;
|
|
408
412
|
try {
|
|
@@ -1172,7 +1176,7 @@ var _permitsSigning = pkix.keyUsagePermits(pkix.makeNS("cms", CmsError, oid),
|
|
|
1172
1176
|
["digitalSignature", "contentCommitment", "nonRepudiation"]);
|
|
1173
1177
|
|
|
1174
1178
|
function _keyUsagePermitsSigning(parsedCerts, der) {
|
|
1175
|
-
var entry =
|
|
1179
|
+
var entry = guard.list.firstMatch(parsedCerts, function (c) { return intrinsic.bufferEquals(c.der, der); });
|
|
1176
1180
|
if (!entry) return true;
|
|
1177
1181
|
return _permitsSigning(entry.cert);
|
|
1178
1182
|
}
|
package/lib/crl-sign.js
CHANGED
|
@@ -24,6 +24,9 @@ var x509Schema = require("./schema-x509");
|
|
|
24
24
|
var signScheme = require("./sign-scheme");
|
|
25
25
|
var guard = require("./guard-all");
|
|
26
26
|
var intrinsic = require("./guard-intrinsic");
|
|
27
|
+
/** @internal The append every list here is built with: `push` stores at the index and a store
|
|
28
|
+
* consults a setter inherited there, and these lists become the bytes that get signed. */
|
|
29
|
+
var _push = intrinsic.append;
|
|
27
30
|
var _hasOwn = intrinsic.hasOwn, _bufferEquals = intrinsic.bufferEquals;
|
|
28
31
|
var _arrSlice = intrinsic.arraySlice, _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
|
|
29
32
|
/** @internal The RECEIVER for the captured `Promise.resolve`, captured too. `resolve` builds through
|
|
@@ -184,11 +187,11 @@ function _idpValue(idp) {
|
|
|
184
187
|
if (idp.fullName != null) {
|
|
185
188
|
var entries = Array.isArray(idp.fullName) ? pkiBuild.reqDenseArray(idp.fullName, "issuingDistributionPoint.fullName", _err, "crl/bad-idp") : [idp.fullName];
|
|
186
189
|
if (!entries.length) throw _err("crl/bad-idp", "issuingDistributionPoint fullName must carry at least one GeneralName");
|
|
187
|
-
children
|
|
190
|
+
_push(children,b.contextConstructed(0, b.contextConstructed(0, Buffer.concat(entries.map(_encodeGeneralName)))));
|
|
188
191
|
}
|
|
189
192
|
var scopeTrue = 0;
|
|
190
|
-
if (idp.onlyContainsUserCerts === true) { children
|
|
191
|
-
if (idp.onlyContainsCACerts === true) { children
|
|
193
|
+
if (idp.onlyContainsUserCerts === true) { _push(children,b.contextPrimitive(1, Buffer.from([0xff]))); scopeTrue++; }
|
|
194
|
+
if (idp.onlyContainsCACerts === true) { _push(children,b.contextPrimitive(2, Buffer.from([0xff]))); scopeTrue++; }
|
|
192
195
|
if (idp.indirectCRL === true) throw _err("crl/bad-idp", _INDIRECT_IDP_DEFERRED);
|
|
193
196
|
if (scopeTrue > 1) throw _err("crl/bad-idp", "at most one of onlyContainsUserCerts / onlyContainsCACerts may be TRUE (RFC 5280 sec. 5.2.5)");
|
|
194
197
|
if (!children.length) throw _err("crl/bad-idp", "issuingDistributionPoint MUST NOT be empty (RFC 5280 sec. 5.2.5)");
|
|
@@ -232,7 +235,7 @@ function _buildCrlExtensions(spec, ctx) {
|
|
|
232
235
|
var id = O(oidName);
|
|
233
236
|
if (seen[id]) throw _err("crl/bad-input", "duplicate CRL extension " + oidName + " (RFC 5280 sec. 5.2 -- at most one instance)");
|
|
234
237
|
seen[id] = true;
|
|
235
|
-
out
|
|
238
|
+
_push(out,_ext(id, critical, valueDer));
|
|
236
239
|
}
|
|
237
240
|
var crlNumberVal = null;
|
|
238
241
|
if (spec.crlNumber != null) { var cn = _boundedInteger(spec.crlNumber, "cRLNumber"); crlNumberVal = cn.value; push("cRLNumber", false, cn.tlv); }
|
|
@@ -264,7 +267,7 @@ function _buildCrlExtensions(spec, ctx) {
|
|
|
264
267
|
}
|
|
265
268
|
_assertExtensionValueDecodes(node, extnId, "extension");
|
|
266
269
|
if (extnId === O("deltaCRLIndicator")) isDelta = true;
|
|
267
|
-
out
|
|
270
|
+
_push(out,b.raw(der));
|
|
268
271
|
});
|
|
269
272
|
if (isDelta) {
|
|
270
273
|
if (seen[O("freshestCRL")]) throw _err("crl/bad-input", "freshestCRL MUST NOT appear in a delta CRL (RFC 5280 sec. 5.2.6)");
|
|
@@ -323,7 +326,7 @@ function _buildRevoked(entryList, isDelta) {
|
|
|
323
326
|
var id = O(oidName);
|
|
324
327
|
if (seen[id]) throw _err("crl/bad-input", "duplicate entry extension " + oidName + " in revoked entry [" + idx + "]");
|
|
325
328
|
seen[id] = true;
|
|
326
|
-
entryExts
|
|
329
|
+
_push(entryExts,_ext(id, critical, valueDer));
|
|
327
330
|
}
|
|
328
331
|
if (e.reason != null) {
|
|
329
332
|
var codeNum = _resolveReason(e.reason, isDelta);
|
|
@@ -360,10 +363,10 @@ function _buildRevoked(entryList, isDelta) {
|
|
|
360
363
|
}
|
|
361
364
|
}
|
|
362
365
|
_assertExtensionValueDecodes(xnode, extnId, "entry extension");
|
|
363
|
-
entryExts
|
|
366
|
+
_push(entryExts,b.raw(der));
|
|
364
367
|
});
|
|
365
368
|
}
|
|
366
|
-
if (entryExts.length) { anyExt = true; children
|
|
369
|
+
if (entryExts.length) { anyExt = true; _push(children,b.sequence(entryExts)); }
|
|
367
370
|
return b.sequence(children);
|
|
368
371
|
});
|
|
369
372
|
return { entries: entries, anyExt: anyExt };
|
|
@@ -375,7 +378,11 @@ function _parseIssuerCert(cert) {
|
|
|
375
378
|
}
|
|
376
379
|
|
|
377
380
|
function _assertIssuerCanSignCrl(issuerCert) {
|
|
378
|
-
|
|
381
|
+
/** @internal The selection returns the first matching row or null. `filter(...)[0]` indexes a
|
|
382
|
+
* result that is EMPTY when the certificate carries no keyUsage, and index 0 of an empty array
|
|
383
|
+
* answers from the array prototype, so a value installed there would be decoded as the issuer's
|
|
384
|
+
* key usage and decide whether it may sign this CRL. */
|
|
385
|
+
var kuExt = guard.list.firstMatch(issuerCert.extensions || [], function (e) { return e.oid === O("keyUsage"); });
|
|
379
386
|
if (!kuExt) return;
|
|
380
387
|
var ku;
|
|
381
388
|
try { ku = EXT_DECODERS[O("keyUsage")](kuExt.value); }
|
|
@@ -453,13 +460,13 @@ function _sign(spec, issuer, opts) {
|
|
|
453
460
|
* into the PreTBSCertList the alternative signature covers. */
|
|
454
461
|
function tbsOver(extList, omitSignatureAlg) {
|
|
455
462
|
var tbsChildren = [];
|
|
456
|
-
if (version === 2) tbsChildren
|
|
457
|
-
if (omitSignatureAlg !== true) tbsChildren
|
|
458
|
-
tbsChildren
|
|
459
|
-
tbsChildren
|
|
460
|
-
if (nextU) tbsChildren
|
|
461
|
-
if (revoked.entries.length) tbsChildren
|
|
462
|
-
if (extList.length) tbsChildren
|
|
463
|
+
if (version === 2) _push(tbsChildren,b.integer(1n));
|
|
464
|
+
if (omitSignatureAlg !== true) _push(tbsChildren,scheme.sigAlgId);
|
|
465
|
+
_push(tbsChildren,issuerDer);
|
|
466
|
+
_push(tbsChildren,thisU);
|
|
467
|
+
if (nextU) _push(tbsChildren,nextU);
|
|
468
|
+
if (revoked.entries.length) _push(tbsChildren,b.sequence(revoked.entries));
|
|
469
|
+
if (extList.length) _push(tbsChildren,b.explicit(0, b.sequence(extList)));
|
|
463
470
|
return b.sequence(tbsChildren);
|
|
464
471
|
}
|
|
465
472
|
|
|
@@ -813,7 +820,7 @@ function isRevoked(crl, serialNumber, opts) {
|
|
|
813
820
|
|
|
814
821
|
function _findExtOid(list, name) {
|
|
815
822
|
var want = O(name);
|
|
816
|
-
return (list || []
|
|
823
|
+
return guard.list.firstMatch(list || [], function (e) { return e.oid === want; });
|
|
817
824
|
}
|
|
818
825
|
|
|
819
826
|
var _IDP_SCHEMA = pkix.issuingDistributionPoint("crl/scope-not-authoritative");
|
package/lib/csr-sign.js
CHANGED
|
@@ -26,6 +26,9 @@ var pkiBuild = require("./pki-build");
|
|
|
26
26
|
var frameworkError = require("./framework-error");
|
|
27
27
|
var guard = require("./guard-all");
|
|
28
28
|
var intrinsic = require("./guard-intrinsic");
|
|
29
|
+
/** @internal The append every list here is built with: `push` stores at the index and a store
|
|
30
|
+
* consults a setter inherited there, and these lists become the bytes that get signed. */
|
|
31
|
+
var _push = intrinsic.append;
|
|
29
32
|
/** @internal The promise a self-check is awaited through, built from the constructor captured at load.
|
|
30
33
|
* `Promise.resolve` builds from its RECEIVER, so reading the global binding at the call hands the
|
|
31
34
|
* construction to whatever that binding holds, and a constructor settling without awaiting its
|
|
@@ -224,7 +227,7 @@ function _sign(spec, key, opts) {
|
|
|
224
227
|
function addAttr(attrType, valueTlv) {
|
|
225
228
|
if (seenAttr[attrType]) throw _err("csr/bad-input", "duplicate " + (oid.name(attrType) || attrType) + " attribute");
|
|
226
229
|
seenAttr[attrType] = true;
|
|
227
|
-
attrs
|
|
230
|
+
_push(attrs,b.sequence([b.oid(attrType), b.set([valueTlv])]));
|
|
228
231
|
}
|
|
229
232
|
if (spec.extensionRequest != null) addAttr(O("extensionRequest"), _buildRequestedExtensions(spec.extensionRequest, subjectSpki));
|
|
230
233
|
if (spec.challengePassword != null) addAttr(O("challengePassword"), _challengePassword(spec.challengePassword));
|
|
@@ -259,7 +262,7 @@ function _sign(spec, key, opts) {
|
|
|
259
262
|
if (!n.children[1].children || n.children[1].children.length === 0) throw _err("csr/bad-input", "pre-encoded attribute [" + i + "] value SET must contain at least one value (RFC 2986 SET SIZE(1..MAX))");
|
|
260
263
|
if (seenAttr[at]) throw _err("csr/bad-input", "duplicate " + (oid.name(at) || at) + " attribute");
|
|
261
264
|
seenAttr[at] = true;
|
|
262
|
-
attrs
|
|
265
|
+
_push(attrs,b.raw(der));
|
|
263
266
|
});
|
|
264
267
|
}
|
|
265
268
|
|
package/lib/ct.js
CHANGED
|
@@ -64,6 +64,7 @@ var _bufferCompare = intrinsic.compare;
|
|
|
64
64
|
var _subarray = intrinsic.subarray;
|
|
65
65
|
var _toLowerCase = intrinsic.toLowerCase;
|
|
66
66
|
var _ctTrim = intrinsic.uncurry(String.prototype.trim);
|
|
67
|
+
var _writeBigUInt64BE = intrinsic.uncurry(Buffer.prototype.writeBigUInt64BE);
|
|
67
68
|
var _bufCopy = intrinsic.uncurry(Buffer.prototype.copy);
|
|
68
69
|
var _writeU64BE = intrinsic.uncurry(Buffer.prototype.writeBigUInt64BE);
|
|
69
70
|
var _searchSet = intrinsic.uncurry(URLSearchParams.prototype.set);
|
|
@@ -293,8 +294,11 @@ function parseSctList(extValue) {
|
|
|
293
294
|
}
|
|
294
295
|
sctCount.tick();
|
|
295
296
|
var one = _parseSct(outer.subReader(sctLen, "ct/list-trailing-bytes"), sctLen);
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
/** @internal The parsed timestamps are appended by defining their indexes: the lists a caller
|
|
298
|
+
* reads its verdict from, and the `all` list a policy counts, are what a numeric setter on the
|
|
299
|
+
* array prototype would otherwise take an entry out of. */
|
|
300
|
+
if (one.unknown) { var u = { version: one.version, rawSct: one.rawSct }; intrinsic.append(unknownScts, u); intrinsic.append(all, u); }
|
|
301
|
+
else { intrinsic.append(scts, one); intrinsic.append(all, one); }
|
|
298
302
|
}
|
|
299
303
|
return guard.verdict.of({ scts: scts, unknownScts: unknownScts, all: all });
|
|
300
304
|
}
|
|
@@ -366,29 +370,36 @@ function reconstructSignedData(entry, sct) {
|
|
|
366
370
|
throw new CtError("ct/bad-input", "reconstructSignedData expects a decoded v1 SCT from parseSctList().scts[]");
|
|
367
371
|
}
|
|
368
372
|
var tsVal = guard.range.uint64(sct.timestamp, _ctErr, "ct/bad-input", "sct.timestamp (RFC 6962 3.2)");
|
|
373
|
+
/** @internal EVERY component of this preimage is appended by defining its index, and the
|
|
374
|
+
* concatenation is the captured one. These bytes are what a log's signature is verified over, so a
|
|
375
|
+
* numeric setter inherited from the array prototype replacing any one of them, the version, the
|
|
376
|
+
* signature type, the timestamp, the entry type, the certificate or the extensions, puts the
|
|
377
|
+
* verification on bytes the log never signed. Converting only the timestamp left the rest open,
|
|
378
|
+
* which is the whole class: the rule belongs to the function, not to the line it was found on. */
|
|
369
379
|
var parts = [];
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
var ts = _bufferAlloc(8); ts
|
|
373
|
-
|
|
380
|
+
intrinsic.append(parts, _bufferFrom([sct.version & 0xff]));
|
|
381
|
+
intrinsic.append(parts, _bufferFrom([0]));
|
|
382
|
+
var ts = _bufferAlloc(8); _writeBigUInt64BE(ts, tsVal); intrinsic.append(parts, ts);
|
|
383
|
+
intrinsic.append(parts, _bufferFrom([(entryType >> 8) & 0xff, entryType & 0xff]));
|
|
374
384
|
if (entryType === 0) {
|
|
375
385
|
var cert = _toBuffer(entry.leafCert, "leafCert", undefined, undefined, 0xffffff, "ct/bad-tbs-length");
|
|
376
|
-
|
|
386
|
+
intrinsic.append(parts, _u24Bytes(cert.length)); intrinsic.append(parts, cert);
|
|
377
387
|
} else {
|
|
378
388
|
var ikh = _toBuffer(entry.issuerKeyHash, "issuerKeyHash");
|
|
379
389
|
if (ikh.length !== 32) {
|
|
380
390
|
throw new CtError("ct/bad-issuer-key-hash", "issuer_key_hash must be exactly 32 bytes (SHA-256 of the issuer SPKI), got " + ikh.length + " (RFC 6962 sec. 3.2)");
|
|
381
391
|
}
|
|
382
392
|
var tbs = _toBuffer(entry.tbsCertificate, "tbsCertificate", undefined, undefined, 0xffffff, "ct/bad-tbs-length");
|
|
383
|
-
|
|
384
|
-
|
|
393
|
+
intrinsic.append(parts, ikh);
|
|
394
|
+
intrinsic.append(parts, _u24Bytes(tbs.length)); intrinsic.append(parts, tbs);
|
|
385
395
|
}
|
|
386
396
|
var ext = _toBuffer(sct.extensions, "sct.extensions", undefined, undefined, 0xffff, "ct/bad-extensions");
|
|
387
397
|
if (ext.length > 0xffff) {
|
|
388
398
|
throw new CtError("ct/bad-extensions", "CtExtensions must be 0..65535 bytes, got " + ext.length + " (RFC 6962 3.2)");
|
|
389
399
|
}
|
|
390
|
-
|
|
391
|
-
|
|
400
|
+
intrinsic.append(parts, _bufferFrom([(ext.length >> 8) & 0xff, ext.length & 0xff]));
|
|
401
|
+
intrinsic.append(parts, ext);
|
|
402
|
+
return intrinsic.bufferConcat(parts);
|
|
392
403
|
}
|
|
393
404
|
|
|
394
405
|
var CT_HASH = intrinsic.assign(intrinsic.create(null), { sha256: "SHA-256" });
|
|
@@ -584,7 +595,7 @@ function encodeSctList(scts) {
|
|
|
584
595
|
var el = ew.build();
|
|
585
596
|
total += el.length;
|
|
586
597
|
if (total > 0xffff) throw new CtError("ct/too-large", "the SCT list body exceeds the 65535-byte maximum (RFC 6962 sec. 3.3)");
|
|
587
|
-
|
|
598
|
+
intrinsic.append(elements, el);
|
|
588
599
|
}
|
|
589
600
|
var lw = new TlsWriter();
|
|
590
601
|
lw.vector(2, 1, 0xffff, Buffer.concat(elements, total), "ct/too-large");
|
|
@@ -803,7 +814,7 @@ function parseLogList(json, opts) {
|
|
|
803
814
|
continue;
|
|
804
815
|
}
|
|
805
816
|
byLogId[rec.logIdHex] = rec;
|
|
806
|
-
|
|
817
|
+
intrinsic.append(logs, rec);
|
|
807
818
|
}
|
|
808
819
|
}
|
|
809
820
|
}
|
|
@@ -1092,13 +1103,13 @@ function x509CertEntry(cert, issuer) {
|
|
|
1092
1103
|
for (var j = 0; j < extsSeq.children.length; j++) {
|
|
1093
1104
|
var ext = extsSeq.children[j];
|
|
1094
1105
|
if (ext.children[0] && intrinsic.bufferEquals(ext.children[0].bytes, sctOid)) { removed++; continue; }
|
|
1095
|
-
intrinsic.
|
|
1106
|
+
intrinsic.append(kept, ext.bytes);
|
|
1096
1107
|
}
|
|
1097
1108
|
if (removed === 0) throw _ctErr("ct/no-sct-extension", "the certificate carries no signedCertificateTimestampList extension (RFC 6962 sec. 3.2)");
|
|
1098
1109
|
var tbsChildren = [];
|
|
1099
1110
|
for (var k = 0; k < tbs.children.length; k++) {
|
|
1100
|
-
if (k !== wrapIdx) { intrinsic.
|
|
1101
|
-
if (kept.length > 0) intrinsic.
|
|
1111
|
+
if (k !== wrapIdx) { intrinsic.append(tbsChildren, tbs.children[k].bytes); continue; }
|
|
1112
|
+
if (kept.length > 0) intrinsic.append(tbsChildren, asn1.build.explicit(3, asn1.build.sequence(kept)));
|
|
1102
1113
|
}
|
|
1103
1114
|
var issuerKeyHash = nodeCrypto.createHash("sha256").update(issSpki).digest();
|
|
1104
1115
|
return { entryType: 1, tbsCertificate: asn1.build.sequence(tbsChildren), issuerKeyHash: issuerKeyHash };
|