@blamejs/pki 0.5.23 → 0.5.25

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/lib/guard-list.js CHANGED
@@ -28,6 +28,8 @@
28
28
  // over `===` has nothing to replace, so it holds whatever the prototype says, in a module that has
29
29
  // been swept and in one that has not.
30
30
 
31
+ var _freeze = require("./guard-intrinsic").freeze;
32
+
31
33
  // contains(list, value) -> boolean. Strict-equality membership, the `indexOf(v) !== -1` rule.
32
34
  // A null / undefined list is honestly empty, never a throw: these run on verdict paths.
33
35
  // @enforced-by behavioral -- `.indexOf(x) !== -1` has no rename-proof form that separates a
@@ -77,9 +79,11 @@ function allMatch(list, predicate) {
77
79
  return true;
78
80
  }
79
81
 
80
- module.exports = {
82
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
83
+ // call, so a writable export would let a caller replace the check rather than pass it.
84
+ module.exports = _freeze({
81
85
  contains: contains,
82
86
  containsAll: containsAll,
83
87
  anyMatches: anyMatches,
84
88
  allMatch: allMatch,
85
- };
89
+ });
package/lib/guard-name.js CHANGED
@@ -273,7 +273,7 @@ function emailEqual(a, b) {
273
273
  var aHost = _strSlice(a, ai + 1), bHost = _strSlice(b, bi + 1);
274
274
  if (!_asciiHost(aHost) || !_asciiHost(bHost)) return "not-comparable";
275
275
  if (aLocal !== bLocal) return "no-match";
276
- return _lowerAscii(aHost) === _lowerAscii(bHost) ? "match" : "no-match";
276
+ return lowerAscii(aHost) === lowerAscii(bHost) ? "match" : "no-match";
277
277
  }
278
278
 
279
279
  // A host-part this comparison can decide: ASCII, and carrying no A-label. Anything else
@@ -292,11 +292,18 @@ function _asciiHost(h) {
292
292
  return true;
293
293
  }
294
294
 
295
+ // lowerAscii(s) -> string
295
296
  // ASCII-only lowercase. String.toLowerCase() is Unicode-aware and would fold characters
