@blamejs/pki 0.4.15 → 0.5.1

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 (60) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/MIGRATING.md +2 -2
  3. package/README.md +142 -137
  4. package/index.js +4 -0
  5. package/lib/acme.js +73 -1
  6. package/lib/asn1-der.js +2 -0
  7. package/lib/attrcert-sign.js +4 -0
  8. package/lib/cbor-det.js +32 -16
  9. package/lib/cmc-build.js +880 -0
  10. package/lib/cmc-verify.js +657 -0
  11. package/lib/cmp-build.js +8 -7
  12. package/lib/cmp-verify.js +11 -1
  13. package/lib/cms-sign.js +170 -8
  14. package/lib/cms-verify.js +80 -14
  15. package/lib/crl-sign.js +22 -0
  16. package/lib/crmf-sign.js +5 -2
  17. package/lib/csr-sign.js +3 -0
  18. package/lib/ct.js +72 -0
  19. package/lib/est.js +828 -32
  20. package/lib/framework-error.js +13 -0
  21. package/lib/guard-bytes.js +37 -1
  22. package/lib/guard-range.js +23 -1
  23. package/lib/http-transport.js +9 -3
  24. package/lib/inspect.js +28 -5
  25. package/lib/jose.js +64 -6
  26. package/lib/lint.js +4 -0
  27. package/lib/merkle.js +5 -5
  28. package/lib/ocsp.js +139 -11
  29. package/lib/oid.js +69 -1
  30. package/lib/path-validate.js +27 -4
  31. package/lib/pkcs12-build.js +12 -0
  32. package/lib/schema-all.js +19 -1
  33. package/lib/schema-attrcert.js +27 -0
  34. package/lib/schema-c509.js +6 -0
  35. package/lib/schema-cmc.js +791 -0
  36. package/lib/schema-cmp.js +25 -0
  37. package/lib/schema-cms.js +17 -1
  38. package/lib/schema-crl.js +23 -1
  39. package/lib/schema-crmf.js +13 -0
  40. package/lib/schema-csr.js +11 -0
  41. package/lib/schema-csrattrs.js +6 -0
  42. package/lib/schema-engine.js +6 -2
  43. package/lib/schema-ocsp.js +41 -0
  44. package/lib/schema-pkcs12.js +16 -0
  45. package/lib/schema-pkcs8.js +8 -0
  46. package/lib/schema-smime.js +4 -4
  47. package/lib/schema-tsp.js +32 -1
  48. package/lib/schema-x509.js +14 -1
  49. package/lib/shbs.js +12 -4
  50. package/lib/sigstore.js +62 -6
  51. package/lib/smime.js +28 -7
  52. package/lib/tls-cert-compress.js +15 -3
  53. package/lib/trust.js +27 -4
  54. package/lib/tsp-sign.js +41 -6
  55. package/lib/vendor/README.md +19 -19
  56. package/lib/webauthn.js +895 -26
  57. package/lib/webcrypto.js +35 -2
  58. package/lib/x509-sign.js +3 -0
  59. package/package.json +1 -1
  60. package/sbom.cdx.json +6 -6
package/lib/webcrypto.js CHANGED
@@ -1097,7 +1097,17 @@ SubtleCrypto.prototype.importKey = async function importKey(format, keyData, alg
1097
1097
  var a2 = (name === "HMAC") ? { name: name, hash: _hashObj(alg.hash, "importKey jwk HMAC"), length: kbuf.length * 8 } : { name: name, length: kbuf.length * 8 };
1098
1098
  return new CryptoKey("secret", extractable, a2, usages, s2);
1099
1099
  }
1100
- var isPrivate = Object.prototype.hasOwnProperty.call(jwk, "d");
1100
+ // The private half is named by the KEY TYPE, not by one spelling. EC and OKP carry it in `d`;
1101
+ // an AKP JWK -- how ML-DSA, ML-KEM and SLH-DSA are represented -- carries it in `priv`.
1102
+ // Testing `d` alone reads every PQC private JWK as public, so a re-import yields a public key
1103
+ // that still announces `usages: ["sign"]` and forces `extractable` true whatever the caller
1104
+ // asked, silently dropping the half that signs.
1105
+ // `priv` is read ONLY for an AKP key, the type that defines it. RFC 7517 sec. 4 requires an
1106
+ // unrecognized member to be ignored, so a member of that name on an EC or OKP JWK is an
1107
+ // extension this implementation has no meaning for -- reading it as private material there
1108
+ // would turn a valid public-key import into a failure.
1109
+ var isPrivate = Object.prototype.hasOwnProperty.call(jwk, "d") ||
1110
+ (jwk.kty === "AKP" && Object.prototype.hasOwnProperty.call(jwk, "priv"));
1101
1111
  var ko = _nodeKey(function () { return isPrivate ? nodeCrypto.createPrivateKey({ key: jwk, format: "jwk" }) : nodeCrypto.createPublicKey({ key: jwk, format: "jwk" }); }, "importKey jwk");
