@blamejs/pki 0.7.28 → 0.7.29

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 CHANGED
@@ -4,6 +4,14 @@ All notable changes to `@blamejs/pki` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this
5
5
  project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## v0.7.29 — 2026-09-12
8
+
9
+ Every decision pki.key makes is taken with operations bound when the module loads.
10
+
11
+ ### Changed
12
+
13
+ - pki.key.import, pki.key.generate, pki.key.decrypt, pki.key.encrypt, pki.key.export, pki.key.publicFromPrivate and the key-pair correspondence check read Array.isArray, Math.floor, isFinite, String, String.prototype.toUpperCase and String.prototype.indexOf, Buffer.from, Object.assign, Object.create and Object.prototype.hasOwnProperty as bound at module load. Replacing any of them afterwards changes nothing the module decides: a non-array usages is still refused, a fractional or infinite maxIterations is still refused, an Ed25519 import still receives signing usages, and an unrestricted RSASSA-PSS pair still corresponds when an inherited saltLength is planted on Object.prototype. Behavior on an untouched runtime is unchanged.
14
+
7
15
  ## v0.7.28 — 2026-09-12
8
16
 
9
17
  pki.cmp.verify names a MAC algorithm it does not compute as what it is, not as a failed signature.
package/lib/key.js CHANGED
@@ -29,6 +29,16 @@ var webcrypto = require("./webcrypto");
29
29
  var compositeKem = require("./composite-kem");
30
30
  var frameworkError = require("./framework-error");
31
31
  var guard = require("./guard-all");
32
+ var intrinsic = require("./guard-intrinsic");
33
+ var _assign = intrinsic.assign;
34
+ var _create = intrinsic.create;
35
+ var _isArray = intrinsic.isArray;
36
+ var _bufferFrom = intrinsic.bufferFrom;
37
+ var _floor = intrinsic.floor;
38
+ var _isFinite = intrinsic.isFinite;
39
+ var _String = intrinsic.String;
40
+ var _toUpperCase = intrinsic.toUpperCase;
41
+ var _strIndexOf = intrinsic.stringIndexOf;
32
42
 
33
43
  var b = asn1.build;
34
44
  var subtle = webcrypto.webcrypto.subtle;
@@ -37,16 +47,16 @@ var PemError = frameworkError.PemError;
37
47
  function O(n) { return oid.byName(n); }
38
48
  function _err(code, msg, cause) { return new KeyError(code, msg, cause); }
39
49
 
40
- var CIPHER_NAME = Object.assign(Object.create(null), { "aes-128-cbc": "aes128-CBC", "aes-192-cbc": "aes192-CBC", "aes-256-cbc": "aes256-CBC" });
50
+ var CIPHER_NAME = _assign(_create(null), { "aes-128-cbc": "aes128-CBC", "aes-192-cbc": "aes192-CBC", "aes-256-cbc": "aes256-CBC" });
41
51
 
42
- var INFER_ALG = Object.create(null);
52
+ var INFER_ALG = _create(null);
43
53
  ["Ed25519", "Ed448", "X25519", "X448"].forEach(function (n) { INFER_ALG[O(n)] = { name: n }; });
44
54
  [["id-ml-dsa-44", "ML-DSA-44"], ["id-ml-dsa-65", "ML-DSA-65"], ["id-ml-dsa-87", "ML-DSA-87"],
45
55
  ["id-ml-kem-512", "ML-KEM-512"], ["id-ml-kem-768", "ML-KEM-768"], ["id-ml-kem-1024", "ML-KEM-1024"]
46
56
  ].forEach(function (r) { INFER_ALG[O(r[0])] = { name: r[1] }; });
47
57
  ["sha2-128s", "sha2-128f", "sha2-192s", "sha2-192f", "sha2-256s", "sha2-256f",
48
58
  "shake-128s", "shake-128f", "shake-192s", "shake-192f", "shake-256s", "shake-256f"
49
- ].forEach(function (s) { INFER_ALG[O("id-slh-dsa-" + s)] = { name: ("SLH-DSA-" + s).toUpperCase() }; });
59
+ ].forEach(function (s) { INFER_ALG[O("id-slh-dsa-" + s)] = { name: _toUpperCase("SLH-DSA-" + s) }; });
50
60
 
51
61
  function _isCryptoKey(x) { return webcrypto.isCryptoKeyLike(x); }
52
62
  function _algName(a) { return typeof a === "string" ? a : (a && a.name); }
