@blamejs/pki 0.5.16 → 0.5.18

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 (50) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/lib/acme.js +7 -4
  3. package/lib/asn1-der.js +1 -0
  4. package/lib/attrcert-sign.js +1 -0
  5. package/lib/cbor-det.js +1 -0
  6. package/lib/cmc-verify.js +1 -0
  7. package/lib/cmp-build.js +16 -1
  8. package/lib/cms-decrypt.js +58 -29
  9. package/lib/cms-encrypt.js +200 -38
  10. package/lib/cms-sign.js +18 -4
  11. package/lib/cms-verify.js +5 -1
  12. package/lib/constants.js +1 -0
  13. package/lib/crl-sign.js +62 -2
  14. package/lib/crmf-sign.js +1 -0
  15. package/lib/csr-sign.js +1 -0
  16. package/lib/ct.js +1 -0
  17. package/lib/est.js +1 -0
  18. package/lib/framework-error.js +1 -0
  19. package/lib/guard-secret.js +45 -1
  20. package/lib/hpke.js +6 -2
  21. package/lib/http-transport.js +1 -0
  22. package/lib/inspect.js +1 -0
  23. package/lib/jose.js +31 -3
  24. package/lib/key.js +2 -1
  25. package/lib/lint.js +1 -0
  26. package/lib/merkle.js +1 -0
  27. package/lib/ocsp.js +1 -0
  28. package/lib/oid.js +1 -0
  29. package/lib/path-validate.js +1 -0
  30. package/lib/pbes2.js +16 -8
  31. package/lib/pkcs12-build.js +203 -12
  32. package/lib/schema-all.js +1 -0
  33. package/lib/schema-c509.js +1 -0
  34. package/lib/schema-csrattrs.js +1 -0
  35. package/lib/schema-engine.js +1 -0
  36. package/lib/schema-pkcs8.js +1 -0
  37. package/lib/schema-smime.js +1 -0
  38. package/lib/schema-tsp.js +1 -0
  39. package/lib/schema-x509.js +1 -0
  40. package/lib/shbs.js +1 -0
  41. package/lib/sigstore.js +1 -0
  42. package/lib/smime.js +1 -0
  43. package/lib/tls-cert-compress.js +1 -0
  44. package/lib/trust.js +1 -0
  45. package/lib/tsp-sign.js +65 -0
  46. package/lib/webauthn.js +1 -0
  47. package/lib/webcrypto.js +11 -8
  48. package/lib/x509-sign.js +38 -0
  49. package/package.json +1 -1
  50. package/sbom.cdx.json +6 -6
package/lib/webcrypto.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * @module pki.webcrypto
6
6
  * @nav Core
7
7
  * @title WebCrypto
8
+ * @fullname WebCrypto: a SubtleCrypto surface over node:crypto
8
9
  * @order 50
9
10
  * @featured true
10
11
  * @slug webcrypto
@@ -470,7 +471,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
470
471
  return _withSecretBytes(key, function (kb) {
471
472
  var cipher = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: (alg.tagLength || 128) / 8 });
472
473
  if (aad) cipher.setAAD(aad);
473
- var ct = Buffer.concat([cipher.update(buf), cipher.final()]);
474
+ var ct = guard.secret.cipherFinish(cipher, buf, WebCryptoError, "webcrypto/operation", "an AES-GCM encrypt intermediate");
474
475
  return Buffer.concat([ct, cipher.getAuthTag()]);
475
476
  });
476
477
  }, "encrypt"));
@@ -480,7 +481,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
480
481
  return _toArrayBuffer(_runCipher(function () {
481
482
  return _withSecretBytes(key, function (kb) {
482
483
  var c2 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv);
483
- return Buffer.concat([c2.update(buf), c2.final()]);
484
+ return guard.secret.cipherFinish(c2, buf, WebCryptoError, "webcrypto/operation", "an AES-CBC encrypt intermediate");
484
485
  });
485
486
  }, "encrypt"));
486
487
  }
