@blamejs/pki 0.5.30 → 0.5.32

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 (53) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +2 -2
  3. package/lib/acme.js +347 -90
  4. package/lib/asn1-der.js +97 -33
  5. package/lib/attrcert-sign.js +1 -1
  6. package/lib/cmc-build.js +19 -8
  7. package/lib/cmc-verify.js +4 -4
  8. package/lib/cmp-build.js +36 -6
  9. package/lib/cmp-session.js +5 -5
  10. package/lib/cmp-verify.js +86 -16
  11. package/lib/cms-compress.js +2 -2
  12. package/lib/cms-decrypt.js +3 -3
  13. package/lib/cms-encrypt.js +1 -1
  14. package/lib/cms-sign.js +7 -7
  15. package/lib/cms-verify.js +9 -4
  16. package/lib/crl-sign.js +5 -5
  17. package/lib/crmf-sign.js +2 -1
  18. package/lib/csr-sign.js +1 -4
  19. package/lib/ct.js +8 -4
  20. package/lib/est.js +234 -34
  21. package/lib/framework-error.js +20 -6
  22. package/lib/guard-bytes.js +24 -3
  23. package/lib/http-digest.js +69 -16
  24. package/lib/http-retry-after.js +68 -24
  25. package/lib/http-transport.js +60 -6
  26. package/lib/inspect.js +13 -2
  27. package/lib/ip-utils.js +102 -25
  28. package/lib/key.js +2 -2
  29. package/lib/lint.js +1 -1
  30. package/lib/mime.js +27 -4
  31. package/lib/ocsp.js +7 -7
  32. package/lib/oid.js +16 -0
  33. package/lib/path-validate.js +76 -18
  34. package/lib/pbes2.js +2 -2
  35. package/lib/pkcs12-build.js +2 -2
  36. package/lib/pki-build.js +320 -21
  37. package/lib/rfc3339.js +75 -17
  38. package/lib/schema-c509.js +36 -9
  39. package/lib/schema-cmc.js +3 -3
  40. package/lib/schema-pkix.js +174 -25
  41. package/lib/schema-tsp.js +10 -1
  42. package/lib/sign-scheme.js +27 -7
  43. package/lib/sigstore.js +52 -9
  44. package/lib/smime.js +86 -6
  45. package/lib/trust.js +114 -14
  46. package/lib/tsp-sign.js +39 -27
  47. package/lib/validator-tpm.js +2 -2
  48. package/lib/webauthn-mds.js +24 -6
  49. package/lib/webauthn.js +3 -3
  50. package/lib/webcrypto.js +1 -1
  51. package/lib/x509-sign.js +9 -5
  52. package/package.json +1 -1
  53. package/sbom.cdx.json +6 -6
@@ -37,7 +37,7 @@ var NULL_PARAMS_DER = Buffer.from([0x05, 0x00]);
37
37
  // (default id-data), eContent = the RFC 1950 ZLIB stream }.
38
38
  async function compress(content, opts) {
39
39
  opts = opts || {};
40
- var raw = guard.bytes.view(content, CmsError, "cms/bad-input", "content");
40
+ var raw = guard.bytes.source(content, CmsError, "cms/bad-input", "content");
41
41
  var level = opts.level;
42
42
  if (level !== undefined && (typeof level !== "number" || !isFinite(level) || Math.floor(level) !== level)) throw _err("cms/bad-input", "opts.level must be an integer");
43
43
  var ctName = opts.contentType || "data";
@@ -86,7 +86,7 @@ async function decompress(input, opts) {
86
86
  }
87
87
 
88
88
  function _toDer(input) {
89
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) return guard.bytes.snapshot(input, CmsError, "cms/bad-input", "input");
89
+ if (guard.bytes.isByteSource(input)) return guard.bytes.snapshotSource(input, CmsError, "cms/bad-input", "input");
90
90
  if (typeof input === "string") { try { return schemaCms.pemDecode(input); } catch (e) { throw _err("cms/bad-input", "the CMS PEM could not be decoded", e); } }
91
91
  throw _err("cms/bad-input", "input must be a DER Buffer, Uint8Array, or PEM string");
92
92
  }
