@blamejs/pki 0.6.50 → 0.6.52
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 +52 -0
- package/README.md +1 -1
- package/index.js +8 -3
- package/lib/cmp-build.js +23 -2
- package/lib/cmp-session.js +352 -85
- package/lib/cmp-verify.js +434 -6
- package/lib/guard-name.js +59 -1
- package/lib/guard-parsed.js +17 -1
- package/lib/key.js +159 -0
- package/lib/oid.js +2 -0
- package/lib/path-validate.js +8 -0
- package/lib/schema-cmp.js +1 -1
- package/lib/schema-pkix.js +43 -3
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/guard-parsed.js
CHANGED
|
@@ -193,6 +193,22 @@ function isRecordedAsProduced(obj) {
|
|
|
193
193
|
return true;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* The bytes a recorded parse result came from, for a consumer that has to hand DER on to a verb taking
|
|
198
|
+
* bytes rather than a parsed object. A copy, so the caller cannot reach the recorded source.
|
|
199
|
+
*
|
|
200
|
+
* Null for anything not recorded, and for a result whose fields no longer match what the parse
|
|
201
|
+
* produced: the bytes are the truth, so handing them on for an object a caller has since edited would
|
|
202
|
+
* silently discard the edit and forward something the caller did not mean.
|
|
203
|
+
*
|
|
204
|
+
* @enforced-by behavioral -- an accessor has no rename-proof shape to detect; its contract is pinned by
|
|
205
|
+
* the vectors that drive it on an unrecorded object, a recorded one, and an edited one.
|
|
206
|
+
*/
|
|
207
|
+
function sourceOf(obj) {
|
|
208
|
+
if (!isRecordedAsProduced(obj)) return null;
|
|
209
|
+
return _bufferFrom(_weakGet(PROVENANCE, obj).source);
|
|
210
|
+
}
|
|
211
|
+
|
|
196
212
|
function _shapeOf(obj) {
|
|
197
213
|
var shape = _create(null);
|
|
198
214
|
var keys = _allNames(obj);
|
|
@@ -278,5 +294,5 @@ module.exports = _freezeExports({
|
|
|
278
294
|
fromTrustedSource: fromTrustedSource, recordingParser: recordingParser,
|
|
279
295
|
recordingWalker: recordingWalker,
|
|
280
296
|
isCert: certShape, isCrl: crlShape, isRecorded: isRecorded,
|
|
281
|
-
isRecordedAsProduced: isRecordedAsProduced,
|
|
297
|
+
isRecordedAsProduced: isRecordedAsProduced, sourceOf: sourceOf,
|
|
282
298
|
});
|
package/lib/key.js
CHANGED
|
@@ -340,6 +340,164 @@ async function publicFromPrivate(privateKey, opts) {
|
|
|
340
340
|
return opts.pem ? pkix.pemEncode(spki, "PUBLIC KEY", PemError) : spki;
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
/**
|
|
344
|
+
* @internal Whether a private key and a SubjectPublicKeyInfo are the two halves of one key pair, for a
|
|
345
|
+
* caller deciding whether a private key it was handed goes with a certificate it was handed.
|
|
346
|
+
*
|
|
347
|
+
* Deriving the public key and comparing does NOT answer this. A key structure states its own public
|
|
348
|
+
* half and the key engine reads what it is told: RFC 5958 sec. 2 gives a OneAsymmetricKey an optional
|
|
349
|
+
* `publicKey`, an EC key's RFC 5915 `ECPrivateKey` carries its own public point, and an RSA private
|
|
350
|
+
* key carries the modulus and public exponent outright. A structure whose private components were
|
|
351
|
+
* replaced while its stored public ones were left alone therefore derives to exactly the public key
|
|
352
|
+
* that was planted in it, and the comparison accepts a private key that cannot use the certificate.
|
|
353
|
+
*
|
|
354
|
+
* So the pair is proven by USING it, on whichever operation the key type can perform: a signature the
|
|
355
|
+
* public half verifies, a Diffie-Hellman agreement that reaches the same secret from both sides, or a
|
|
356
|
+
* key encapsulation the private half decapsulates to the same secret. Each fails for a key that merely
|
|
357
|
+
* claims the public half.
|
|
358
|
+
*
|
|
359
|
+
* What a true answer means is exactly that: the private key WORKS with this public key, on the
|
|
360
|
+
* operation its type performs. It is not a statement that every field of the private structure is
|
|
361
|
+
* internally consistent, which no operation reveals. A component the algorithm ignores, such as a bit
|
|
362
|
+
* an X25519 scalar clamps away or an ML-KEM implicit-rejection secret, is not exercised by a
|
|
363
|
+
* correspondence that succeeds, and does not stop the key from being usable with the certificate.
|
|
364
|
+
* A caller needing structural consistency has a different question, and this is not it.
|
|
365
|
+
*/
|
|
366
|
+
var _PAIR_DIGEST = Object.assign(Object.create(null), { rsa: "sha256", ec: "sha256" });
|
|
367
|
+
var _PAIR_AGREE = Object.assign(Object.create(null), { x25519: 1, x448: 1 });
|
|
368
|
+
var _PAIR_KEM = Object.assign(Object.create(null),
|
|
369
|
+
{ "ml-kem-512": 1, "ml-kem-768": 1, "ml-kem-1024": 1 });
|
|
370
|
+
/** @internal RFC 4055 sec. 1.2: ONE RSA key pair may be identified either by `rsaEncryption` or by
|
|
371
|
+
* `id-RSASSA-PSS`, and a delivered private key and the certificate that certifies it need not have
|
|
372
|
+
* chosen the same one. The key engine reports those two encodings as different types, so comparing
|
|
373
|
+
* types alone would call a usable pair no pair at all. They name one algorithm and are exercised
|
|
374
|
+
* together, under PSS, which is the padding the restricted encoding permits. */
|
|
375
|
+
var _PAIR_RSA = Object.assign(Object.create(null), { rsa: 1, "rsa-pss": 1 });
|
|
376
|
+
var _PAIR_PROBE = Buffer.from("pki.js key pair correspondence", "utf8");
|
|
377
|
+
|
|
378
|
+
function _sameKeyFamily(priv, pub) {
|
|
379
|
+
if (priv.asymmetricKeyType === pub.asymmetricKeyType) return true;
|
|
380
|
+
return !!(_PAIR_RSA[guard.text.keyOf(priv.asymmetricKeyType)] &&
|
|
381
|
+
_PAIR_RSA[guard.text.keyOf(pub.asymmetricKeyType)]);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** @internal How to exercise a signing pair: the digest, and any padding the encoding requires. An
|
|
385
|
+
* `id-RSASSA-PSS` key may pin the hash and salt length it is usable with, and the engine refuses any
|
|
386
|
+
* other, so a pinned value from either half is what proves the pair. */
|
|
387
|
+
function _pairSignOptions(priv, pub) {
|
|
388
|
+
var privPss = priv.asymmetricKeyType === "rsa-pss", pubPss = pub.asymmetricKeyType === "rsa-pss";
|
|
389
|
+
if (!privPss && !pubPss) {
|
|
390
|
+
return { digest: _PAIR_DIGEST[guard.text.keyOf(priv.asymmetricKeyType)] || null, options: null };
|
|
391
|
+
}
|
|
392
|
+
var privDetails = _pssRestrictionOf(priv, privPss);
|
|
393
|
+
var pubDetails = _pssRestrictionOf(pub, pubPss);
|
|
394
|
+
/** @internal A half that pins nothing constrains nothing, so only two halves that BOTH pin can
|
|
395
|
+
* disagree. Both encodings pinning incompatible parameters describes no operation this pair can
|
|
396
|
+
* perform together, which is not the same as being different keys: it is reported as unexercisable
|
|
397
|
+
* rather than as a false "not a pair". Where one pins and the other does not, the pinned half
|
|
398
|
+
* supplies the parameters below and the engine enforces it against its own key. */
|
|
399
|
+
if (_pssConflict(privDetails, pubDetails)) return null;
|
|
400
|
+
var digest = privDetails.hashAlgorithm || pubDetails.hashAlgorithm || "sha256";
|
|
401
|
+
/** @internal The engine derives MGF1 from the digest and takes no separate option for it, so a half
|
|
402
|
+
* that pins a mask generator other than its own hash names an operation this pair cannot perform
|
|
403
|
+
* together. That is the same "cannot be decided" verdict two conflicting halves get, not a false
|
|
404
|
+
* report that the halves are different keys. */
|
|
405
|
+
var mgf1 = privDetails.mgf1HashAlgorithm || pubDetails.mgf1HashAlgorithm;
|
|
406
|
+
if (mgf1 != null && mgf1 !== digest) return null;
|
|
407
|
+
var salt = _pssSalt(privDetails.saltLength, pubDetails.saltLength);
|
|
408
|
+
/** @internal Null-prototype, because the engine READS this object by name. A plain object would
|
|
409
|
+
* let an inherited `saltLength` reach the signature as a restriction neither half stated. */
|
|
410
|
+
var options = Object.create(null);
|
|
411
|
+
options.padding = nodeCrypto.constants.RSA_PKCS1_PSS_PADDING;
|
|
412
|
+
if (salt != null) options.saltLength = salt;
|
|
413
|
+
return { digest: digest, options: options };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
var _PSS_PINS = ["hashAlgorithm", "mgf1HashAlgorithm", "saltLength"];
|
|
417
|
+
|
|
418
|
+
/** @internal What a half pins, as a null-prototype record carrying only what the key itself states.
|
|
419
|
+
* A half pins nothing when it is not an id-RSASSA-PSS key at all, and equally when it is one whose
|
|
420
|
+
* parameters are absent, which RFC 4055 sec. 3.1 leaves optional. Reading either through a plain
|
|
421
|
+
* object would let an inherited `saltLength` or `hashAlgorithm` answer as a restriction the key never
|
|
422
|
+
* carried, and refuse a genuine pair. */
|
|
423
|
+
function _pssRestrictionOf(key, isPss) {
|
|
424
|
+
var out = Object.create(null);
|
|
425
|
+
var details = isPss ? key.asymmetricKeyDetails : null;
|
|
426
|
+
if (details == null) return out;
|
|
427
|
+
for (var i = 0; i < _PSS_PINS.length; i++) {
|
|
428
|
+
var name = _PSS_PINS[i];
|
|
429
|
+
if (Object.prototype.hasOwnProperty.call(details, name) && details[name] != null) out[name] = details[name];
|
|
430
|
+
}
|
|
431
|
+
return out;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** @internal Whether two halves state a restriction that cannot be satisfied at once. RFC 4055
|
|
435
|
+
* sec. 3.3 requires the signature's hash and mask generator to match the key's, so two halves naming
|
|
436
|
+
* different ones describe no shared operation. It treats the salt length differently: "The saltLength
|
|
437
|
+
* field in the signature parameters MUST be greater or equal to that in the key parameters field",
|
|
438
|
+
* and sec. 3.1 says the field "does not need to be fixed for a given RSA key pair". Two halves naming
|
|
439
|
+
* different salt lengths are therefore both satisfied by the larger, and do not conflict. A field
|
|
440
|
+
* only one half states constrains only that half, so it cannot disagree with anything. */
|
|
441
|
+
function _pssConflict(a, b) {
|
|
442
|
+
if (a.hashAlgorithm != null && b.hashAlgorithm != null && a.hashAlgorithm !== b.hashAlgorithm) return true;
|
|
443
|
+
if (a.mgf1HashAlgorithm != null && b.mgf1HashAlgorithm != null && a.mgf1HashAlgorithm !== b.mgf1HashAlgorithm) return true;
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** @internal The smallest salt length both halves accept, which is the larger of the two floors. */
|
|
448
|
+
function _pssSalt(a, b) {
|
|
449
|
+
if (a == null) return b;
|
|
450
|
+
if (b == null) return a;
|
|
451
|
+
return a > b ? a : b;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function correspondsTo(privateKey, spkiDer) {
|
|
455
|
+
var privDer = await _toPrivateKeyDer(privateKey);
|
|
456
|
+
var priv, pub;
|
|
457
|
+
try { priv = nodeCrypto.createPrivateKey({ key: privDer, format: "der", type: "pkcs8" }); }
|
|
458
|
+
catch (e) { throw _err("key/bad-input", "the private key could not be read", e); }
|
|
459
|
+
try { pub = nodeCrypto.createPublicKey({ key: Buffer.from(spkiDer), format: "der", type: "spki" }); }
|
|
460
|
+
catch (e) { throw _err("key/bad-input", "the public key could not be read", e); }
|
|
461
|
+
if (!_sameKeyFamily(priv, pub)) return false;
|
|
462
|
+
var kind = guard.text.keyOf(priv.asymmetricKeyType);
|
|
463
|
+
try {
|
|
464
|
+
if (_PAIR_KEM[kind]) {
|
|
465
|
+
var sealed = nodeCrypto.encapsulate(pub);
|
|
466
|
+
return guard.crypto.constantTimeEqual(nodeCrypto.decapsulate(priv, sealed.ciphertext), sealed.sharedKey);
|
|
467
|
+
}
|
|
468
|
+
if (_PAIR_AGREE[kind]) {
|
|
469
|
+
var ephemeral = nodeCrypto.generateKeyPairSync(priv.asymmetricKeyType);
|
|
470
|
+
if (!guard.crypto.constantTimeEqual(
|
|
471
|
+
nodeCrypto.diffieHellman({ privateKey: priv, publicKey: ephemeral.publicKey }),
|
|
472
|
+
nodeCrypto.diffieHellman({ privateKey: ephemeral.privateKey, publicKey: pub }))) return false;
|
|
473
|
+
/** @internal The agreement proves the SCALAR, not the encoding it was handed. RFC 7748 masks the
|
|
474
|
+
* top bit of an X25519 u-coordinate before the ladder, so a public value differing from the real
|
|
475
|
+
* one only in a masked bit reaches the same secret from both sides. The certificate would then
|
|
476
|
+
* carry bytes this key does not produce, and its subjectKeyIdentifier and any pinning of it
|
|
477
|
+
* would name a key the holder does not have. These types store no public copy in the private
|
|
478
|
+
* structure for an attacker to plant, so what the scalar generates IS the canonical answer and
|
|
479
|
+
* comparing against it adds a bound the agreement alone does not give. */
|
|
480
|
+
return guard.crypto.constantTimeEqual(
|
|
481
|
+
nodeCrypto.createPublicKey(priv).export({ format: "der", type: "spki" }),
|
|
482
|
+
pub.export({ format: "der", type: "spki" }));
|
|
483
|
+
}
|
|
484
|
+
var how = _pairSignOptions(priv, pub);
|
|
485
|
+
if (how === null) {
|
|
486
|
+
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");
|
|
487
|
+
}
|
|
488
|
+
var signKey = how.options ? Object.assign(Object.create(null), { key: priv }, how.options) : priv;
|
|
489
|
+
var verifyKey = how.options ? Object.assign(Object.create(null), { key: pub }, how.options) : pub;
|
|
490
|
+
return nodeCrypto.verify(how.digest, _PAIR_PROBE, verifyKey,
|
|
491
|
+
nodeCrypto.sign(how.digest, _PAIR_PROBE, signKey)) === true;
|
|
492
|
+
} catch (e) {
|
|
493
|
+
/** @internal The incompatible-parameters verdict is decided rather than caught, so it is passed
|
|
494
|
+
* through with the reason it was raised for. Rewrapping it would tell an operator the pair could
|
|
495
|
+
* not be exercised without saying that the two encodings pin conflicting parameters. */
|
|
496
|
+
if (e && e.code === "key/unsupported-algorithm" && e.isPkiError === true) throw e;
|
|
497
|
+
throw _err("key/unsupported-algorithm", "the key pair could not be exercised to decide whether its two halves correspond", e);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
343
501
|
|
|
344
502
|
function _detectKeyInput(input) {
|
|
345
503
|
var der = pkix.coerceToDer(input, { pemLabel: null, PemError: PemError, ErrorClass: KeyError, prefix: "key" });
|
|
@@ -397,4 +555,5 @@ module.exports = {
|
|
|
397
555
|
import: import_,
|
|
398
556
|
generate: generate,
|
|
399
557
|
publicFromPrivate: publicFromPrivate,
|
|
558
|
+
correspondsTo: correspondsTo, // @internal
|
|
400
559
|
};
|
package/lib/oid.js
CHANGED
|
@@ -174,6 +174,8 @@ var FAMILIES = Object.assign(Object.create(null), {
|
|
|
174
174
|
countersignature: 6, challengePassword: 7, extensionRequest: 14,
|
|
175
175
|
smimeCapabilities: 15, friendlyName: 20, localKeyId: 21 } },
|
|
176
176
|
|
|
177
|
+
keyPackageContentTypes: { base: [2, 16, 840, 1, 101, 2, 1, 2, 78], of: { aKeyPackage: 5 } },
|
|
178
|
+
|
|
177
179
|
pkcs9CertTypes: { base: [1, 2, 840, 113549, 1, 9, 22], of: { x509Certificate: 1, sdsiCertificate: 2 } },
|
|
178
180
|
pkcs9CrlTypes: { base: [1, 2, 840, 113549, 1, 9, 23], of: { x509CRL: 1 } },
|
|
179
181
|
|
package/lib/path-validate.js
CHANGED
|
@@ -486,8 +486,16 @@ function ipMatch(constraint, addr) {
|
|
|
486
486
|
return true;
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
+
/** @internal The one place a constraint base meets a name, so the base's form is read here and
|
|
490
|
+
* nowhere else. A caller's base met `guard.name.constraintBaseRefusal` at the door; a base a
|
|
491
|
+
* certificate carries in its own nameConstraints extension met no door, and the same rule decides it
|
|
492
|
+
* here. Answering a base outside its tag's form with no match rather than no verdict would make an
|
|
493
|
+
* excluded subtree that covers nothing exclude nothing. */
|
|
489
494
|
function nameMatchesConstraint(gnTag, gnValue, base) {
|
|
490
495
|
if (base.tagNumber !== gnTag) return null;
|
|
496
|
+
if (gnTag === 1 || gnTag === 2 || gnTag === 6) {
|
|
497
|
+
if (guard.name.constraintBaseUnreadable(gnTag, base.value)) return "unsupported";
|
|
498
|
+
}
|
|
491
499
|
switch (gnTag) {
|
|
492
500
|
case 1: return emailMatch(base.value, gnValue);
|
|
493
501
|
case 2: return hostConstraintMatch(base.value, gnValue);
|
package/lib/schema-cmp.js
CHANGED
|
@@ -359,7 +359,7 @@ var ENCRYPTED_KEY = schema.choice([
|
|
|
359
359
|
if (ct === null || ct.length === 0) {
|
|
360
360
|
throw ctx.E("cmp/bad-cert-response", "an EncryptedKey envelopedData must carry non-empty attached ciphertext -- its encryptedContent is the certificate/key payload (RFC 9810 sec. 5.2.2)");
|
|
361
361
|
}
|
|
362
|
-
return { envelopedData: env };
|
|
362
|
+
return { envelopedData: env, bytes: asn1.sequenceTlv(n) };
|
|
363
363
|
}) },
|
|
364
364
|
], { code: "cmp/bad-cert-response", what: "EncryptedKey" });
|
|
365
365
|
|
package/lib/schema-pkix.js
CHANGED
|
@@ -539,6 +539,44 @@ function keyUsageOf(ns, cert, E, code, label) {
|
|
|
539
539
|
return null;
|
|
540
540
|
}
|
|
541
541
|
|
|
542
|
+
/** @internal The extendedKeyUsage purposes a certificate asserts, or null when it carries no such
|
|
543
|
+
* extension. A malformed extension throws through the caller's ErrorClass; it never reads as an
|
|
544
|
+
* empty set. */
|
|
545
|
+
var _EKU_DECODER = new _WeakMapI();
|
|
546
|
+
function extKeyUsageOf(ns, cert, E, code, label) {
|
|
547
|
+
var exts = (cert && cert.extensions) || [];
|
|
548
|
+
var want = ns.oid.byName("extKeyUsage");
|
|
549
|
+
for (var i = 0; i < exts.length; i++) {
|
|
550
|
+
if (exts[i].oid !== want || exts[i].value == null) continue;
|
|
551
|
+
var dec = _weakGet(_EKU_DECODER, ns);
|
|
552
|
+
if (!dec) { dec = certExtensionDecoders(ns).byOid[want]; _weakSet(_EKU_DECODER, ns, dec); }
|
|
553
|
+
try { return dec(exts[i].value); }
|
|
554
|
+
catch (e) { throw E(code, "the " + label + " extendedKeyUsage extension is malformed", e); }
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* @internal Whether a certificate ASSERTS a key purpose, for a rule that requires the assertion to be
|
|
561
|
+
* present. RFC 5280 sec. 4.2.1.12 constrains a certificate only when the extension is there, so an
|
|
562
|
+
* absent extendedKeyUsage permits every purpose and satisfies `pki.path.validate`'s `requiredEku`. A
|
|
563
|
+
* profile that reads the purpose as an authorization statement (RFC 6960's id-kp-OCSPSigning
|
|
564
|
+
* responder, RFC 9483 sec. 4.1.6's id-kp-cmKGA key generation authority) needs the opposite reading:
|
|
565
|
+
* the certificate must say so. This returns false for an absent, empty, malformed, or
|
|
566
|
+
* differently-purposed extension, and true only when the named purpose is listed.
|
|
567
|
+
*
|
|
568
|
+
* @enforced-by behavioral -- an absent extension answering an authorization question has no
|
|
569
|
+
* rename-proof code shape; each consumer's RED conformance vector drives the shipped verb on a
|
|
570
|
+
* certificate with no extendedKeyUsage and asserts the refusal.
|
|
571
|
+
*/
|
|
572
|
+
function assertsPurpose(ns, cert, purposeOid) {
|
|
573
|
+
var purposes;
|
|
574
|
+
try { purposes = extKeyUsageOf(ns, cert, ns.E, ns.prefix + "/bad-extension-value", "certificate"); }
|
|
575
|
+
catch (_e) { return false; }
|
|
576
|
+
if (!purposes) return false;
|
|
577
|
+
return guard.list.contains(purposes, purposeOid);
|
|
578
|
+
}
|
|
579
|
+
|
|
542
580
|
function issuingDistributionPoint(code) {
|
|
543
581
|
return schema.seq([
|
|
544
582
|
schema.trailing([
|
|
@@ -676,7 +714,7 @@ function certExtensionDecoders(ns) {
|
|
|
676
714
|
for (var z = 0; z < bs.bytes.length; z++) { if (bs.bytes[z] !== 0) { anyBit = true; break; } }
|
|
677
715
|
if (!anyBit) throw ns.E(C, "KeyUsage must assert at least one bit (RFC 5280 sec. 4.2.1.3)");
|
|
678
716
|
schema.assertMinimalNamedBits(bs.unusedBits, bs.bytes, function (m) { throw ns.E(C, m); });
|
|
679
|
-
// allow:registry-table-inherits-object-prototype -- the decoded KeyUsage record, whose keys are the fixed KU_BITS names the schema declares
|
|
717
|
+
// allow:registry-table-inherits-object-prototype -- the decoded KeyUsage record, whose keys are the fixed KU_BITS names the schema declares; the certificate supplies none of them
|
|
680
718
|
var out = {};
|
|
681
719
|
_forEach(KU_BITS, function (nm, bit) {
|
|
682
720
|
var byte = bit >> 3, mask = 0x80 >> (bit & 7);
|
|
@@ -822,7 +860,7 @@ function certExtensionDecoders(ns) {
|
|
|
822
860
|
function authorityKeyIdentifier(buf) {
|
|
823
861
|
var C = ns.prefix + "/bad-extension-value";
|
|
824
862
|
var kids = seqChildren(buf, C, "AuthorityKeyIdentifier");
|
|
825
|
-
// allow:registry-table-inherits-object-prototype -- the decoded AuthorityKeyIdentifier record, read by the three field names the schema declares
|
|
863
|
+
// allow:registry-table-inherits-object-prototype -- the decoded AuthorityKeyIdentifier record, read by the three field names the schema declares; the certificate supplies none of them
|
|
826
864
|
var out = { keyIdentifier: null, authorityCertIssuer: null, authorityCertSerialNumber: null };
|
|
827
865
|
var lastTag = -1;
|
|
828
866
|
_forEach(kids, function (k) {
|
|
@@ -869,7 +907,7 @@ function certExtensionDecoders(ns) {
|
|
|
869
907
|
if (dp.tagClass !== "universal" || dp.tagNumber !== _T.SEQUENCE || !dp.children) {
|
|
870
908
|
throw ns.E(C, "DistributionPoint must be a SEQUENCE { distributionPoint?, reasons?, cRLIssuer? }");
|
|
871
909
|
}
|
|
872
|
-
// allow:registry-table-inherits-object-prototype -- the decoded DistributionPoint record, read by the three field names the schema declares
|
|
910
|
+
// allow:registry-table-inherits-object-prototype -- the decoded DistributionPoint record, read by the three field names the schema declares; the certificate supplies none of them
|
|
873
911
|
var out = { distributionPoint: null, reasons: null, cRLIssuer: null };
|
|
874
912
|
var lastTag = -1;
|
|
875
913
|
_forEach(dp.children, function (f) {
|
|
@@ -1247,6 +1285,8 @@ module.exports = {
|
|
|
1247
1285
|
distributionPointName: distributionPointName,
|
|
1248
1286
|
issuingDistributionPoint: issuingDistributionPoint,
|
|
1249
1287
|
keyUsageOf: keyUsageOf,
|
|
1288
|
+
extKeyUsageOf: extKeyUsageOf,
|
|
1289
|
+
assertsPurpose: assertsPurpose,
|
|
1250
1290
|
generalizedTime: generalizedTime,
|
|
1251
1291
|
utf8Text: utf8Text,
|
|
1252
1292
|
rawNonEmptySequence: rawNonEmptySequence,
|
package/package.json
CHANGED
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:
|
|
5
|
+
"serialNumber": "urn:uuid:5de9cc32-97b6-4f34-a868-7ad628091d11",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-07T15:01:14.383Z",
|
|
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.6.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.6.52",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.6.
|
|
25
|
+
"version": "0.6.52",
|
|
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.6.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.6.52",
|
|
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.6.
|
|
57
|
+
"ref": "@blamejs/pki@0.6.52",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|