@blamejs/pki 0.8.30 → 0.8.48

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +411 -0
  2. package/README.md +67 -16
  3. package/bin/pki.js +716 -30
  4. package/examples/issue-a-certificate.js +90 -0
  5. package/examples/post-quantum.js +66 -0
  6. package/examples/read-a-certificate.js +56 -0
  7. package/examples/revoke-and-check.js +86 -0
  8. package/examples/sign-and-verify-cms.js +63 -0
  9. package/index.js +18 -5
  10. package/lib/acme.js +223 -74
  11. package/lib/alt-sig.js +441 -0
  12. package/lib/asn1-der.js +48 -25
  13. package/lib/attrcert-sign.js +27 -19
  14. package/lib/cbor-det.js +24 -14
  15. package/lib/cmc-build.js +9 -2
  16. package/lib/cmc-verify.js +14 -3
  17. package/lib/cmp-build.js +17 -5
  18. package/lib/cmp-session.js +24 -11
  19. package/lib/cmp-verify.js +28 -19
  20. package/lib/cms-compress.js +3 -1
  21. package/lib/cms-decrypt.js +102 -7
  22. package/lib/cms-encrypt.js +59 -7
  23. package/lib/cms-sign.js +31 -9
  24. package/lib/cms-verify.js +22 -18
  25. package/lib/composite-kem.js +30 -18
  26. package/lib/composite-sig.js +29 -14
  27. package/lib/constants.js +28 -0
  28. package/lib/crl-sign.js +111 -19
  29. package/lib/crmf-sign.js +167 -15
  30. package/lib/csr-sign.js +117 -6
  31. package/lib/ct.js +939 -48
  32. package/lib/est.js +29 -16
  33. package/lib/framework-error.js +12 -0
  34. package/lib/guard-async.js +1 -1
  35. package/lib/guard-bytes.js +103 -20
  36. package/lib/guard-crypto.js +205 -3
  37. package/lib/guard-encoding.js +6 -1
  38. package/lib/guard-identifier.js +55 -8
  39. package/lib/guard-intrinsic.js +43 -0
  40. package/lib/guard-json.js +122 -9
  41. package/lib/guard-limits.js +12 -1
  42. package/lib/guard-list.js +63 -8
  43. package/lib/guard-name.js +167 -20
  44. package/lib/guard-range.js +43 -5
  45. package/lib/guard-text.js +41 -0
  46. package/lib/guard-verdict.js +39 -8
  47. package/lib/hpke.js +688 -42
  48. package/lib/http-transport.js +156 -4
  49. package/lib/identity-match.js +4 -4
  50. package/lib/inspect.js +448 -2
  51. package/lib/jose.js +93 -25
  52. package/lib/key.js +18 -13
  53. package/lib/lint.js +165 -1
  54. package/lib/merkle.js +233 -27
  55. package/lib/ocsp.js +27 -14
  56. package/lib/oid.js +14 -4
  57. package/lib/path-validate.js +143 -61
  58. package/lib/pkcs12-build.js +7 -2
  59. package/lib/pki-build.js +31 -7
  60. package/lib/possession.js +575 -0
  61. package/lib/related-cert.js +708 -0
  62. package/lib/revocation-fetch.js +6 -6
  63. package/lib/scep.js +15 -5
  64. package/lib/schema-c509.js +5 -2
  65. package/lib/schema-cmc.js +1 -1
  66. package/lib/schema-cmp.js +8 -8
  67. package/lib/schema-cms.js +2 -15
  68. package/lib/schema-csr.js +69 -0
  69. package/lib/schema-engine.js +10 -3
  70. package/lib/schema-pkix.js +267 -4
  71. package/lib/schema-tsp.js +7 -6
  72. package/lib/sign-scheme.js +22 -9
  73. package/lib/sigstore.js +684 -168
  74. package/lib/sleep.js +8 -1
  75. package/lib/smime.js +22 -1
  76. package/lib/tlog.js +1235 -0
  77. package/lib/tls-cert-compress.js +25 -8
  78. package/lib/tsp-sign.js +120 -35
  79. package/lib/tuf.js +1395 -0
  80. package/lib/validator-tpm.js +4 -1
  81. package/lib/verify-seam.js +7 -1
  82. package/lib/webauthn-mds.js +41 -4
  83. package/lib/webauthn.js +43 -25
  84. package/lib/webcrypto.js +48 -46
  85. package/lib/x509-sign.js +225 -19
  86. package/package.json +2 -1
  87. package/sbom.cdx.json +6 -6