@@ -490,7 +491,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
490
491
  return _toArrayBuffer(_runCipher(function () {
491
492
  return _withSecretBytes(key, function (kb) {
492
493
  var c3 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter);
493
- return Buffer.concat([c3.update(buf), c3.final()]);
494
+ return guard.secret.cipherFinish(c3, buf, WebCryptoError, "webcrypto/operation", "an AES-CTR encrypt intermediate");
494
495
  });
495
496
  }, "encrypt"));
496
497
  }
@@ -528,7 +529,9 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
528
529
  var d = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: tagLen });
529
530
  if (gcmAad) d.setAAD(gcmAad);
530
531
  d.setAuthTag(tag);
531
- return Buffer.concat([d.update(ct), d.final()]);
532
+ // The recovered plaintext exists in full before final() judges the tag, so a forged message
533
+ // would otherwise abandon a readable copy on the throw path.
534
+ return guard.secret.cipherFinish(d, ct, WebCryptoError, "webcrypto/operation", "the recovered AES-GCM plaintext");
532
535
  });
533
536
  }, "decrypt"));
534
537
  }
@@ -537,7 +540,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
537
540
  return _toArrayBuffer(_runCipher(function () {
538
541
  return _withSecretBytes(key, function (kb) {
539
542
  var d2 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv2);
540
- return Buffer.concat([d2.update(buf), d2.final()]);
543
+ return guard.secret.cipherFinish(d2, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CBC plaintext");
541
544
  });
542
545
  }, "decrypt"));
543
546
  }
@@ -547,7 +550,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
547
550
  return _toArrayBuffer(_runCipher(function () {
548
551
  return _withSecretBytes(key, function (kb) {
549
552
  var d3 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter2);
550
- return Buffer.concat([d3.update(buf), d3.final()]);
553
+ return guard.secret.cipherFinish(d3, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CTR plaintext");
551
554
  });
552
555
  }, "decrypt"));
553
556
  }
