@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/CHANGELOG.md +41 -1
- package/MIGRATING.md +31 -0
- package/README.md +2 -2
- package/lib/acme.js +269 -37
- package/lib/cmp-build.js +35 -1
- package/lib/cmp-verify.js +3 -8
- package/lib/crmf-sign.js +304 -1
- package/lib/guard-all.js +7 -2
- package/lib/guard-async.js +3 -1
- package/lib/guard-bytes.js +4 -2
- package/lib/guard-compress.js +3 -1
- package/lib/guard-crypto.js +4 -1
- package/lib/guard-der.js +4 -1
- package/lib/guard-encoding.js +3 -1
- package/lib/guard-header.js +4 -1
- package/lib/guard-identifier.js +4 -2
- package/lib/guard-intrinsic.js +7 -2
- package/lib/guard-json.js +4 -1
- package/lib/guard-limits.js +4 -1
- package/lib/guard-list.js +6 -2
- package/lib/guard-name.js +17 -7
- package/lib/guard-parsed.js +5 -2
- package/lib/guard-range.js +5 -2
- package/lib/guard-secret.js +3 -1
- package/lib/guard-text.js +3 -1
- package/lib/guard-time.js +5 -2
- package/lib/pki-build.js +29 -0
- package/lib/schema-pkix.js +136 -84
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
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
|
-
|
|
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
|
|
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
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
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
|
-
|
|
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
|
+
});
|
package/lib/guard-parsed.js
CHANGED
|
@@ -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
|
-
|
|
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
|
+
});
|
package/lib/guard-range.js
CHANGED
|
@@ -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
|
-
|
|
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
|
+
});
|
package/lib/guard-secret.js
CHANGED
|
@@ -138,4 +138,6 @@ function cipherFinish(transform, input, ErrorClass, code, label) {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|