@@ -479,11 +479,44 @@ function coerceToDer(input, opts) {
479
479
  * would otherwise be read end to end on the way to being refused for its size. */
480
480
  guard.limits.byteCap(buf, _COERCE_MAX_BYTES, function (c, m) { return new opts.ErrorClass(c, m); },
481
481
  opts.prefix + "/too-large", "parse input");
482
- return _isPemArmor(buf) ? pemDecode(buf, opts.pemLabel, opts.PemError) : buf;
482
+ if (!_isPemArmor(buf)) return buf;
483
+ /** @internal A DER header short enough for the short form can be entirely text bytes, so the
484
+ * probe alone cannot separate armor from a DER value carrying an armor line in its content: an
485
+ * APPLICATION 3 primitive is identifier 0x43 and any content length from 32 to 126 is a
486
+ * printable length octet. Bytes that do not decode as one complete DER value are armor, which is
487
+ * the resolution `pki convert` takes and keeps every PEM file a caller reads into a Buffer on the
488
+ * PEM path. The decode runs only where the probe already said armor, so DER input reaches its
489
+ * parser without it. */
490
+ if (!_isCompleteDer(buf)) return pemDecode(buf, opts.pemLabel, opts.PemError);
491
+ /** @internal A primitive tag makes any content valid, so bytes can satisfy both readings at once
492
+ * and no rule chooses between them: a caller handed the wrong one would be handed the other
493
+ * reading's bytes, silently. The argument is what is ambiguous, not the file, so the message
494
+ * names the two unambiguous ways to say which was meant. */
495
+ if (_isPemBlock(buf, opts)) {
496
+ throw new opts.ErrorClass(opts.prefix + "/bad-input",
497
+ "parse input is both one complete DER value and a well-formed PEM block, so which was meant " +
498
+ "cannot be read from the bytes: pass PEM as a string, or pass the DER value on its own");
499
+ }
500
+ return buf;
483
501
  }
484
502
  throw new opts.ErrorClass(opts.prefix + "/bad-input", "parse expects a DER BufferSource (Buffer, typed array, DataView, or ArrayBuffer) or a PEM string");
485
503
  }
486
504
 
505
+ /** @internal Whether a buffer also holds a well-formed PEM block, asked only to detect that both
506
+ * readings hold. The decoded bytes are discarded: the caller refuses rather than choosing one. */
507
+ function _isPemBlock(buf, opts) {
508
+ try { pemDecode(buf, opts.pemLabel, opts.PemError); return true; }
509
+ catch (_e) { return false; }
510
+ }
511
+
512
+ /** @internal Whether a buffer is exactly one complete DER value. Trailing bytes disqualify it, so a
513
+ * PEM file whose leading text happened to decode cannot be taken for DER on that prefix alone. */
514
+ function _isCompleteDer(buf) {
515
+ // allow:bare-decode classifies bytes AT the door, before a parse context exists to carry caps; the buffer is byte-capped above and the decode holds the codec's own caps.
516
+ try { asn1.decode(buf); return true; }
517
+ catch (_e) { return false; }
518
+ }
519
+
487
520
  /** @internal Whether a buffer is armored text rather than DER. Read from a fixed window at the
488
521
  * front, the answer is wrong for a file whose explanatory text is longer than the window, and the
489
522
  * caller then hands PEM to the DER decoder and reports the DER as malformed. So the whole buffer is
@@ -493,7 +526,11 @@ function _isPemArmor(buf) {
493
526
  var n = buf.length;
494
527
  for (var i = 0; i < n; i++) {
495
528
  var c = buf[i];
496
- var textByte = (c >= 0x20 && c < 0x7f) || c === 0x09 || c === 0x0a || c === 0x0d ||
529
+ /** @internal ASCII whitespace has six members and a text file carries all six, so the walk
530
+ * passes tab, line feed, vertical tab, form feed, carriage return and space, plus the printable
531
+ * range and the byte-order mark. Every other byte ends the walk: a boundary behind one means the
532
+ * buffer is not text, and DER is binary. A PEM file that does carry one is passed as a string. */
533
+ var textByte = (c >= 0x20 && c < 0x7f) || (c >= 0x09 && c <= 0x0d) ||
497
534
  c === 0xef || c === 0xbb || c === 0xbf;
498
535
  if (!textByte) return false;
499
536
  if (c === 0x2d && _bufToString(_subarray(buf, i, i + 10), "latin1") === "-----BEGIN") return true;
@@ -704,6 +741,68 @@ function algorithmIdentifier(ns, opts) {
704
741
  });
705
742
  }
706
743
 