296
- // outside ASCII (the Kelvin sign lowercases to "k"), which is precisely the mapping the
297
- // host-part rule does not authorize; _asciiHost has already excluded those inputs, so this
298
- // stays a plain A-Z shift rather than inheriting a locale-sensitive transform.
299
- function _lowerAscii(s) {
297
+ // outside ASCII (the Kelvin sign lowercases to "k"), which is precisely the mapping a
298
+ // name comparison does not authorize: a name folded that way is one the certificate or
299
+ // message does not carry, and comparing it equal to a name that was asked for is the
300
+ // defect. Every case-insensitive name comparison in the toolkit -- a host part, a CMP
301
+ // domain, an ACME identifier set -- folds through this one definition, so none of them can
302
+ // disagree about which characters case-fold.
303
+ //
304
+ // @enforced-by guard-shape-reinlined
305
+ // @guard-shape 0x41\s*&&\s*[A-Za-z_$][\w$]*\s*<=\s*0x5[aA]\s*\)\s*\?[^:]*\+\s*(?:32|0x20)\s*\)
306
+ function lowerAscii(s) {
300
307
  var out = "";
301
308
  for (var i = 0; i < s.length; i++) {
302
309
  var c = _charCodeAt(s, i);
@@ -305,8 +312,11 @@ function _lowerAscii(s) {
305
312
  return out;
306
313
  }
307
314
 
308
- module.exports = {
315
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
316
+ // call, so a writable export would let a caller replace the check rather than pass it.
317
+ module.exports = intrinsic.freeze({
309
318
  assertNoControlBytes: assertNoControlBytes, assertPrintableIa5: assertPrintableIa5,
310
319
  dnEqual: dnEqual, rdnEqual: rdnEqual, emailEqual: emailEqual,
311
320
  escapeControlBytes: escapeControlBytes, escapeDnValue: escapeDnValue,
312
- };
321
+ lowerAscii: lowerAscii,
322
+ });
@@ -44,6 +44,7 @@ var time = require("./guard-time");
44
44
  // one answering `false` makes each of those checks reject a well-formed parsed structure -- the
45
45
  // fail-closed direction, and still a caller deciding what this guard recognizes.
46
46
  var _isArray = require("./guard-intrinsic").isArray;
47
+ var _freezeExports = require("./guard-intrinsic").freeze;
47
48
  // The copy that becomes the recorded provenance bytes. A replacement returning a buffer over the
48
49
  // caller's own memory would let those bytes change after they were recorded, which is the one
49
50
  // thing provenance exists to prevent.
@@ -598,10 +599,12 @@ function acceptDerived(input, kind, parse, E, code, label) {
598
599
  ".parse result: " + _WHY[kind]);
599
600
  }
600
601
 
601
- module.exports = {
602
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
603
+ // call, so a writable export would let a caller replace the check rather than pass it.
604
+ module.exports = _freezeExports({
602
605
  accept: accept, acceptDerived: acceptDerived,
603
606
  fromTrustedSource: fromTrustedSource, recordingParser: recordingParser,
604
607
  recordingWalker: recordingWalker,
605
608
  isCert: certShape, isCrl: crlShape, isRecorded: isRecorded,
606
609
  isRecordedAsProduced: isRecordedAsProduced,
607
- };
610
+ });
@@ -25,6 +25,7 @@
25
25
  // Number at all, so one answering true for an unsafe magnitude reopens the precision loss this
26
26
  // guard exists to prevent. See guard-intrinsic for the whole captured set.
27
27
  var _isSafeInteger = require("./guard-intrinsic").isSafeInteger;
28
+ var _freeze = require("./guard-intrinsic").freeze;
28
29
  // The narrow itself. This module exists to turn a bounded BigInt into a Number without losing the
29
30
  // bound, and `Number` is a writable property of globalThis, so a replacement returns whatever it
30
31
  // likes from a value this function has just certified as in range.
@@ -131,7 +132,9 @@ function authoredInteger(value, E, code, label) {
131
132
  throw E(code, label + " must be an integer (a safe-integer number, or a bigint for a large value)");
132
133
  }
133
134
 
134
- module.exports = {
135
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
136
+ // call, so a writable export would let a caller replace the check rather than pass it.
137
+ module.exports = _freeze({
135
138
  int: int, uint31: uint31, positiveInt31: positiveInt31, uint64: uint64,
136
139
  authoredInteger: authoredInteger,
137
- };
140
+ });
@@ -138,4 +138,6 @@ function cipherFinish(transform, input, ErrorClass, code, label) {
138
138
  }
139
139
  }
140
140
 
141
- module.exports = { zeroize: zeroize, zeroizeAll: zeroizeAll, cipherFinish: cipherFinish };
141
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
142
+ // call, so a writable export would let a caller replace the check rather than pass it.
143
+ module.exports = intrinsic.freeze({ zeroize: zeroize, zeroizeAll: zeroizeAll, cipherFinish: cipherFinish });
package/lib/guard-text.js CHANGED
@@ -99,4 +99,6 @@ function decode(input, maxBytes, ErrorClass, spec) {
99
99
  throw new ErrorClass(spec.badInput, spec.label + " expects a string or Buffer");
100
100
  }
101
101
 
102
- module.exports = { decode: decode };
102
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
103
+ // call, so a writable export would let a caller replace the check rather than pass it.
104
+ module.exports = intrinsic.freeze({ decode: decode });
package/lib/guard-time.js CHANGED
@@ -32,6 +32,7 @@
32
32
  // the global `isNaN` is writable, and one returning false makes an invalid Date pass the check
33
33
  // below, which is the fail-open direction.
34
34
  var util = { types: require("./guard-intrinsic").types };
35
+ var _freeze = require("./guard-intrinsic").freeze;
35
36
  var _isNaN = Number.isNaN;
36
37
 
37
38
  // assertValid(value, E, code, label) -> the same Date, once proven valid.
@@ -130,9 +131,11 @@ function isDate(value) {
130
131
  return util.types.isDate(value);
131
132
  }
132
133
 
133
- module.exports = {
134
+ // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
135
+ // call, so a writable export would let a caller replace the check rather than pass it.
136
+ module.exports = _freeze({
134
137
  assertValid: assertValid,
135
138
  instantOf: instantOf,
136
139
  isDate: isDate,
137
140
  within: within,
138
- };
141
+ });
package/lib/pki-build.js CHANGED
@@ -18,9 +18,16 @@ var intrinsic = require("./guard-intrinsic");
18
18
  // Each of these doors refuses a caller argument that is not a list. Read live, a replacement
19
19
  // answering true lets a non-list through the check written to stop it.
20
20
  var _isArray = intrinsic.isArray;
21
+ // Taken at load for the reason every capture here is: the question "do these two encodings name the
22
+ // same key" decides whether a proof of possession is accepted, and a caller who replaces the copy or
23
+ // the comparison afterwards decides it instead.
24
+ var _bufferFrom = intrinsic.bufferFrom;
25
+ var _bufferEquals = intrinsic.bufferEquals;
21
26
  var oid = require("./oid");
22
27
  var ipUtils = require("./ip-utils");
23
28
  var nodeCrypto = require("crypto");
29
+ // The key-material comparison, taken at load like every other operation a decision here rests on.
30
+ var _keyEquals = intrinsic.uncurry(nodeCrypto.KeyObject.prototype.equals);
24
31
 
25
32
  var b = asn1.build;
26
33
 
@@ -402,6 +409,27 @@ function makeBuilder(ctx) {
402
409
  if (!ok) throw E("bad-input", "the signing key does not correspond to the public key -- the signature would not verify");
403
410
  }
404
411
 
412
+ // Do two SubjectPublicKeyInfo encodings name the same key? Bytes first, because that is the answer
413
+ // almost always and it costs nothing. When they differ the question is still open, since one key has
414
+ // more than one legal SPKI: an EC point may be carried compressed or uncompressed, so a P-256 key
415
+ // written the compressed way is byte-unequal to the same key written the other. Comparing the DER
416
+ // alone would refuse a proof of possession over a key the requester genuinely holds, while the
417
+ // sibling arms of the same verb accept that template. The fallback asks the key layer, which
418
+ // compares key material and still answers false for a different key, a different curve, or a
419
+ // different algorithm. A key neither side can import is equal to nothing, so the refusal stands.
420
+ function samePublicKey(spkiA, spkiB) {
421
+ var a = _bufferFrom(spkiA), bb = _bufferFrom(spkiB);
422
+ if (_bufferEquals(a, bb)) return true;
423
+ var ka, kb;
424
+ // allow:swallow-unverified an SPKI the key layer cannot import matches nothing, which is the
425
+ // refusal the caller wants; the caller raises its own typed error on the false.
426
+ try {
427
+ ka = nodeCrypto.createPublicKey({ key: a, format: "der", type: "spki" });
428
+ kb = nodeCrypto.createPublicKey({ key: bb, format: "der", type: "spki" });
429
+ } catch (_e) { return false; }
430
+ return _keyEquals(ka, kb) === true;
431
+ }
432
+
405
433
  return {
406
434
  E: E, code: code, KU_BIT: KU_BIT,
407
435
  encodeName: encodeName, isEmptyName: isEmptyName, encodeGeneralName: encodeGeneralName,
@@ -413,6 +441,7 @@ function makeBuilder(ctx) {
413
441
  spkiKeyId: spkiKeyId, skiKeyId: skiKeyId,
414
442
  reqDer: reqDer, assertValidSpki: assertValidSpki, assertValidExtension: assertValidExtension,
415
443
  certLikeFromSpki: certLikeFromSpki, assertSignatureVerifies: assertSignatureVerifies,
444
+ samePublicKey: samePublicKey,
416
445
  };
417
446
  }
418
447