@@ -129,7 +129,7 @@ function _parse(input) {
129
129
  return schemaCms.parse(_toDer(input));
130
130
  }
131
131
  function _toDer(input) {
132
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) return guard.bytes.snapshot(input, CmsError, "cms/bad-input", "input");
132
+ if (guard.bytes.isByteSource(input)) return guard.bytes.snapshotSource(input, CmsError, "cms/bad-input", "input");
133
133
  if (typeof input === "string") { try { return schemaCms.pemDecode(input); } catch (e) { throw _err("cms/bad-input", "the CMS PEM could not be decoded", e); } }
134
134
  throw _err("cms/bad-input", "input must be a DER Buffer, Uint8Array, or PEM string");
135
135
  }
@@ -166,7 +166,7 @@ function _riKindForKey(km) {
166
166
  throw _err("cms/bad-input", "key material needs { key, cert }, { password }, { kek }, or { cek }");
167
167
  }
168
168
  function _assertSupported(ri, km) {
169
- if (ri.type === "kari" && ri.keyEncryptionAlgorithm && /mqv/i.test(ri.keyEncryptionAlgorithm.name || "")) throw _err("cms/unsupported-algorithm", "ECMQV kari is not supported");
169
+ if (ri.type === "kari" && ri.keyEncryptionAlgorithm && intrinsic.stringIndexOf(intrinsic.toLowerCase(ri.keyEncryptionAlgorithm.name || ""), "mqv") !== -1) throw _err("cms/unsupported-algorithm", "ECMQV kari is not supported"); // /mqv/i (ASCII name)
170
170
  if (ri.type === "ori") {
171
171
  if (ri.oriType !== O("kem")) throw _err("cms/unsupported-recipient-type", "unsupported OtherRecipientInfo type " + ri.oriType);
172
172
  if (ri.kemri && ri.kemri.kem && ri.kemri.kem.oid === O("id-kem-rsa")) throw _err("cms/unsupported-algorithm", "RSA-KEM is not supported");
@@ -801,7 +801,7 @@ function _releaseKeyDer(k) {
801
801
  if (k && k.owned) guard.secret.zeroize(k.der, CmsError, "cms/bad-input", "the recipient private-key copy");
802
802
  }
803
803
  function _normCertDer(cert) {
804
- if (Buffer.isBuffer(cert) || cert instanceof Uint8Array) return guard.bytes.snapshot(cert, CmsError, "cms/bad-input", "the recipient certificate");
804
+ if (guard.bytes.isByteSource(cert)) return guard.bytes.snapshotSource(cert, CmsError, "cms/bad-input", "the recipient certificate");
805
805
  if (typeof cert === "string") { try { return x509.pemDecode(cert); } catch (e) { throw _err("cms/bad-input", "the recipient certificate PEM could not be decoded", e); } }
806
806
  throw _err("cms/bad-input", "the recipient certificate must be a DER Buffer or PEM string");
807
807
  }
@@ -41,7 +41,7 @@ function _algId(name, shape) { return shape === "null" ? b.sequence([b.oid(O(nam
41
41
  // A certificate descriptor -> raw DER (the recipient cert is parsed for dispatch + rid; the caller
42
42
  // supplies bytes, not a re-encoded parse).
43
43
  function _normCertDer(cert, what) {
44
- if (Buffer.isBuffer(cert) || cert instanceof Uint8Array) return guard.bytes.snapshot(cert, CmsError, "cms/bad-input", what || "a certificate");
44
+ if (guard.bytes.isByteSource(cert)) return guard.bytes.snapshotSource(cert, CmsError, "cms/bad-input", what || "a certificate");
45
45
  if (typeof cert === "string") { try { return x509.pemDecode(cert); } catch (e) { throw _err("cms/bad-input", (what || "a certificate") + " PEM could not be decoded", e); } }
46
46
  throw _err("cms/bad-input", (what || "a certificate") + " must be a DER Buffer, Uint8Array, or PEM string");
47
47
  }
package/lib/cms-sign.js CHANGED
@@ -134,7 +134,7 @@ function _resolveAttrPairs(list, what) {
134
134
  return (list || []).map(function (a) {
135
135
  var vals = (a.values || []).map(function (v) { return _toBuf(v, what); });
136
136
  if (!vals.length) throw _err("cms/bad-input", "a signed attribute must carry at least one value (RFC 5652 -- Attribute values is SET SIZE (1..MAX))");
137
- return { type: /^\d+(\.\d+)+$/.test(a.type) ? a.type : O(a.type), values: vals };
137
+ return { type: oid.isDottedDecimal(a.type) ? a.type : O(a.type), values: vals };
138
138
  });
139
139
  }
140
140
 
@@ -351,17 +351,17 @@ function _keyOnlyKeyId(so) {
351
351
 
352
352
  function _normCertDer(c) {
353
353
  if (c == null) throw _err("cms/bad-input", "each signer requires a certificate (cert)");
354
- if (c instanceof Uint8Array || Buffer.isBuffer(c)) {
355
- c = guard.bytes.snapshot(c, CmsError, "cms/bad-input", "a signer certificate");
354
+ if (guard.bytes.isByteSource(c)) {
355
+ c = guard.bytes.snapshotSource(c, CmsError, "cms/bad-input", "a signer certificate");
356
356
  return c[0] === 0x30 ? c : _pemToDer(c.toString("latin1")); // DER as-is, else PEM
357
357
  }
358
358
  if (typeof c === "string") return _pemToDer(c);
359
359
  throw _err("cms/bad-input", "a signer certificate must be a DER Buffer or a PEM string");
360
360
  }
361
361
  function _pemToDer(text) {
362
- var m = text.match(/-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/);
363
- if (!m) throw _err("cms/bad-input", "a signer certificate PEM is not a CERTIFICATE block");
364
- return Buffer.from(m[1].replace(/[^A-Za-z0-9+/=]/g, ""), "base64");
362
+ var der = pkix.pemDecodeLenient(text, "CERTIFICATE");
363
+ if (der === null) throw _err("cms/bad-input", "a signer certificate PEM is not a CERTIFICATE block");
364
+ return der;
365
365
  }
366
366
 
367
367
  // pki.cms.sign -- documented by the @primitive block in cms-verify.js (the @module pki.cms home).
@@ -460,7 +460,7 @@ function _dedupe(ders) {
460
460
  }
461
461
 
462
462
  function _toBuf(v, what) {
463
- if (Buffer.isBuffer(v) || v instanceof Uint8Array) return guard.bytes.snapshot(v, CmsError, "cms/bad-input", what);
463
+ if (guard.bytes.isByteSource(v)) return guard.bytes.snapshotSource(v, CmsError, "cms/bad-input", what);
464
464
  throw _err("cms/bad-input", what + " must be a Buffer");
465
465
  }
466
466
 
package/lib/cms-verify.js CHANGED
@@ -123,7 +123,7 @@ EC_CURVE[oid.byName("secp384r1")] = { curve: "P-384", coordLen: 48 };
123
123
  EC_CURVE[oid.byName("secp521r1")] = { curve: "P-521", coordLen: 66 };
124
124
 
125
125
  function _toBuf(v, what) {
126
- if (Buffer.isBuffer(v) || v instanceof Uint8Array) return guard.bytes.snapshot(v, CmsError, "cms/bad-input", what);
126
+ if (guard.bytes.isByteSource(v)) return guard.bytes.snapshotSource(v, CmsError, "cms/bad-input", what);
127
127
  throw _err("cms/bad-input", what + " must be a Buffer");
128
128
  }
129
129
 
@@ -679,7 +679,7 @@ function _snapshotIfBytes(input, label) {
679
679
  // Every byte form the parser accepts -- an ArrayBuffer or a DataView reaches the
680
680
  // decoder as readily as a Buffer, and leaving those aliased would reopen the
681
681
  // window for exactly the inputs that came in by the wider door.
682
- if (ArrayBuffer.isView(input) || input instanceof ArrayBuffer) {
682
+ if (guard.bytes.isByteSource(input)) {
683
683
  return guard.bytes.snapshotSource(input, CmsError, "cms/bad-input", label);
684
684
  }
685
685
  return input;
@@ -804,7 +804,7 @@ function setEngine(engine) { _engine = engine; }
804
804
  // rewritten. `requiredEku` is copied for the same reason as the array.
805
805
  var _ANCHOR_CLONE_DEPTH = 8;
806
806
  function _cloneAnchorValue(v, depth) {
807
- if (Buffer.isBuffer(v) || ArrayBuffer.isView(v) || v instanceof ArrayBuffer) {
807
+ if (guard.bytes.isByteSource(v)) {
808
808
  return _snapshotIfBytes(v, "opts.trustAnchors[]");
809
809
  }
810
810
  if (v === null || typeof v !== "object") return v;
@@ -969,7 +969,12 @@ function _applyTrust(res, parsedCerts, cfg) {
969
969
  // A CONFIG fault -- unusable anchors, an invalid time -- is the caller's mistake and must
970
970
  // not be absorbed into "untrusted", which would read as a verdict about the message. A
971
971
  // chain that simply does not reach an anchor is not that: it is the answer.
972
- if (e && e.code && /bad-input|bad-anchor|bad-time/.test(String(e.code))) throw e;
972
+ if (e && e.code) {
973
+ var code = String(e.code);
974
+ if (intrinsic.stringIndexOf(code, "bad-input") !== -1 ||
975
+ intrinsic.stringIndexOf(code, "bad-anchor") !== -1 ||
976
+ intrinsic.stringIndexOf(code, "bad-time") !== -1) throw e;
977
+ }
973
978
  s.trusted = false;
974
979
  });
975
980
  });
package/lib/crl-sign.js CHANGED
@@ -180,7 +180,7 @@ function _resolveReason(reason, isDelta) {
180
180
  // The AKI keyIdentifier from the issuer: an explicit Buffer, or true -> the issuer cert's subjectKeyIdentifier,
181
181
  // else the SHA-1 of the issuer SPKI (RFC 5280 sec. 5.2.1 key-identifier method).
182
182
  function _akiKeyId(val, ctx) {
183
- if (Buffer.isBuffer(val)) return guard.bytes.snapshot(val, CrlError, "crl/bad-input", "the authorityKeyIdentifier keyIdentifier");
183
+ if (guard.bytes.isByteSource(val)) return guard.bytes.snapshotSource(val, CrlError, "crl/bad-input", "the authorityKeyIdentifier keyIdentifier");
184
184
  if (val === true) {
185
185
  if (ctx.issuerCert) {
186
186
  var ski = (ctx.issuerCert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
@@ -463,7 +463,7 @@ function _sign(spec, issuer, opts) {
463
463
  : "explicit form; the issuer takes { key, name, publicKey }, or { key, cert } to take both from a certificate");
464
464
  });
465
465
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "crl/bad-input", "pki.crl.sign has an unknown option ");
466
- if (issuer.key == null) throw _err("crl/bad-input", "a signing key (issuer.key, a PKCS#8 private key) is required");
466
+ if (issuer.key == null) throw _err("crl/bad-input", "a signing key (issuer.key, a WebCrypto CryptoKey or a PKCS#8 private key DER/PEM) is required");
467
467
 
468
468
  // Resolve the issuer name + signing-key SPKI. `{ cert }` supplies both; else `{ name|spec.issuer, publicKey }`.
469
469
  var issuerDer, issuerSpki, issuerCert = null;
@@ -597,7 +597,7 @@ function _coerceCrl(crl) {
597
597
  // names, are separate questions that only a certificate can answer.
598
598
  function _resolveIssuer(issuer) {
599
599
  if (issuer == null) throw _err("crl/bad-input", "an issuer is required to verify a CRL");
600
- if (Buffer.isBuffer(issuer)) { _assertValidSpki(issuer, "issuer SPKI"); return { spki: issuer, cert: null }; }
600
+ if (guard.bytes.isByteSource(issuer)) { var _isp = guard.bytes.source(issuer, CrlError, "crl/bad-input", "issuer SPKI"); _assertValidSpki(_isp, "issuer SPKI"); return { spki: _isp, cert: null }; }
601
601
  if (issuer.cert != null) { var ic = _parseIssuerCert(issuer.cert); return { spki: ic.subjectPublicKeyInfo.bytes, cert: ic }; }
602
602
  if (issuer.publicKey != null) { var spki = _reqDer(issuer.publicKey, "issuer.publicKey"); _assertValidSpki(spki, "issuer.publicKey"); return { spki: spki, cert: null }; }
603
603
  // A parsed certificate passed directly. It reaches the same identity and cRLSign checks the
@@ -685,8 +685,8 @@ function _serialHexOf(serial) {
685
685
  if (typeof serial === "bigint") v = serial;
686
686
  else if (typeof serial === "number") { if (!Number.isSafeInteger(serial)) throw _err("crl/bad-input", "serialNumber number must be a safe integer (pass a BigInt, hex string, or Buffer)"); v = BigInt(serial); }
687
687
  else if (typeof serial === "string") { try { v = BigInt(serial); } catch (e) { throw _err("crl/bad-input", "serialNumber string must be a decimal or 0x-hex integer", e); } }
688
- else if (Buffer.isBuffer(serial)) { v = serial.length ? BigInt("0x" + serial.toString("hex")) : 0n; }
689
- else throw _err("crl/bad-input", "serialNumber must be a BigInt, integer, hex string, or Buffer");
688
+ else if (guard.bytes.isByteSource(serial)) { var _sb = guard.bytes.source(serial, CrlError, "crl/bad-input", "serialNumber"); v = _sb.length ? BigInt("0x" + _sb.toString("hex")) : 0n; }
689
+ else throw _err("crl/bad-input", "serialNumber must be a BigInt, integer, hex string, or BufferSource");
690
690
  if (v <= 0n) throw _err("crl/bad-input", "serialNumber must be a positive integer");
691
691
  // Match schema-crl's serialNumberHex: the DER INTEGER content octets (preserving sign padding).
692
692
  return asn1.decode(b.integer(v)).content.toString("hex");
package/lib/crmf-sign.js CHANGED
@@ -328,7 +328,8 @@ function _buildEncryptedKeyPop(pop, outerTag, template) {
328
328
  // reject. CBC is the default here for that reason, not as a preference between the two.
329
329
  var cea = pop.contentEncryptionAlgorithm || "aes-256-cbc";
330
330
  if (typeof cea !== "string") throw _err("crmf/bad-input", "pop.contentEncryptionAlgorithm must be an algorithm name");
331
- if (/gcm|ccm|chacha/i.test(cea)) {
331
+ var _ceaLc = intrinsic.toLowerCase(cea); // /gcm|ccm|chacha/i (ASCII algorithm name)
332
+ if (intrinsic.stringIndexOf(_ceaLc, "gcm") !== -1 || intrinsic.stringIndexOf(_ceaLc, "ccm") !== -1 || intrinsic.stringIndexOf(_ceaLc, "chacha") !== -1) {
332
333
  throw _err("crmf/bad-popo", "encryptedKey is typed EnvelopedData, and the AEAD algorithm " + cea +
333
334
  " produces an AuthEnvelopedData instead (RFC 5083) -- choose a CBC content-encryption algorithm");
334
335
  }
package/lib/csr-sign.js CHANGED
@@ -47,9 +47,6 @@ var _b = pkiBuild.makeBuilder({
47
47
  NAME_SCHEMA: pkix.name(NS), SPKI_SCHEMA: pkix.spki(NS), EXT_DECODERS: EXT_DECODERS,
48
48
  });
49
49
 
50
- // challengePassword DirectoryString charset (PrintableString set); anything else uses UTF8String.
51
- var PRINTABLE_RE = /^[A-Za-z0-9 '()+,\-./:=?]*$/;
52
-
53
50
  // attributes ::= [0] IMPLICIT SET OF Attribute (RFC 2986). The IMPLICIT tag replaces the universal SET,
54
51
  // so it is a context-constructed [0] whose DER-sorted members ARE the SET-OF; empty -> A0 00.
55
52
  function _implicitSetOf0(members) {
@@ -64,7 +61,7 @@ function _buildRequestedExtensions(extSpec, subjectSpki) { return _b.requestedEx
64
61
  // value is in that charset, else UTF8String; never a Teletex/BMP/Universal string for a new value.
65
62
  function _challengePassword(pw) {
66
63
  if (typeof pw !== "string" || pw.length < 1 || pw.length > 255) throw _err("csr/bad-input", "challengePassword must be a 1..255 character string (RFC 2985 sec. 5.4.1)");
67
- return PRINTABLE_RE.test(pw) ? b.printable(pw) : b.utf8(pw);
64
+ return asn1.isPrintableString(pw) ? b.printable(pw) : b.utf8(pw);
68
65
  }
69
66
 
70
67
  /**
package/lib/ct.js CHANGED
@@ -49,6 +49,10 @@ var intrinsic = require("./guard-intrinsic.js");
49
49
  // replaceable properties to answer one thing, and here it decides whether a log state is one this
50
50
  // toolkit trusts -- answering true for a name the table never carried trusts an untrusted log.
51
51
  var _hasOwn = intrinsic.hasOwn;
52
+ var _strSlice = intrinsic.uncurry(String.prototype.slice);
53
+ var _JSON_SUFFIX = ".json";
54
+ // A pathname ending with the literal ".json" suffix (matching /\.json$/), by suffix compare (no regex).
55
+ function _endsWithJson(s) { return s.length >= _JSON_SUFFIX.length && _strSlice(s, s.length - _JSON_SUFFIX.length) === _JSON_SUFFIX; }
52
56
  var ByteReader = require("./byte-reader.js");
53
57
  var ByteWriter = require("./byte-writer.js");
54
58
  var oid = require("./oid.js");
@@ -973,9 +977,9 @@ function _parseHttpsUrl(u, label) {
973
977
  // yield an unambiguous sig URL, so the caller must pass opts.sigUrl explicitly (guards never guess a value).
974
978
  // The derived URL inherits the json URL's https origin.
975
979
  function _sigUrlFor(parsed) {
976
- if (!/\.json$/.test(parsed.pathname)) throw _ctErr("ct/bad-input", "cannot derive the detached-signature URL from a non-.json path (" + JSON.stringify(parsed.pathname) + "); pass opts.sigUrl explicitly");
980
+ if (!_endsWithJson(parsed.pathname)) throw _ctErr("ct/bad-input", "cannot derive the detached-signature URL from a non-.json path (" + JSON.stringify(parsed.pathname) + "); pass opts.sigUrl explicitly");
977
981
  var sig = new URL(parsed.href);
978
- sig.pathname = parsed.pathname.replace(/\.json$/, ".sig");
982
+ sig.pathname = _strSlice(parsed.pathname, 0, parsed.pathname.length - _JSON_SUFFIX.length) + ".sig";
979
983
  return sig.href;
980
984
  }
981
985
 
@@ -994,8 +998,8 @@ function _fetchBody(transport, url, req, label) {
994
998
  res = res || {};
995
999
  var h = {};
996
1000
  Object.keys(res.headers || {}).forEach(function (k) { h[k.toLowerCase()] = res.headers[k]; });
997
- var body = (Buffer.isBuffer(res.body) || res.body instanceof Uint8Array)
998
- ? guard.bytes.view(res.body, CtError, "ct/bad-input", label)
1001
+ var body = guard.bytes.isByteSource(res.body)
1002
+ ? guard.bytes.source(res.body, CtError, "ct/bad-input", label)
999
1003
  : Buffer.from(String(res.body == null ? "" : res.body), "utf8");
1000
1004
  if (body.length > req.maxResponseBytes) throw _ctErr("ct/response-too-large", "the " + label + " (" + body.length + " bytes) exceeds the " + req.maxResponseBytes + "-byte cap");
1001
1005
  if (res.status !== 200) throw _ctErr("ct/http-error", "the CT server returned HTTP " + JSON.stringify(res.status) + " for the " + label);