744
+ /** @internal IssuerAndSerialNumber ::= SEQUENCE { issuer Name, serialNumber CertificateSerialNumber }
745
+ * (RFC 5652 sec. 10.2.4). CMS names the type and RFC 9763 sec. 3.1 reuses it inside a CSR attribute,
746
+ * so the shape is defined once and each caller supplies its own code and name for the refusal. */
747
+ function issuerAndSerialNumber(ns, opts) {
748
+ opts = opts || {};
749
+ return schema.seq([
750
+ schema.field("issuer", name(ns)),
751
+ schema.field("serialNumber", schema.integerLeaf()),
752
+ ], {
753
+ assert: "sequence", arity: { exact: 2 },
754
+ code: opts.code || (ns.prefix + "/bad-issuer-and-serial"), what: opts.what || "IssuerAndSerialNumber",
755
+ build: function (m) {
756
+ return {
757
+ issuer: m.fields.issuer.value.result,
758
+ serialNumber: m.fields.serialNumber.value,
759
+ serialNumberHex: _bufToString(m.fields.serialNumber.node.content, "hex"),
760
+ };
761
+ },
762
+ });
763
+ }
764
+
765
+ /** @internal The digest a signature algorithm OID names, where it names one. RFC 9763 sec. 4.1 reads
766
+ * this relation directly ("a hash algorithm explicitly indicated by the related certificate's
767
+ * signature OID"), and an algorithm whose OID fixes no digest, such as Ed25519 or ML-DSA, is absent
768
+ * rather than mapped to a default. The value is the registry name, so a caller that needs its own
769
+ * spelling maps from one table instead of carrying a second copy of the relation. */
770
+ var SIG_OID_DIGEST_ROWS = [
771
+ ["sha1WithRSAEncryption", "sha1"], ["sha256WithRSAEncryption", "sha256"],
772
+ ["sha384WithRSAEncryption", "sha384"], ["sha512WithRSAEncryption", "sha512"],
773
+ ["ecdsaWithSHA1", "sha1"], ["ecdsaWithSHA256", "sha256"],
774
+ ["ecdsaWithSHA384", "sha384"], ["ecdsaWithSHA512", "sha512"],
775
+ ["sha1", "sha1"], ["sha256", "sha256"], ["sha384", "sha384"], ["sha512", "sha512"],
776
+ ["sha3-256", "sha3-256"], ["sha3-512", "sha3-512"],
777
+ ["id-RSASSA-PSS-SHAKE128", "shake128"], ["id-RSASSA-PSS-SHAKE256", "shake256"],
778
+ ];
779
+ /** @internal The digest output length in octets, for the readers that hold a hash value to the length
780
+ * of the algorithm named beside it. A SHAKE is absent: its output length is a parameter of the use,
781
+ * not of the algorithm, so there is no single length to hold a value to. */
782
+ var DIGEST_LENGTH_ROWS = [
783
+ ["sha1", 20], ["sha256", 32], ["sha384", 48], ["sha512", 64],
784
+ ["sha3-256", 32], ["sha3-512", 64],
785
+ ];
786
+ function digestLengths() {
787
+ var out = _create(null);
788
+ _forEach(DIGEST_LENGTH_ROWS, function (r) { out[r[0]] = r[1]; });
789
+ return out;
790
+ }
791
+ var DIGEST_LENGTHS = digestLengths();
792
+ /** @internal Keyed by dotted OID through the registry the caller passes, this module taking its
793
+ * registry as a parameter rather than requiring it. A row whose name the registry does not carry
794
+ * throws rather than being skipped: a skipped row is a digest the readers silently stop deriving,
795
+ * which reads as "this certificate names no hash" on a certificate that names one. */
796
+ function signatureDigestNames(oidRegistry) {
797
+ var out = _create(null);
798
+ _forEach(SIG_OID_DIGEST_ROWS, function (r) {
799
+ var dotted = oidRegistry.byName(r[0]);
800
+ if (!dotted) throw new Error("schema-pkix: the signature-digest table names " + r[0] + ", which the OID registry does not carry");
801
+ out[dotted] = r[1];
802
+ });
803
+ return out;
804
+ }
805
+
707
806
  function pbkdf2Params(ns) {
708
807
  return schema.seq([
709
808
  schema.field("salt", schema.octetString()),
@@ -1349,7 +1448,12 @@ function crlExtensionDecoders(ns) {
1349
1448
  var doorScope = _create(null);
1350
1449
  doorScope.crl = _assign(_create(null), byScope.crl);
1351
1450
  doorScope.entry = _assign(_create(null), byScope.entry);
1352
- _forEach(["authorityKeyIdentifier", "issuerAltName", "authorityInfoAccess", "freshestCRL"], function (n) {
1451
+ /** @internal ITU-T X.509 (2019) clause 9.8 states altSignatureAlgorithm and altSignatureValue as CRL
1452
+ * extensions as well as certificate ones, and clause 7.10.3 gives the CRL the same procedure, so the
1453
+ * two share one decoder with the certificate scope. subjectAltPublicKeyInfo is absent: the NOTE in
1454
+ * clause 7.2.2 says it "is only used as a public-key certificate extension". */
1455
+ _forEach(["authorityKeyIdentifier", "issuerAltName", "authorityInfoAccess", "freshestCRL",
1456
+ "altSignatureAlgorithm", "altSignatureValue"], function (n) {
1353
1457
  doorScope.crl[O(n)] = scopedCertDecoder(ns, n);
1354
1458
  });
1355
1459
  doorScope.entry[O("certificateIssuer")] = _generalNamesDecoder(ns);
@@ -1670,10 +1774,93 @@ function _acceptExtensionRecord(ext, E, code, key) {
1670
1774
  record.oid = checked.oid;
1671
1775
  record.name = typeof checked.name === "string" ? checked.name : null;
1672
1776
  record.critical = checked.critical === true;
1673
- record.value = guard.bytes.snapshot(checked.value, E, code, "the extension value");
1777
+ /** @internal Normalized to a byte view before it is copied. The check above admits what
1778
+ * `guard.bytes.isByteSource` admits, which includes a DataView and an ArrayBuffer, and
1779
+ * `guard.bytes.snapshot` takes neither: a value this verb had just called acceptable was then refused
1780
+ * for being the wrong kind of container, so the two messages contradicted each other about one value.
1781
+ * `snapshotSource` views and copies in one call, and the view shares the caller's store rather than
1782
+ * copying it, so the copy is still the only allocation. */
1783
+ record.value = guard.bytes.snapshotSource(checked.value, E, code, "the extension value");
1674
1784
  return record;
1675
1785
  }
1676
1786
 
1787
+ /** @internal Whether a parsed certificate's keyUsage permits a named set of purposes, as one definition
1788
+ * three verifiers share. RFC 5280 sec. 4.2.1.3 confines a key to the purposes a present keyUsage asserts,
1789
+ * so a verifier checking a signature under a certificate's key owes this check: a certificate confined to
1790
+ * `keyAgreement` does not authorize a signature. Absent keyUsage is unconfined and permits; a keyUsage that
1791
+ * does not DECODE denies rather than permits, since an extension nothing could read has not been satisfied.
1792
+ * `allowed` is the set each caller's own specification names, which is the only thing that differs between
1793
+ * them: RFC 9483 sec. 3.2 requires `digitalSignature` alone, while a signature over content is also
1794
+ * authorized by `contentCommitment` or `nonRepudiation`. */
1795
+ function keyUsagePermits(ns, allowed) {
1796
+ var kuOid = ns.oid.byName("keyUsage");
1797
+ var decoders = certExtensionDecoders(ns).byOid;
1798
+ return function (parsedCert) {
1799
+ var exts = (parsedCert && parsedCert.extensions) || [];
1800
+ for (var i = 0; i < exts.length; i++) {
1801
+ if (exts[i].oid !== kuOid) continue;
1802
+ var ku;
1803
+ try { ku = decoders[kuOid](exts[i].value); }
1804
+ catch (e) { void e; return false; }
1805
+ for (var a = 0; a < allowed.length; a++) if (ku[allowed[a]] === true) return true;
1806
+ return false;
1807
+ }
1808
+ return true;
1809
+ };
1810
+ }
1811
+
1812
+ /** @internal The subject-key algorithms that can only ever SIGN, as one table the linter and the verifier
1813
+ * share. RFC 9883 sec. 6 states "The privateKeyPossessionStatement attribute MUST NOT be used to obtain a
1814
+ * signature certificate", and sec. 4 states the same requirement as a property of the request: "the
1815
+ * subjectPKInfo MUST contain the public key for the key establishment algorithm". The mechanism exists
1816
+ * because a key-establishment key cannot sign and so cannot prove possession the PKCS#10 way. A key that
1817
+ * can only sign has no such problem, so a request to certify one through that attribute asks for the
1818
+ * certificate those sentences forbid, whether or not the request names a key usage. Read off the requested
1819
+ * usages alone, the rule missed every request that omitted the keyUsage extension; read off this table
1820
+ * too, the two doors that apply it reach the same verdict on the same request.
1821
+ *
1822
+ * Only the signature-ONLY families are here. RSA and EC can do either, so an RSA or EC subject key says
1823
+ * nothing on its own and is left to the usages a request asks for. `rsassaPss` IS here and
1824
+ * `rsaEncryption` is NOT, which is the distinction the rule turns on: a bare RSA key can do key
1825
+ * transport, while an id-RSASSA-PSS SPKI is restricted to signing and can no more establish a key than
1826
+ * an EdDSA one. `dsa` and the stateful hash-based algorithms sign by construction. */
1827
+ var SIGNATURE_ONLY_KEY_NAMES = [
1828
+ "Ed25519", "Ed448", "rsassaPss", "dsa",
1829
+ "id-alg-hss-lms-hashsig", "id-alg-xmss-hashsig", "id-alg-xmssmt-hashsig",
1830
+ ];
1831
+ /** @internal The families, matched by the prefix the registry files them under rather than listed one at a
1832
+ * time: three ML-DSA sets, twelve SLH-DSA sets and eighteen composite ML-DSA arms, all of which sign and
1833
+ * none of which establishes a key. Taking them by family means a set the registry gains later belongs to
1834
+ * this rule without a second edit, which is what kept RSASSA-PSS out of an earlier hand-written list. */
1835
+ var SIGNATURE_ONLY_KEY_PREFIXES = ["id-ml-dsa-", "id-slh-dsa-", "id-MLDSA"];
1836
+
1837
+ var _signatureOnlyByNs = new _WeakMapI();
1838
+
1839
+ /** @internal Whether a dotted subject-key algorithm OID names a signature-only family. Built once per
1840
+ * OID registry and memoized on it, since the registry is enumerated to pick the families up by prefix. */
1841
+ function signatureOnlyKeyOid(ns) {
1842
+ var table = _weakGet(_signatureOnlyByNs, ns.oid);
1843
+ if (table === undefined) {
1844
+ table = _assign(_create(null), {});
1845
+ _forEach(SIGNATURE_ONLY_KEY_NAMES, function (n) {
1846
+ var dotted = ns.oid.byName(n);
1847
+ if (dotted !== undefined && dotted !== null) table[dotted] = n;
1848
+ });
1849
+ var registry = ns.oid.all();
1850
+ _forEach(intrinsic.keys(registry), function (dotted) {
1851
+ var n = registry[dotted];
1852
+ if (typeof n !== "string") return;
1853
+ _forEach(SIGNATURE_ONLY_KEY_PREFIXES, function (p) {
1854
+ if (_strIndexOf(n, p) === 0) table[dotted] = n;
1855
+ });
1856
+ });
1857
+ _weakSet(_signatureOnlyByNs, ns.oid, table);
1858
+ }
1859
+ return function (dotted) {
1860
+ return typeof dotted === "string" && _hasOwn(table, dotted);
1861
+ };
1862
+ }
1863
+
1677
1864
  function certExtensionDecoders(ns) {
1678
1865
  var GN_SUBTREE = generalName(ns, { decodeValue: true, subtreeBase: true, code: ns.prefix + "/bad-name-constraints" });
1679
1866
  var _h = _decodeHelpers(ns), decodeTop = _h.decodeTop, seqChildren = _h.seqChildren, readInt = _h.readInt, O = _h.O;
@@ -1876,6 +2063,67 @@ function certExtensionDecoders(ns) {
1876
2063
  return null;
1877
2064
  }
1878
2065
 
2066
+ /** @internal RelatedCertificate ::= SEQUENCE { hashAlgorithm DigestAlgorithmIdentifier,
2067
+ * hashValue OCTET STRING } (RFC 9763 sec. 4.1), the digest of "the entire related certificate".
2068
+ * The value is held to the length of the algorithm it names, since a hash of the wrong length for
2069
+ * its own algorithm identifies no certificate and would otherwise be carried forward as an
2070
+ * identity to compare against. */
2071
+ function relatedCertificate(buf) {
2072
+ var C = ns.prefix + "/bad-extension-value";
2073
+ var kids = seqChildren(buf, C, "RelatedCertificate");
2074
+ if (kids.length !== 2) throw ns.E(C, "RelatedCertificate must be a SEQUENCE { hashAlgorithm, hashValue } (RFC 9763 sec. 4.1)");
2075
+ var alg;
2076
+ try { alg = schema.walk(algorithmIdentifier(ns), kids[0], ns).result; }
2077
+ catch (e) { throw ns.E(C, "RelatedCertificate hashAlgorithm must be a DigestAlgorithmIdentifier (RFC 9763 sec. 4.1)", e); }
2078
+ var value;
2079
+ try { value = _bufferFrom(asn1.read.octetString(kids[1])); }
2080
+ catch (e) { throw ns.E(C, "RelatedCertificate hashValue must be an OCTET STRING (RFC 9763 sec. 4.1)", e); }
2081
+ if (value.length === 0) throw ns.E(C, "RelatedCertificate hashValue must not be empty (RFC 9763 sec. 4.1)");
2082
+ var want = DIGEST_LENGTHS[alg.name];
2083
+ if (want !== undefined && value.length !== want) {
2084
+ throw ns.E(C, "RelatedCertificate hashValue is " + value.length + " octets, and " + alg.name + " produces " + want);
2085
+ }
2086
+ return { hashAlgorithm: alg.name, hashAlgorithmOid: alg.oid, hashValue: value };
2087
+ }
2088
+
2089
+ /** @internal SubjectAltPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
2090
+ * subjectAltPublicKey BIT STRING } (ITU-T X.509 (2019) clause 9.8.2). Those are the two components
2091
+ * SubjectPublicKeyInfo has, in that order, and a field name is not encoded, so the two types share
2092
+ * one encoding and this reads through the shared SPKI sub-schema. The whole value is surfaced as
2093
+ * `bytes` because it IS an SPKI on the wire: an importer takes it unchanged. */
2094
+ function subjectAltPublicKeyInfo(buf) {
2095
+ var C = ns.prefix + "/bad-extension-value";
2096
+ var n = decodeTop(buf, C, "SubjectAltPublicKeyInfo");
2097
+ var v;
2098
+ try { v = schema.walk(spki(ns), n, ns).result; }
2099
+ catch (e) { throw ns.E(C, "SubjectAltPublicKeyInfo must be a SEQUENCE { algorithm, subjectAltPublicKey BIT STRING } (ITU-T X.509 (2019) clause 9.8.2)", e); }
2100
+ if (v.publicKey.unusedBits !== 0) throw ns.E(C, "the subjectAltPublicKey BIT STRING must hold whole octets");
2101
+ if (v.publicKey.bytes.length === 0) throw ns.E(C, "the subjectAltPublicKey must not be empty");
2102
+ return { algorithm: v.algorithm, subjectAltPublicKey: v.publicKey.bytes, bytes: v.bytes };
2103
+ }
2104
+
2105
+ /** @internal AltSignatureAlgorithm ::= AlgorithmIdentifier (clause 9.8.3). The extension value is the
2106
+ * AlgorithmIdentifier itself, not a SEQUENCE wrapping one. */
2107
+ function altSignatureAlgorithm(buf) {
2108
+ var C = ns.prefix + "/bad-extension-value";
2109
+ var n = decodeTop(buf, C, "AltSignatureAlgorithm");
2110
+ try { return schema.walk(algorithmIdentifier(ns), n, ns).result; }
2111
+ catch (e) { throw ns.E(C, "AltSignatureAlgorithm must be an AlgorithmIdentifier (ITU-T X.509 (2019) clause 9.8.3)", e); }
2112
+ }
2113
+
2114
+ /** @internal AltSignatureValue ::= BIT STRING (clause 9.8.4). Held to whole octets, a signature being
2115
+ * an octet string of bits and every algorithm here producing one. */
2116
+ function altSignatureValue(buf) {
2117
+ var C = ns.prefix + "/bad-extension-value";
2118
+ var n = decodeTop(buf, C, "AltSignatureValue");
2119
+ var bs;
2120
+ try { bs = asn1.read.bitString(n); }
2121
+ catch (e) { throw ns.E(C, "AltSignatureValue must be a BIT STRING (ITU-T X.509 (2019) clause 9.8.4)", e); }
2122
+ if (bs.unusedBits !== 0) throw ns.E(C, "the AltSignatureValue BIT STRING must hold whole octets");
2123
+ if (bs.bytes.length === 0) throw ns.E(C, "the AltSignatureValue must not be empty");
2124
+ return { unusedBits: bs.unusedBits, bytes: _bufferFrom(bs.bytes) };
2125
+ }
2126
+
1879
2127
  function extKeyUsage(buf) {
1880
2128
  var C = ns.prefix + "/bad-extension-value";
1881
2129
  var kids = seqChildren(buf, C, "ExtKeyUsage");
@@ -2233,6 +2481,10 @@ function certExtensionDecoders(ns) {
2233
2481
  byOid[O("subjectInfoAccess")] = subjectInfoAccess;
2234
2482
  byOid[O("subjectDirectoryAttributes")] = subjectDirectoryAttributes;
2235
2483
  byOid[O("ocspNoCheck")] = ocspNoCheck;
2484
+ byOid[O("relatedCertificate")] = relatedCertificate;
2485
+ byOid[O("subjectAltPublicKeyInfo")] = subjectAltPublicKeyInfo;
2486
+ byOid[O("altSignatureAlgorithm")] = altSignatureAlgorithm;
2487
+ byOid[O("altSignatureValue")] = altSignatureValue;
2236
2488
  byOid[O("msCertificateTemplate")] = msCertificateTemplate;
2237
2489
  byOid[O("msEnrollCertType")] = msEnrollCertType;
2238
2490
  byOid[O("msCaVersion")] = msCaVersion;
@@ -2340,6 +2592,12 @@ function signedEnvelope(ns, tbsSchema, opts) {
2340
2592
  schema.field("signatureAlgorithm", algorithmIdentifier(ns)),
2341
2593
  schema.field("signatureValue", schema.bitString()),
2342
2594
  ], {
2595
+ /** @internal Exactly three, with no trailing element. X.509 (2019) extended the SIGNED
2596
+ * parameterized type with optional `altAlgorithmIdentifier` and `altSignature` components after
2597
+ * the signature, and then forbade them for every structure it profiles: "only one digital
2598
+ * signature shall be generated, i.e., the altAlgorithmIdentifier and the altSignature components
2599
+ * shall be absent" (clauses 7.2.1, 7.10.2, 11.3 and 14.2). Declaring either as an optional field
2600
+ * here would admit a second signature the text excludes, in every format that composes this. */
2343
2601
  assert: "sequence", arity: { exact: 3 }, code: opts.code, what: opts.what,
2344
2602
  build: function (m, ctx) {
2345
2603
  var tbsMatch = m.fields.toBeSigned.value;
@@ -2415,6 +2673,9 @@ module.exports = {
2415
2673
  DN_SHORT: DN_SHORT,
2416
2674
  time: time,
2417
2675
  algorithmIdentifier: algorithmIdentifier,
2676
+ issuerAndSerialNumber: issuerAndSerialNumber,
2677
+ digestLengths: digestLengths,
2678
+ signatureDigestNames: signatureDigestNames,
2418
2679
  pbkdf2Params: pbkdf2Params,
2419
2680
  pbmac1Params: pbmac1Params,
2420
2681
  spki: spki,
@@ -2447,6 +2708,8 @@ module.exports = {
2447
2708
  crlFixedCriticality: crlFixedCriticality,
2448
2709
  crlEntryFixedCriticality: crlEntryFixedCriticality,
2449
2710
  certExtensionDecoders: certExtensionDecoders,
2711
+ keyUsagePermits: keyUsagePermits,
2712
+ signatureOnlyKeyOid: signatureOnlyKeyOid,
2450
2713
  scopedCertDecoder: scopedCertDecoder,
2451
2714
  crlExtensionDecoders: crlExtensionDecoders,
2452
2715
  decodeExtensionList: decodeExtensionList,
package/lib/schema-tsp.js CHANGED
@@ -42,6 +42,7 @@ var oid = require("./oid");
42
42
  var smime = require("./schema-smime");
43
43
  var cms = require("./schema-cms");
44
44
  var frameworkError = require("./framework-error");
45
+ var guard = require("./guard-all");
45
46
 
46
47
  var TspError = frameworkError.TspError;
47
48
  var PemError = frameworkError.PemError;
@@ -177,11 +178,11 @@ var PKI_STATUS_INFO = schema.seq([
177
178
  _assertMinimalNamedBits(bs.unusedBits, bs.bytes);
178
179
  failInfo = { unusedBits: bs.unusedBits, bytes: bs.bytes, bits: _namedBits(bs.bytes) };
179
180
  }
180
- return {
181
+ return guard.verdict.of({
181
182
  status: Number(status),
182
183
  statusString: m.fields.statusString.present ? m.fields.statusString.value.items.map(function (it) { return it.value; }) : null,
183
184
  failInfo: failInfo,
184
- };
185
+ });
185
186
  },
186
187
  });
187
188
 
@@ -213,14 +214,14 @@ var TIME_STAMP_RESP = schema.seq([
213
214
  if (granted && !present) throw NS.E("tsp/missing-token", "a granted TimeStampResp must carry a timeStampToken (RFC 3161 sec. 2.4.2)");
214
215
  if (!granted && present) throw NS.E("tsp/unexpected-token", "a non-granted TimeStampResp must not carry a timeStampToken (RFC 3161 sec. 2.4.2)");
215
216
  if (status.status !== 2 && status.failInfo) throw NS.E("tsp/unexpected-failinfo", "failInfo is present only when the status is rejection(2) (RFC 3161 sec. 2.4.2)");
216
- return {
217
+ return guard.verdict.of({
217
218
  status: status.status,
218
219
  statusString: status.statusString,
219
220
  failInfo: status.failInfo,
220
221
  /** @internal The token is a second parse of bytes carried inside this one, so it takes the
221
222
  * caps this door was given rather than the built-in ceilings. */
222
223
  timeStampToken: present ? parseToken(m.fields.timeStampToken.value.bytes, ctx ? ctx.caps : undefined) : null,
223
- };
224
+ });
224
225
  },
225
226
  });
226
227
 
@@ -552,7 +553,7 @@ function signerCertificateDer(token) {
552
553
  * one key. Two that name two different certificates leave which of them signed the token
553
554
  * unsettled, so this answers with nothing and the caller says so, rather than taking one of
554
555
  * them. */
555
- if (found !== null) return Buffer.compare(found, named) === 0 ? found : null;
556
+ if (found !== null) return guard.bytes.compare(found, named) === 0 ? found : null;
556
557
  found = named;
557
558
  }
558
559
  return found;
@@ -576,7 +577,7 @@ function _essNamedCertificate(token, attr) {
576
577
  var element = certs[j];
577
578
  if (!element || element.tagClass !== "universal" || !Buffer.isBuffer(element.bytes)) continue;
578
579
  var actual = digest().update(element.bytes).digest();
579
- if (actual.length === want.length && Buffer.compare(actual, want) === 0) return element.bytes;
580
+ if (actual.length === want.length && guard.bytes.compare(actual, want) === 0) return element.bytes;
580
581
  }
581
582
  return null;
582
583
  }
@@ -5,7 +5,6 @@
5
5
 
6
6
  var asn1 = require("./asn1-der");
7
7
  var oid = require("./oid");
8
- var nodeCrypto = require("crypto");
9
8
  var pkcs8 = require("./schema-pkcs8");
10
9
  var pkix = require("./schema-pkix");
11
10
  var frameworkError = require("./framework-error");
@@ -14,6 +13,13 @@ var subtle = webcrypto.webcrypto.subtle;
14
13
  var validator = require("./validator-all");
15
14
  var guard = require("./guard-all");
16
15
  var intrinsic = require("./guard-intrinsic");
16
+ /** @internal The signing and key-import operations, captured at load. The objects were held and their
17
+ * METHODS fetched per call, which leaves them replaceable: a `sign` returning bytes of its own choosing
18
+ * decides the signature that goes out on a certificate, a CRL or a request, and an `importKey` or an
19
+ * `adoptKey` returning a different private key makes the captured signer sign with that key instead. */
20
+ var _subtleSign = intrinsic.uncurry(subtle.sign);
21
+ var _subtleImportKey = intrinsic.uncurry(subtle.importKey);
22
+ var _adoptKey = webcrypto.adoptKey;
17
23
  var compositeSig = require("./composite-sig");
18
24
  var b = asn1.build;
19
25
  function O(name) { return oid.byName(name); }
@@ -28,6 +34,10 @@ var _isBuffer = intrinsic.isBuffer;
28
34
  var _bufferFrom = intrinsic.bufferFrom;
29
35
  var _isU8 = intrinsic.types.isUint8Array;
30
36
  var _resolve = intrinsic.uncurry(intrinsic.promiseResolve);
37
+ /** @internal The promise constructor, captured at load, for the reason `guard-intrinsic` gives: the
38
+ * resolve builds its promise from the receiver, and the bytes a signature is made of travel through
39
+ * these promises. */
40
+ var _Promise = intrinsic.Promise;
31
41
 
32
42
  var HASH = intrinsic.assign(intrinsic.create(null), { sha256: "SHA-256", sha384: "SHA-384", sha512: "SHA-512" });
33
43
  var NODE_DIGEST = intrinsic.assign(intrinsic.create(null), { sha256: "sha256", sha384: "sha384", sha512: "sha512", shake128: "shake128", shake256: "shake256" });
@@ -211,7 +221,7 @@ function _importKey(key, imp, E) {
211
221
  throw E("bad-input", "the signing key is a WebCrypto CryptoKey of type " + _stringify(key.type) + "; a signing key must be a private key (type \"private\")");
212
222
  }
213
223
  _assertKeyMatchesScheme(key, imp, E);
214
- return webcrypto.adoptKey(key, imp, ["sign"], E, "bad-input");
224
+ return _adoptKey(key, imp, ["sign"], E, "bad-input");
215
225
  }
216
226
  var der, owned = false;
217
227
  if (_isBuffer(key)) der = guard.bytes.view(key, E, "bad-input", "the signer private key");
@@ -224,7 +234,7 @@ function _importKey(key, imp, E) {
224
234
  throw E("bad-input", "a signer key must be a WebCrypto CryptoKey, a node:crypto KeyObject, a PKCS#8 DER Buffer, " +
225
235
  "a PKCS#8 PEM string, or a signer { algorithm, publicKey, sign }");
226
236
  }
227
- var imported = subtle.importKey("pkcs8", der, imp, false, ["sign"]);
237
+ var imported = _subtleImportKey(subtle, "pkcs8", der, imp, false, ["sign"]);
228
238
  if (!owned) return imported;
229
239
  return imported.then(function (k) {
230
240
  guard.secret.zeroize(der, E, "bad-input", "the signer private-key copy");
@@ -315,11 +325,14 @@ function _signExternally(signer, scheme, signedBytes, E) {
315
325
  * the rewritten artifact. `Buffer.from` is not enough: a small copy comes out of Node's shared
316
326
  * pool, whose backing ArrayBuffer the callback could reach the original through. */
317
327
  var handed = new intrinsic.Uint8Array(signedBytes.length);
318
- handed.set(signedBytes);
328
+ /** @internal The copy goes through the captured `set`. Read off the instance it dispatches through
329
+ * `Uint8Array.prototype`, and a replacement there writes different bytes into the allocation the
330
+ * callback is handed, so the signer signs a message this never assembled. */
331
+ intrinsic.typedArraySet(handed, signedBytes);
319
332
  var produced;
320
333
  try { produced = intrinsic.apply(signer.sign, signer.receiver, [handed]); }
321
334
  catch (e) { throw E("bad-input", "the signer sign() callback failed", e); }
322
- return _resolve(Promise, produced).then(function (raw) {
335
+ return _resolve(_Promise, produced).then(function (raw) {
323
336
  var sig = guard.bytes.snapshotSource(raw, E, "bad-input", "the signature the signer returned");
324
337
  return _assertSignerSignature(sig, scheme, E);
325
338
  }, function (e) {
@@ -369,7 +382,7 @@ function _nodeSignOptions(key, scheme) {
369
382
  var name = scheme.sign.name;
370
383
  if (name === "ECDSA") return { key: key, dsaEncoding: "ieee-p1363" };
371
384
  if (name === "RSA-PSS") {
372
- return { key: key, padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: scheme.sign.saltLength };
385
+ return { key: key, padding: guard.crypto.padding.RSA_PKCS1_PSS, saltLength: scheme.sign.saltLength };
373
386
  }
374
387
  return key;
375
388
  }
@@ -393,7 +406,7 @@ function _signWithKeyObject(key, scheme, signedBytes, E) {
393
406
  }
394
407
  _assertKeyObjectMatchesScheme(key, scheme, E);
395
408
  try {
396
- return _bufferFrom(nodeCrypto.sign(_nodeDigest(scheme), signedBytes, _nodeSignOptions(key, scheme)));
409
+ return _bufferFrom(guard.crypto.sign(_nodeDigest(scheme), signedBytes, _nodeSignOptions(key, scheme)));
397
410
  } catch (e) {
398
411
  throw E("bad-input", "the signer KeyObject could not produce a " + scheme.imp.name + " signature", e);
399
412
  }
@@ -402,7 +415,7 @@ function _signWithKeyObject(key, scheme, signedBytes, E) {
402
415
  function signOverTbs(scheme, key, signedBytes, E) {
403
416
  if (intrinsic.types.isKeyObject(key)) {
404
417
  var koSig = _signWithKeyObject(key, scheme, signedBytes, E);
405
- return _resolve(Promise, scheme.ecdsaDer ? validator.sig.rawToEcdsaDer(koSig, scheme.coordLen) : koSig);
418
+ return _resolve(_Promise, scheme.ecdsaDer ? validator.sig.rawToEcdsaDer(koSig, scheme.coordLen) : koSig);
406
419
  }
407
420
  var signer = _snapshotSigner(key);
408
421
  if (signer) {
@@ -414,7 +427,7 @@ function signOverTbs(scheme, key, signedBytes, E) {
414
427
  return compositeSig.compositeSign(scheme.composite, _normCompositeKeys(key, scheme.composite, E), signedBytes).then(function (sig) { return _bufferFrom(sig); });
415
428
  }
416
429
  return _importKey(key, scheme.imp, E).then(function (priv) {
417
- return subtle.sign(scheme.sign, priv, signedBytes).then(function (sigRaw) {
430
+ return _subtleSign(subtle, scheme.sign, priv, signedBytes).then(function (sigRaw) {
418
431
  var sig = _bufferFrom(sigRaw);
419
432
  if (scheme.ecdsaDer) sig = validator.sig.rawToEcdsaDer(sig, scheme.coordLen);
420
433
  return sig;