@@ -89,7 +99,7 @@ async function _toPrivateKeyDer(input) {
89
99
  * var enc = await pki.key.encrypt(der, "s3cr3t", { pem: true });
90
100
  * var back = await pki.key.decrypt(enc, "s3cr3t");
91
101
  */
92
- var _ENCRYPT_OPTS = Object.assign(Object.create(null), { cipher: 1, iterations: 1, pem: 1, prf: 1, salt: 1 });
102
+ var _ENCRYPT_OPTS = _assign(_create(null), { cipher: 1, iterations: 1, pem: 1, prf: 1, salt: 1 });
93
103
 
94
104
  async function encrypt(privateKey, password, opts) {
95
105
  opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.encrypt options");
@@ -148,14 +158,14 @@ async function encrypt(privateKey, password, opts) {
148
158
  * var enc = await pki.key.encrypt(await pki.key.export(pair.privateKey), "s3cr3t", { pem: true });
149
159
  * var der = await pki.key.decrypt(enc, "s3cr3t");
150
160
  */
151
- var _DECRYPT_OPTS = Object.assign(Object.create(null), { maxIterations: 1, pem: 1 });
161
+ var _DECRYPT_OPTS = _assign(_create(null), { maxIterations: 1, pem: 1 });
152
162
 
153
163
  async function decrypt(encrypted, password, opts) {
154
164
  opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.decrypt options");
155
165
  guard.identifier.assertKnownKeys(opts, _DECRYPT_OPTS, _err, "key/bad-input",
156
166
  "pki.key.decrypt has an unknown option (the PBKDF2 cap here is `maxIterations`; " +
157
167
  "`iterations` is the encrypt-side count): ");
158
- if (opts.maxIterations != null && (typeof opts.maxIterations !== "number" || !isFinite(opts.maxIterations) || opts.maxIterations < 1 || Math.floor(opts.maxIterations) !== opts.maxIterations)) {
168
+ if (opts.maxIterations != null && (typeof opts.maxIterations !== "number" || !_isFinite(opts.maxIterations) || opts.maxIterations < 1 || _floor(opts.maxIterations) !== opts.maxIterations)) {
159
169
  throw _err("key/bad-input", "maxIterations must be a positive integer");
160
170
  }
161
171
  var input = pkix.coerceToDer(encrypted, { pemLabel: "ENCRYPTED PRIVATE KEY", PemError: PemError, ErrorClass: KeyError, prefix: "key" });
@@ -204,7 +214,7 @@ function _decryptPbes2(encAlg, ciphertext, password, opts) {
204
214
  * var pair = await pki.key.generate("Ed25519");
205
215
  * var spkiPem = await pki.key.export(pair.publicKey, { format: "pem" });
206
216
  */
207
- var _EXPORT_OPTS = Object.assign(Object.create(null), { format: 1, label: 1 });
217
+ var _EXPORT_OPTS = _assign(_create(null), { format: 1, label: 1 });
208
218
 
209
219
  async function export_(key, opts) {
210
220
  opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.export options");
@@ -247,7 +257,7 @@ async function export_(key, opts) {
247
257
  * var spki = await pki.key.export(pair.publicKey);
248
258
  * var pub = await pki.key.import(spki); // Ed25519 -- algorithm inferred
249
259
  */
250
- var _IMPORT_OPTS = Object.assign(Object.create(null), { algorithm: 1, extractable: 1, password: 1, usages: 1 });
260
+ var _IMPORT_OPTS = _assign(_create(null), { algorithm: 1, extractable: 1, password: 1, usages: 1 });
251
261
 
252
262
  async function import_(input, opts) {
253
263
  opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.import options");
@@ -260,7 +270,7 @@ async function import_(input, opts) {
260
270
  }
261
271
  var algorithm = opts.algorithm != null ? opts.algorithm : _inferAlgorithm(detected);
262
272
  var isPublic = detected.format === "spki";
263
- if (opts.usages != null && !Array.isArray(opts.usages)) throw _err("key/bad-input", "opts.usages must be an array of key-usage strings");
273
+ if (opts.usages != null && !_isArray(opts.usages)) throw _err("key/bad-input", "opts.usages must be an array of key-usage strings");
264
274
  var usages = opts.usages || _importUsages(_algName(algorithm), isPublic);
265
275
  var extractable = opts.extractable != null ? opts.extractable : false;
266
276
  try {
@@ -291,14 +301,14 @@ async function import_(input, opts) {
291
301
  * var pair = await pki.key.generate("Ed25519");
292
302
  * var pkcs8 = await pki.key.export(pair.privateKey);
293
303
  */
294
- var _GENERATE_OPTS = Object.assign(Object.create(null), { extractable: 1, usages: 1 });
304
+ var _GENERATE_OPTS = _assign(_create(null), { extractable: 1, usages: 1 });
295
305
 
296
306
  async function generate(algorithm, opts) {
297
307
  opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.generate options");
298
308
  guard.identifier.assertKnownKeys(opts, _GENERATE_OPTS, _err, "key/bad-input",
299
309
  "pki.key.generate has an unknown option (the WebCrypto spelling is `extractable`): ");
300
310
  var extractable = opts.extractable != null ? opts.extractable : true;
301
- if (opts.usages != null && !Array.isArray(opts.usages)) throw _err("key/bad-input", "opts.usages must be an array of key-usage strings");
311
+ if (opts.usages != null && !_isArray(opts.usages)) throw _err("key/bad-input", "opts.usages must be an array of key-usage strings");
302
312
  var usages = opts.usages || _generateUsages(_algName(algorithm));
303
313
  var pair;
304
314
  try { pair = await subtle.generateKey(algorithm, extractable, usages); }
@@ -333,7 +343,7 @@ async function generate(algorithm, opts) {
333
343
  * var pair = await pki.key.generate("Ed25519");
334
344
  * var spki = await pki.key.publicFromPrivate(await pki.key.export(pair.privateKey));
335
345
  */
336
- var _PUBLIC_FROM_PRIVATE_OPTS = Object.assign(Object.create(null), { pem: 1 });
346
+ var _PUBLIC_FROM_PRIVATE_OPTS = _assign(_create(null), { pem: 1 });
337
347
 
338
348
  /** @internal The composite ML-KEM OID a private key names, or null when it names anything else. Read
339
349
  * from the AlgorithmIdentifier alone: a key that is not well formed enough to state one is left to the
@@ -399,17 +409,17 @@ async function publicFromPrivate(privateKey, opts) {
399
409
  * correspondence that succeeds, and does not stop the key from being usable with the certificate.
400
410
  * A caller needing structural consistency has a different question, and this is not it.
401
411
  */
402
- var _PAIR_DIGEST = Object.assign(Object.create(null), { rsa: "sha256", ec: "sha256" });
403
- var _PAIR_AGREE = Object.assign(Object.create(null), { x25519: 1, x448: 1 });
404
- var _PAIR_KEM = Object.assign(Object.create(null),
412
+ var _PAIR_DIGEST = _assign(_create(null), { rsa: "sha256", ec: "sha256" });
413
+ var _PAIR_AGREE = _assign(_create(null), { x25519: 1, x448: 1 });
414
+ var _PAIR_KEM = _assign(_create(null),
405
415
  { "ml-kem-512": 1, "ml-kem-768": 1, "ml-kem-1024": 1 });
406
416
  /** @internal RFC 4055 sec. 1.2: ONE RSA key pair may be identified either by `rsaEncryption` or by
407
417
  * `id-RSASSA-PSS`, and a delivered private key and the certificate that certifies it need not have
408
418
  * chosen the same one. The key engine reports those two encodings as different types, so comparing
409
419
  * types alone would call a usable pair no pair at all. They name one algorithm and are exercised
410
420
  * together, under PSS, which is the padding the restricted encoding permits. */
411
- var _PAIR_RSA = Object.assign(Object.create(null), { rsa: 1, "rsa-pss": 1 });
412
- var _PAIR_PROBE = Buffer.from("pki.js key pair correspondence", "utf8");
421
+ var _PAIR_RSA = _assign(_create(null), { rsa: 1, "rsa-pss": 1 });
422
+ var _PAIR_PROBE = _bufferFrom("pki.js key pair correspondence", "utf8");
413
423
 
414
424
  function _sameKeyFamily(priv, pub) {
415
425
  if (priv.asymmetricKeyType === pub.asymmetricKeyType) return true;
@@ -443,7 +453,7 @@ function _pairSignOptions(priv, pub) {
443
453
  var salt = _pssSalt(privDetails.saltLength, pubDetails.saltLength);
444
454
  /** @internal Null-prototype, because the engine READS this object by name. A plain object would
445
455
  * let an inherited `saltLength` reach the signature as a restriction neither half stated. */
446
- var options = Object.create(null);
456
+ var options = _create(null);
447
457
  options.padding = nodeCrypto.constants.RSA_PKCS1_PSS_PADDING;
448
458
  if (salt != null) options.saltLength = salt;
449
459
  return { digest: digest, options: options };
@@ -457,12 +467,12 @@ var _PSS_PINS = ["hashAlgorithm", "mgf1HashAlgorithm", "saltLength"];
457
467
  * object would let an inherited `saltLength` or `hashAlgorithm` answer as a restriction the key never
458
468
  * carried, and refuse a genuine pair. */
459
469
  function _pssRestrictionOf(key, isPss) {
460
- var out = Object.create(null);
470
+ var out = _create(null);
461
471
  var details = isPss ? key.asymmetricKeyDetails : null;
462
472
  if (details == null) return out;
463
473
  for (var i = 0; i < _PSS_PINS.length; i++) {
464
474
  var name = _PSS_PINS[i];
465
- if (Object.prototype.hasOwnProperty.call(details, name) && details[name] != null) out[name] = details[name];
475
+ if (intrinsic.hasOwn(details, name) && details[name] != null) out[name] = details[name];
466
476
  }
467
477
  return out;
468
478
  }
@@ -492,7 +502,7 @@ async function correspondsTo(privateKey, spkiDer) {
492
502
  var priv, pub;
493
503
  try { priv = nodeCrypto.createPrivateKey({ key: privDer, format: "der", type: "pkcs8" }); }
494
504
  catch (e) { throw _err("key/bad-input", "the private key could not be read", e); }
495
- try { pub = nodeCrypto.createPublicKey({ key: Buffer.from(spkiDer), format: "der", type: "spki" }); }
505
+ try { pub = nodeCrypto.createPublicKey({ key: _bufferFrom(spkiDer), format: "der", type: "spki" }); }
496
506
  catch (e) { throw _err("key/bad-input", "the public key could not be read", e); }
497
507
  if (!_sameKeyFamily(priv, pub)) return false;
498
508
  var kind = guard.text.keyOf(priv.asymmetricKeyType);
@@ -521,8 +531,8 @@ async function correspondsTo(privateKey, spkiDer) {
521
531
  if (how === null) {
522
532
  throw _err("key/unsupported-algorithm", "the two halves pin incompatible RSASSA-PSS parameters, so no operation exercises them together and whether they are a pair cannot be decided");
523
533
  }
524
- var signKey = how.options ? Object.assign(Object.create(null), { key: priv }, how.options) : priv;
525
- var verifyKey = how.options ? Object.assign(Object.create(null), { key: pub }, how.options) : pub;
534
+ var signKey = how.options ? _assign(_create(null), { key: priv }, how.options) : priv;
535
+ var verifyKey = how.options ? _assign(_create(null), { key: pub }, how.options) : pub;
526
536
  return nodeCrypto.verify(how.digest, _PAIR_PROBE, verifyKey,
527
537
  nodeCrypto.sign(how.digest, _PAIR_PROBE, signKey)) === true;
528
538
  } catch (e) {
@@ -569,17 +579,17 @@ function _inferAlgorithm(detected) {
569
579
  }
570
580
 
571
581
  function _importUsages(name, isPublic) {
572
- var n = String(name == null ? "" : name).toUpperCase();
582
+ var n = _toUpperCase(_String(name == null ? "" : name));
573
583
  if (n === "X25519" || n === "X448" || n === "ECDH") return isPublic ? [] : ["deriveBits", "deriveKey"];
574
- if (n.indexOf("ML-KEM") === 0) return isPublic ? ["encapsulateBits"] : ["decapsulateBits"];
584
+ if (_strIndexOf(n, "ML-KEM") === 0) return isPublic ? ["encapsulateBits"] : ["decapsulateBits"];
575
585
  if (n === "RSA-OAEP") return isPublic ? ["encrypt"] : ["decrypt"];
576
586
  return isPublic ? ["verify"] : ["sign"];
577
587
  }
578
588
 
579
589
  function _generateUsages(name) {
580
- var n = String(name == null ? "" : name).toUpperCase();
590
+ var n = _toUpperCase(_String(name == null ? "" : name));
581
591
  if (n === "X25519" || n === "X448" || n === "ECDH") return ["deriveBits", "deriveKey"];
582
- if (n.indexOf("ML-KEM") === 0) return ["encapsulateBits", "decapsulateBits"];
592
+ if (_strIndexOf(n, "ML-KEM") === 0) return ["encapsulateBits", "decapsulateBits"];
583
593
  if (n === "RSA-OAEP") return ["encrypt", "decrypt"];
584
594
  return ["sign", "verify"];
585
595
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.7.28",
3
+ "version": "0.7.29",
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",
@@ -84,6 +84,6 @@
84
84
  "devDependencies": {
85
85
  "c8": "12.0.0",
86
86
  "esbuild": "0.28.2",
87
- "eslint": "10.9.1"
87
+ "eslint": "10.10.0"
88
88
  }
89
89
  }
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:369c5f21-643b-4e6e-9bbe-caa64491393d",
5
+ "serialNumber": "urn:uuid:3c9a8588-ff6f-477c-92fd-33c03ea2c98b",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-12T04:58:41.118Z",
8
+ "timestamp": "2026-09-12T05:32:15.338Z",
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.7.28",
22
+ "bom-ref": "@blamejs/pki@0.7.29",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.7.28",
25
+ "version": "0.7.29",
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.7.28",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.7.29",
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.7.28",
57
+ "ref": "@blamejs/pki@0.7.29",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]