1102
1112
  return new CryptoKey(isPrivate ? "private" : "public", isPrivate ? extractable : true, _algFromImport(name, alg, ko), usages, ko);
1103
1113
  }
@@ -1187,6 +1197,17 @@ function _curveFromKey(ko) {
1187
1197
  * (either), or `raw` (symmetric, or an uncompressed EC / OKP public
1188
1198
  * point). Throws unless the key was created `extractable`.
1189
1199
  *
1200
+ * `raw` is defined for public and secret keys only -- asking for it on a private
1201
+ * key throws `webcrypto/not-supported` rather than answering with the public half.
1202
+ * This matters through `wrapKey`, which forwards the caller's format here: wrapping
1203
+ * a private key as `raw` would otherwise escrow the public key, and unwrapping it
1204
+ * returns a handle announcing `usages: ["sign"]` that cannot sign, with the private
1205
+ * key gone. Use `pkcs8` or `jwk` to serialize a private key.
1206
+ *
1207
+ * A private `jwk` round-trips as a private key for every algorithm, ML-DSA, ML-KEM
1208
+ * and SLH-DSA included: those are `kty: "AKP"` and carry the private half in `priv`
1209
+ * rather than the `d` an EC or OKP key uses.
1210
+ *
1190
1211
  * @example
1191
1212
  * var keyPair = await pki.webcrypto.subtle.generateKey({ name: "Ed25519" }, true, ["sign", "verify"]);
1192
1213
  * var spki = await pki.webcrypto.subtle.exportKey("spki", keyPair.publicKey);
@@ -1206,7 +1227,19 @@ SubtleCrypto.prototype.exportKey = async function exportKey(format, key) {
1206
1227
  }
1207
1228
  if (format === "spki") return _toArrayBuffer(key._handle.export({ format: "der", type: "spki" }));
1208
1229
  if (format === "pkcs8") return _toArrayBuffer(key._handle.export({ format: "der", type: "pkcs8" }));
1209
- if (format === "raw") return _toArrayBuffer(_rawPublic(key));
1230
+ if (format === "raw") {
1231
+ // "raw" is defined for PUBLIC and secret keys; there is no raw private-key serialization for
1232
+ // EC or OKP. Answering a private-key request with the public half hands back the opposite of
1233
+ // what was asked for, with nothing to notice it by -- and `wrapKey` forwards the caller's
1234
+ // format straight here, so a private key wrapped as "raw" escrows the PUBLIC key. Unwrapping
1235
+ // that yields a handle announcing it can sign, which cannot, and the private key is gone.
1236
+ if (key.type !== "public") {
1237
+ throw new WebCryptoError("webcrypto/not-supported",
1238
+ "exportKey: 'raw' is defined for public and secret keys only -- a " + key.type +
1239
+ " key has no raw serialization; use 'pkcs8' or 'jwk'");
1240
+ }
1241
+ return _toArrayBuffer(_rawPublic(key));
1242
+ }
1210
1243
  throw new WebCryptoError("webcrypto/not-supported", "exportKey: unsupported format " + JSON.stringify(format));
1211
1244
  };
1212
1245
 
package/lib/x509-sign.js CHANGED
@@ -254,6 +254,9 @@ function _hasCriticalSan(extSpec) {
254
254
  * - `pss` (boolean) -- sign an RSA key with RSASSA-PSS rather than PKCS#1 v1.5.
255
255
  * - `digestAlgorithm` (string) -- override the message digest where the algorithm permits a choice.
256
256
  * @example
257
+ * var pair = await pki.key.generate("Ed25519");
258
+ * var signerSpki = await pki.key.export(pair.publicKey);
259
+ * var signerKeyPkcs8 = await pki.key.export(pair.privateKey);
257
260
  * var root = await pki.x509.sign(
258
261
  * { subject: "Example Root CA", subjectPublicKey: signerSpki,
259
262
  * notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.4.15",
3
+ "version": "0.5.1",
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:7595bce4-18d5-4ef0-a2a1-6be18d59782d",
5
+ "serialNumber": "urn:uuid:350d591c-d7d9-431c-8902-3859e2fdad78",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-11T01:35:46.496Z",
8
+ "timestamp": "2026-08-12T22:09:02.062Z",
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.4.15",
22
+ "bom-ref": "@blamejs/pki@0.5.1",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.4.15",
25
+ "version": "0.5.1",
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.4.15",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.1",
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.4.15",
57
+ "ref": "@blamejs/pki@0.5.1",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]