@@ -874,7 +877,7 @@ SubtleCrypto.prototype.wrapKey = async function wrapKey(format, key, wrappingKey
874
877
  try {
875
878
  return _withSecretBytes(wrappingKey, function (wkBytes) {
876
879
  var c = nodeCrypto.createCipheriv("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
877
- return _toArrayBuffer(Buffer.concat([c.update(bytes), c.final()]));
880
+ return _toArrayBuffer(guard.secret.cipherFinish(c, bytes, WebCryptoError, "webcrypto/operation", "an AES-KW wrap intermediate"));
878
881
  });
879
882
  } catch (e) { throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW key wrap failed", e); }
880
883
  }
@@ -919,7 +922,7 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
919
922
  try {
920
923
  bytes = _withSecretBytes(unwrappingKey, function (kwBytes) {
921
924
  var d = nodeCrypto.createDecipheriv("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
922
- return Buffer.concat([d.update(wrapped), d.final()]);
925
+ return guard.secret.cipherFinish(d, wrapped, WebCryptoError, "webcrypto/operation", "the unwrapped key material");
923
926
  });
924
927
  } catch (e) { throw new WebCryptoError("webcrypto/operation", "unwrapKey: AES-KW key unwrap failed (integrity or length)", e); }
925
928
  } else {
package/lib/x509-sign.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * @module pki.x509
7
7
  * @nav Signing
8
8
  * @title Certificates
9
+ * @fullname X.509 certificates: parse, sign and inspect
9
10
  * @intro The X.509 certificate-issuance producing side. `pki.x509.sign` builds a `TBSCertificate`,
10
11
  * signs it, and emits a `Certificate` (RFC 5280 sec. 4) that `pki.schema.x509.parse`,
11
12
  * `pki.path.validate`, and OpenSSL all accept, self-signed or CA-signed, over any signature
@@ -52,6 +53,27 @@ var OID_SKI = O("subjectKeyIdentifier");
52
53
 
53
54
  // The recognized keys of the `extensions` spec object; an unknown key is a typo and throws at
54
55
  // config-time (a custom extension is passed as pre-encoded DER via the array form).
56
+ // The three caller-owned objects pki.x509.sign reads, each with its own door. A key nothing here
57
+ // names is a typo or a misplaced argument, and the failure it causes is invisible: the certificate
58
+ // builds, signs, and simply does not carry what was asked for. `spec.extension` (one letter short
59
+ // of `extensions`) emitted a certificate with NO extensions at all -- no basicConstraints on an
60
+ // intended CA, no keyUsage on an intended constrained leaf. `spec.issuer` is the other shape: the
61
+ // issuer is argument TWO, and nesting it in the spec left the certificate SELF-SIGNED with nothing
62
+ // to read as a failure.
63
+ //
64
+ // Every table is derived from what the function actually reads, not from the doc block, because a
65
+ // table naming a key nothing reads reopens the hole it was added to close.
66
+ var KNOWN_SPEC_KEYS = {
67
+ subject: 1, subjectPublicKey: 1, notBefore: 1, notAfter: 1, serialNumber: 1, extensions: 1,
68
+ };
69
+ // The issuer names itself in one of two FORMS, and the cert form wins unconditionally: when
70
+ // `issuer.cert` is present the builder takes the DN and the public key from it and never reads
71
+ // `name` or `publicKey`. A union accepted `{ key, cert, name: "Different CA", publicKey }` and
72
+ // signed under the certificate's identity while discarding the identity the caller wrote out.
73
+ var KNOWN_ISSUER_CERT_KEYS = { key: 1, cert: 1 };
74
+ var KNOWN_ISSUER_EXPLICIT_KEYS = { key: 1, name: 1, publicKey: 1 };
75
+ var KNOWN_SIGN_OPTS = { digestAlgorithm: 1, pem: 1, pss: 1 };
76
+
55
77
  var KNOWN_EXT_KEYS = {
56
78
  subjectKeyIdentifier: 1, authorityKeyIdentifier: 1, keyUsage: 1, keyUsageCritical: 1,
57
79
  extendedKeyUsage: 1, extendedKeyUsageCritical: 1, basicConstraints: 1, subjectAltName: 1,
@@ -281,6 +303,22 @@ function _sign(spec, issuer, opts) {
281
303
  opts = opts || {};
282
304
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("x509/bad-input", "the certificate spec must be an object");
283
305
  issuer = issuer || {};
306
+ // Before a single field is read, so a misspelling is a refusal rather than an omission carried
307
+ // into a signed certificate. The issuer message names its own argument because the mistake this
308
+ // catches most often is putting the issuer inside the spec, where it self-signed in silence.
309
+ guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "x509/bad-input", function (k) {
310
+ return "unknown certificate spec field " + JSON.stringify(k) +
311
+ (k === "issuer" ? "; the issuer is the SECOND argument to pki.x509.sign, not a spec field" : "") +
312
+ (k === "extension" ? "; the extensions spec field is `extensions`" : "");
313
+ });
314
+ var byCert = issuer.cert != null;
315
+ guard.identifier.assertKnownKeys(issuer, byCert ? KNOWN_ISSUER_CERT_KEYS : KNOWN_ISSUER_EXPLICIT_KEYS,
316
+ _err, "x509/bad-input", function (k) {
317
+ return "unknown issuer field " + JSON.stringify(k) + " for the " + (byCert
318
+ ? "certificate form; issuer.cert supplies the name and the public key, so they are not read here"
319
+ : "explicit form; the issuer takes { key, name, publicKey }, or { key, cert } to take both from a certificate");
320
+ });
321
+ guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "x509/bad-input", "pki.x509.sign has an unknown option ");
284
322
  if (issuer.key == null) throw _err("x509/bad-input", "a signing key (issuer.key, a PKCS#8 private key) is required");
285
323
 
286
324
  var spki = _reqDer(spec.subjectPublicKey, "spec.subjectPublicKey (the SPKI DER of the certified key)");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:4977fc76-9318-4187-883f-52d642638d7f",
5
+ "serialNumber": "urn:uuid:123ddb5e-05ea-4e65-9d7d-7a667c46e3a3",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-20T03:58:27.675Z",
8
+ "timestamp": "2026-08-20T20:31:47.390Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/pki@0.5.16",
22
+ "bom-ref": "@blamejs/pki@0.5.18",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.5.16",
25
+ "version": "0.5.18",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
29
- "purl": "pkg:npm/%40blamejs/pki@0.5.16",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.18",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/pki@0.5.16",
57
+ "ref": "@blamejs/pki@0.5.18",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]