@blamejs/pki 0.4.15 → 0.5.0
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 +37 -1
- package/MIGRATING.md +2 -2
- package/README.md +142 -137
- package/index.js +4 -0
- package/lib/acme.js +73 -1
- package/lib/asn1-der.js +2 -0
- package/lib/attrcert-sign.js +4 -0
- package/lib/cbor-det.js +32 -16
- package/lib/cmc-build.js +880 -0
- package/lib/cmc-verify.js +657 -0
- package/lib/cmp-build.js +8 -7
- package/lib/cmp-verify.js +11 -1
- package/lib/cms-sign.js +170 -8
- package/lib/cms-verify.js +80 -14
- package/lib/crl-sign.js +22 -0
- package/lib/crmf-sign.js +5 -2
- package/lib/csr-sign.js +3 -0
- package/lib/ct.js +72 -0
- package/lib/est.js +828 -32
- package/lib/framework-error.js +13 -0
- package/lib/guard-bytes.js +37 -1
- package/lib/guard-range.js +23 -1
- package/lib/http-transport.js +9 -3
- package/lib/inspect.js +28 -5
- package/lib/jose.js +15 -0
- package/lib/lint.js +4 -0
- package/lib/merkle.js +5 -5
- package/lib/ocsp.js +139 -11
- package/lib/oid.js +69 -1
- package/lib/path-validate.js +27 -4
- package/lib/pkcs12-build.js +12 -0
- package/lib/schema-all.js +19 -1
- package/lib/schema-attrcert.js +27 -0
- package/lib/schema-c509.js +6 -0
- package/lib/schema-cmc.js +791 -0
- package/lib/schema-cmp.js +25 -0
- package/lib/schema-cms.js +17 -1
- package/lib/schema-crl.js +23 -1
- package/lib/schema-crmf.js +13 -0
- package/lib/schema-csr.js +11 -0
- package/lib/schema-csrattrs.js +6 -0
- package/lib/schema-engine.js +6 -2
- package/lib/schema-ocsp.js +41 -0
- package/lib/schema-pkcs12.js +16 -0
- package/lib/schema-pkcs8.js +8 -0
- package/lib/schema-smime.js +4 -4
- package/lib/schema-tsp.js +32 -1
- package/lib/schema-x509.js +14 -1
- package/lib/shbs.js +12 -4
- package/lib/sigstore.js +4 -0
- package/lib/smime.js +28 -7
- package/lib/tls-cert-compress.js +15 -3
- package/lib/trust.js +27 -4
- package/lib/tsp-sign.js +41 -6
- package/lib/vendor/README.md +19 -19
- package/lib/webauthn.js +895 -26
- package/lib/x509-sign.js +3 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/smime.js
CHANGED
|
@@ -495,7 +495,7 @@ function _base64Body(der) {
|
|
|
495
495
|
* @primitive pki.smime.sign
|
|
496
496
|
* @signature pki.smime.sign(content, signers, opts?) -> Promise<Buffer>
|
|
497
497
|
* @since 0.2.25
|
|
498
|
-
* @status
|
|
498
|
+
* @status stable
|
|
499
499
|
* @spec RFC 8551, RFC 5652
|
|
500
500
|
* @related pki.smime.verify, pki.cms.sign
|
|
501
501
|
*
|
|
@@ -521,6 +521,10 @@ function _base64Body(der) {
|
|
|
521
521
|
* @opts protectHeaders enable RFC 9788 header protection (`hp="clear"`) -- inline `opts.headers` on the signed payload + the outer display headers.
|
|
522
522
|
* @opts headers the Non-Structural fields to protect + display: an object `{ Name: value }` or an array `[{ name, value }]` (Subject / From / To / Date / ...); used with `protectHeaders`.
|
|
523
523
|
* @example
|
|
524
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
525
|
+
* var signerKeyPkcs8 = await pki.key.export(pair.privateKey);
|
|
526
|
+
* var signerCertDer = await pki.x509.sign({ subject: "Signer", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
527
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") }, { key: signerKeyPkcs8 });
|
|
524
528
|
* var msg = await pki.smime.sign(Buffer.from("hello"), [{ cert: signerCertDer, key: signerKeyPkcs8 }]);
|
|
525
529
|
*/
|
|
526
530
|
async function sign(content, signers, opts) {
|
|
@@ -565,7 +569,7 @@ function _capped(msg) {
|
|
|
565
569
|
* @primitive pki.smime.verify
|
|
566
570
|
* @signature pki.smime.verify(message, opts?) -> Promise<{ valid, signers, form, content, micalg, protectedHeaders, headerProtection }>
|
|
567
571
|
* @since 0.2.25
|
|
568
|
-
* @status
|
|
572
|
+
* @status stable
|
|
569
573
|
* @spec RFC 8551, RFC 5652, RFC 9788
|
|
570
574
|
* @related pki.smime.sign, pki.cms.verify, pki.path.validate
|
|
571
575
|
*
|
|
@@ -595,6 +599,11 @@ function _capped(msg) {
|
|
|
595
599
|
* @opts strictMicalg reject a `multipart/signed` whose `micalg` disagrees with the SignerInfo digest.
|
|
596
600
|
* @opts legacyHeaderProtection opt in to detecting a LEGACY RFC 8551 header-protected message (RFC 9788 sec. 4.10): a Cryptographic Payload that is a bare `message/rfc822` wrap with no `hp=` parameter. When set, a precisely-identified legacy message surfaces the inner message's headers under `headerProtection.legacy = { headers, mode, fromMismatch, confidential }` -- `headers` an ordered `[{ name, value }]` array (retaining legally-repeated fields such as `Received`), the mode inferred from the envelope (`clear` here) -- NOT under `protectedHeaders`, and `present` stays `false`. Consuming `headerProtection.legacy.headers` is an explicit choice: a legacy message is structurally indistinguishable from an ordinary forwarded `message/rfc822`, so this is a heuristic (RFC 9788 sec. 4.10.2: "not based on any strong end-to-end guarantees") -- cross-check `legacy.fromMismatch`. Anything not precisely identified (a nested crypto layer, an `hp=` on the inner message, a non-`message/rfc822` payload, a duplicate of a singleton field, or a duplicate Content-Type) reports `legacy: null`. Off by default. The signed-and-encrypted form (RFC 9788 Appendix C.3.17) is a documented gap (`legacy: null` at `decrypt`; surfaces as `clear` only via the caller's re-`verify` step) -- the non-recursive layered API exposes no single seam holding both the inner signature verdict and the outer header section.
|
|
597
601
|
* @example
|
|
602
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
603
|
+
* var key = await pki.key.export(pair.privateKey);
|
|
604
|
+
* var cert = await pki.x509.sign({ subject: "Signer", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
605
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") }, { key: key });
|
|
606
|
+
* var smimeMessageBytes = await pki.smime.sign(Buffer.from("hello"), [{ cert: cert, key: key }]);
|
|
598
607
|
* var res = await pki.smime.verify(smimeMessageBytes);
|
|
599
608
|
* if (res.valid) { res.content; res.signers[0].sid; }
|
|
600
609
|
*/
|
|
@@ -680,7 +689,7 @@ function _cmsEncryptOpts(opts) {
|
|
|
680
689
|
* @primitive pki.smime.encrypt
|
|
681
690
|
* @signature pki.smime.encrypt(content, recipients, opts?) -> Promise<Buffer>
|
|
682
691
|
* @since 0.2.26
|
|
683
|
-
* @status
|
|
692
|
+
* @status stable
|
|
684
693
|
* @spec RFC 8551, RFC 5652, RFC 5083
|
|
685
694
|
* @related pki.smime.decrypt, pki.cms.encrypt
|
|
686
695
|
*
|
|
@@ -709,6 +718,11 @@ function _cmsEncryptOpts(opts) {
|
|
|
709
718
|
* @opts keyIdentifier forwarded: `"issuerAndSerial"` (default) or `"subjectKeyIdentifier"`.
|
|
710
719
|
* @opts ukm forwarded: user keying material for kari / kemri recipients.
|
|
711
720
|
* @example
|
|
721
|
+
* var rsa = { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" };
|
|
722
|
+
* var pair = await pki.key.generate(rsa);
|
|
723
|
+
* var recipientCertDer = await pki.x509.sign({ subject: "Recipient", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
724
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
|
|
725
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
712
726
|
* var enc = await pki.smime.encrypt(Buffer.from("secret"), [{ cert: recipientCertDer }]);
|
|
713
727
|
*/
|
|
714
728
|
async function encrypt(content, recipients, opts) {
|
|
@@ -735,7 +749,7 @@ async function encrypt(content, recipients, opts) {
|
|
|
735
749
|
* @primitive pki.smime.decrypt
|
|
736
750
|
* @signature pki.smime.decrypt(message, keyMaterial, opts?) -> Promise<{ content, smimeType, authenticated, recipientType, recipientIndex, contentEncryptionAlgorithm, protectedHeaders, headerProtection }>
|
|
737
751
|
* @since 0.2.26
|
|
738
|
-
* @status
|
|
752
|
+
* @status stable
|
|
739
753
|
* @spec RFC 8551, RFC 5652, RFC 5083, RFC 9788
|
|
740
754
|
* @related pki.smime.encrypt, pki.cms.decrypt, pki.smime.verify
|
|
741
755
|
*
|
|
@@ -763,9 +777,15 @@ async function encrypt(content, recipients, opts) {
|
|
|
763
777
|
* @opts strictSmimeType reject a header `smime-type` that disagrees with the CMS body (`smime/smime-type-mismatch`).
|
|
764
778
|
* @opts legacyHeaderProtection opt in to detecting a LEGACY RFC 8551 header-protected message (RFC 9788 sec. 4.10): an encrypted Cryptographic Payload that is a bare `message/rfc822` wrap with no `hp=` parameter. When set, a precisely-identified legacy message surfaces the inner headers under `headerProtection.legacy = { headers, mode: "cipher", fromMismatch, confidential }` -- `headers` an ordered `[{ name, value }]` array (retaining repeated fields), the `confidential` set derived from the actual visible outer Header Section -- NOT under `protectedHeaders`, and `present` stays `false`, since a legacy message is structurally indistinguishable from a forwarded `message/rfc822` (a heuristic; cross-check `legacy.fromMismatch`). Anything not precisely identified reports `legacy: null`. Off by default.
|
|
765
779
|
* @example
|
|
780
|
+
* var rsa = { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" };
|
|
781
|
+
* var pair = await pki.key.generate(rsa);
|
|
782
|
+
* var recipientKeyPkcs8 = await pki.key.export(pair.privateKey);
|
|
783
|
+
* var recipientCertDer = await pki.x509.sign({ subject: "Recipient", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
784
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") }, { key: recipientKeyPkcs8 });
|
|
785
|
+
* var smimeMessageBytes = await pki.smime.encrypt(Buffer.from("secret"), [{ cert: recipientCertDer }]);
|
|
766
786
|
* var res = await pki.smime.decrypt(smimeMessageBytes, { key: recipientKeyPkcs8, cert: recipientCertDer });
|
|
767
787
|
* res.content; // the recovered inner MIME entity
|
|
768
|
-
* res.authenticated; // false for an enveloped-only
|
|
788
|
+
* res.authenticated; // true here (an AEAD content cipher); false for an enveloped-only CBC message, which carries no integrity
|
|
769
789
|
*/
|
|
770
790
|
async function decrypt(message, keyMaterial, opts) {
|
|
771
791
|
opts = opts || {};
|
|
@@ -795,7 +815,7 @@ async function decrypt(message, keyMaterial, opts) {
|
|
|
795
815
|
* @primitive pki.smime.compress
|
|
796
816
|
* @signature pki.smime.compress(content, opts?) -> Promise<Buffer>
|
|
797
817
|
* @since 0.2.27
|
|
798
|
-
* @status
|
|
818
|
+
* @status stable
|
|
799
819
|
* @spec RFC 8551, RFC 3274
|
|
800
820
|
* @related pki.smime.decompress, pki.cms.compress
|
|
801
821
|
*
|
|
@@ -827,7 +847,7 @@ async function compress(content, opts) {
|
|
|
827
847
|
* @primitive pki.smime.decompress
|
|
828
848
|
* @signature pki.smime.decompress(message, opts?) -> Promise<{ content, contentType, contentTypeName, compressionAlgorithm }>
|
|
829
849
|
* @since 0.2.27
|
|
830
|
-
* @status
|
|
850
|
+
* @status stable
|
|
831
851
|
* @spec RFC 8551, RFC 3274
|
|
832
852
|
* @related pki.smime.compress, pki.cms.decompress, pki.smime.verify, pki.smime.decrypt
|
|
833
853
|
*
|
|
@@ -842,6 +862,7 @@ async function compress(content, opts) {
|
|
|
842
862
|
*
|
|
843
863
|
* @opts maxOutputBytes forwarded to cms.decompress: lower the decompressed-output cap (a DoS bound; downward only).
|
|
844
864
|
* @example
|
|
865
|
+
* var compressedSmimeBytes = await pki.smime.compress(Buffer.from("compress me"));
|
|
845
866
|
* var res = await pki.smime.decompress(compressedSmimeBytes);
|
|
846
867
|
* res.content; // the recovered inner MIME entity
|
|
847
868
|
*/
|
package/lib/tls-cert-compress.js
CHANGED
|
@@ -141,7 +141,7 @@ function _resolveAllowed(opts) {
|
|
|
141
141
|
* @primitive pki.tls.decompressCertificate
|
|
142
142
|
* @signature pki.tls.decompressCertificate(bytes, opts?) -> { algorithm, algorithmName, uncompressedLength, certificateMessage, certificate }
|
|
143
143
|
* @since 0.4.3
|
|
144
|
-
* @status
|
|
144
|
+
* @status stable
|
|
145
145
|
* @spec RFC 8879, RFC 8446
|
|
146
146
|
* @related pki.tls.compressCertificate, pki.tls.parseCertificateMessage, pki.schema.x509.parse
|
|
147
147
|
*
|
|
@@ -179,6 +179,10 @@ function _resolveAllowed(opts) {
|
|
|
179
179
|
* @example
|
|
180
180
|
* // The Certificate message this codec carries: an empty request context, then one
|
|
181
181
|
* // entry -- the certificate DER followed by its (here empty) extensions vector.
|
|
182
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
183
|
+
* var certDer = await pki.x509.sign({ subject: "example.com", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
184
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
|
|
185
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
182
186
|
* var u24 = function (n) { var b = Buffer.alloc(3); b.writeUIntBE(n, 0, 3); return b; };
|
|
183
187
|
* var entry = Buffer.concat([u24(certDer.length), certDer, Buffer.from([0, 0])]);
|
|
184
188
|
* var message = Buffer.concat([Buffer.from([0]), u24(entry.length), entry]);
|
|
@@ -252,7 +256,7 @@ function decompressCertificate(bytes, opts) {
|
|
|
252
256
|
* @primitive pki.tls.parseCertificateMessage
|
|
253
257
|
* @signature pki.tls.parseCertificateMessage(bytes, opts?) -> { certificateRequestContext, entries }
|
|
254
258
|
* @since 0.4.3
|
|
255
|
-
* @status
|
|
259
|
+
* @status stable
|
|
256
260
|
* @spec RFC 8446, RFC 7250
|
|
257
261
|
* @related pki.tls.decompressCertificate, pki.schema.x509.parse
|
|
258
262
|
*
|
|
@@ -277,6 +281,10 @@ function decompressCertificate(bytes, opts) {
|
|
|
277
281
|
* certificateType - "X509" (default) or "RawPublicKey" (RFC 7250).
|
|
278
282
|
*
|
|
279
283
|
* @example
|
|
284
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
285
|
+
* var certDer = await pki.x509.sign({ subject: "example.com", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
286
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
|
|
287
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
280
288
|
* var u24 = function (n) { var b = Buffer.alloc(3); b.writeUIntBE(n, 0, 3); return b; };
|
|
281
289
|
* var entry = Buffer.concat([u24(certDer.length), certDer, Buffer.from([0, 0])]);
|
|
282
290
|
* var message = Buffer.concat([Buffer.from([0]), u24(entry.length), entry]);
|
|
@@ -307,7 +315,7 @@ function parseCertificateMessage(bytes, opts) {
|
|
|
307
315
|
* @primitive pki.tls.compressCertificate
|
|
308
316
|
* @signature pki.tls.compressCertificate(certificateMessage, opts?) -> Buffer
|
|
309
317
|
* @since 0.4.3
|
|
310
|
-
* @status
|
|
318
|
+
* @status stable
|
|
311
319
|
* @spec RFC 8879
|
|
312
320
|
* @related pki.tls.decompressCertificate
|
|
313
321
|
*
|
|
@@ -330,6 +338,10 @@ function parseCertificateMessage(bytes, opts) {
|
|
|
330
338
|
* level - the codec's compression level, passed through unchanged where it applies.
|
|
331
339
|
*
|
|
332
340
|
* @example
|
|
341
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
342
|
+
* var certDer = await pki.x509.sign({ subject: "example.com", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
343
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
|
|
344
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
333
345
|
* var u24 = function (n) { var b = Buffer.alloc(3); b.writeUIntBE(n, 0, 3); return b; };
|
|
334
346
|
* var entry = Buffer.concat([u24(certDer.length), certDer, Buffer.from([0, 0])]);
|
|
335
347
|
* var message = Buffer.concat([Buffer.from([0]), u24(entry.length), entry]);
|
package/lib/trust.js
CHANGED
|
@@ -353,7 +353,7 @@ function _dedupAnchors(anchors) {
|
|
|
353
353
|
* @primitive pki.trust.parseCertdata
|
|
354
354
|
* @signature pki.trust.parseCertdata(text) -> { anchors }
|
|
355
355
|
* @since 0.2.0
|
|
356
|
-
* @status
|
|
356
|
+
* @status stable
|
|
357
357
|
* @spec RFC 5280 (NSS certdata.txt object stream)
|
|
358
358
|
* @defends trust-metadata-misattribution (CWE-345), trust-store-parser-DoS (CWE-770)
|
|
359
359
|
* @related pki.trust.parseCcadbCsv, pki.trust.anchor, pki.path.validate
|
|
@@ -378,6 +378,11 @@ function _dedupAnchors(anchors) {
|
|
|
378
378
|
* @example
|
|
379
379
|
* // Real input is the NSS certdata.txt read from disk; a one-root stream is
|
|
380
380
|
* // synthesized here from a DER certificate to show the object shape.
|
|
381
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
382
|
+
* var der = await pki.x509.sign({ subject: "Example Root", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
383
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
384
|
+
* extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign"] } },
|
|
385
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
381
386
|
* var cert = pki.schema.x509.parse(der);
|
|
382
387
|
* var oct = function (buf) { return Array.prototype.map.call(buf, function (b) { return "\\" + ("000" + b.toString(8)).slice(-3); }).join(""); };
|
|
383
388
|
* var blk = function (n, v) { return n + " MULTILINE_OCTAL\n" + oct(v) + "\nEND\n"; };
|
|
@@ -573,7 +578,7 @@ function _pemCell(cell) {
|
|
|
573
578
|
* @primitive pki.trust.parseCcadbCsv
|
|
574
579
|
* @signature pki.trust.parseCcadbCsv(text) -> { anchors }
|
|
575
580
|
* @since 0.2.0
|
|
576
|
-
* @status
|
|
581
|
+
* @status stable
|
|
577
582
|
* @spec RFC 4180, RFC 5280 (CCADB certificate-records CSV)
|
|
578
583
|
* @defends trust-metadata-misattribution (CWE-345), trust-store-parser-DoS (CWE-770)
|
|
579
584
|
* @related pki.trust.parseCertdata, pki.trust.anchor, pki.path.validate
|
|
@@ -592,6 +597,11 @@ function _pemCell(cell) {
|
|
|
592
597
|
* encoding, through the same strict time reader.
|
|
593
598
|
*
|
|
594
599
|
* @example
|
|
600
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
601
|
+
* var pemText = await pki.x509.sign({ subject: "Example Root", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
602
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
603
|
+
* extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign", "cRLSign"] } },
|
|
604
|
+
* { key: await pki.key.export(pair.privateKey) }, { pem: true });
|
|
595
605
|
* var csv = "Common Name or Certificate Name,Trust Bits," +
|
|
596
606
|
* "Distrust for TLS After Date,Distrust for S/MIME After Date,PEM Info\n" +
|
|
597
607
|
* 'Example Root,"Websites; Email",2027.06.01,,"' + pemText + '"';
|
|
@@ -651,7 +661,7 @@ function parseCcadbCsv(text) {
|
|
|
651
661
|
* @primitive pki.trust.anchor
|
|
652
662
|
* @signature pki.trust.anchor(entry, opts?) -> trustAnchor
|
|
653
663
|
* @since 0.2.0
|
|
654
|
-
* @status
|
|
664
|
+
* @status stable
|
|
655
665
|
* @spec RFC 5280 sec. 6.1.1 (NSS trust-bit semantics)
|
|
656
666
|
* @related pki.trust.parseCertdata, pki.trust.parseCcadbCsv, pki.path.validate
|
|
657
667
|
*
|
|
@@ -669,12 +679,25 @@ function parseCcadbCsv(text) {
|
|
|
669
679
|
* purpose: string // "serverAuth" | "emailProtection" | "codeSigning" -- fail-fast purpose check
|
|
670
680
|
*
|
|
671
681
|
* @example
|
|
682
|
+
* var ca = await pki.key.generate("Ed25519");
|
|
683
|
+
* var caKey = await pki.key.export(ca.privateKey);
|
|
684
|
+
* var caDer = await pki.x509.sign({ subject: "Example Root", subjectPublicKey: await pki.key.export(ca.publicKey),
|
|
685
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
686
|
+
* extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign", "cRLSign"], subjectKeyIdentifier: true } },
|
|
687
|
+
* { key: caKey });
|
|
688
|
+
* var pemText = pki.schema.x509.pemEncode(caDer, "CERTIFICATE");
|
|
689
|
+
* var leaf = await pki.key.generate("Ed25519");
|
|
690
|
+
* var der = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(leaf.publicKey),
|
|
691
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
692
|
+
* extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["serverAuth"], authorityKeyIdentifier: true } },
|
|
693
|
+
* { cert: caDer, key: caKey });
|
|
672
694
|
* var csv = "Common Name or Certificate Name,Trust Bits," +
|
|
673
695
|
* "Distrust for TLS After Date,Distrust for S/MIME After Date,PEM Info\n" +
|
|
674
696
|
* 'Example Root,Websites,,,"' + pemText + '"';
|
|
675
697
|
* var entry = pki.trust.parseCcadbCsv(csv).anchors[0];
|
|
676
698
|
* var anchor = pki.trust.anchor(entry, { purpose: "serverAuth" });
|
|
677
|
-
* await pki.path.validate([pki.schema.x509.parse(der)],
|
|
699
|
+
* await pki.path.validate([pki.schema.x509.parse(der)],
|
|
700
|
+
* { time: new Date("2026-06-01T00:00:00Z"), trustAnchor: anchor, checkPurpose: "serverAuth" });
|
|
678
701
|
*/
|
|
679
702
|
function anchor(entry, opts) {
|
|
680
703
|
if (!entry || typeof entry !== "object" || !Buffer.isBuffer(entry.publicKey) ||
|
package/lib/tsp-sign.js
CHANGED
|
@@ -76,7 +76,7 @@ function _signingCertV2(certDer, hashName) {
|
|
|
76
76
|
* @primitive pki.tsp.sign
|
|
77
77
|
* @signature pki.tsp.sign(messageImprint, tsa, opts) -> Promise<Buffer|string>
|
|
78
78
|
* @since 0.2.15
|
|
79
|
-
* @status
|
|
79
|
+
* @status stable
|
|
80
80
|
* @spec RFC 3161
|
|
81
81
|
* @related pki.schema.tsp.parseToken, pki.cms.sign
|
|
82
82
|
*
|
|
@@ -96,6 +96,14 @@ function _signingCertV2(certDer, hashName) {
|
|
|
96
96
|
* @opts certHashAlgorithm The ESSCertIDv2 hash algorithm name. Default `sha256`.
|
|
97
97
|
* @opts sid / pem Passed through to `pki.cms.sign` (signer identifier, PEM output).
|
|
98
98
|
* @example
|
|
99
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
100
|
+
* var signerKeyPkcs8 = await pki.key.export(pair.privateKey);
|
|
101
|
+
* var signerCertDer = await pki.x509.sign({ subject: "Example TSA", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
102
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
103
|
+
* // RFC 3161 sec. 2.3: a TSA certificate's extendedKeyUsage MUST be critical
|
|
104
|
+
* extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["timeStamping"], extendedKeyUsageCritical: true } },
|
|
105
|
+
* { key: signerKeyPkcs8 });
|
|
106
|
+
* var sha256Digest = Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello")));
|
|
99
107
|
* var imprint = { hashAlgorithm: "sha256", hashedMessage: sha256Digest };
|
|
100
108
|
* var token = await pki.tsp.sign(imprint, { cert: signerCertDer, key: signerKeyPkcs8 }, { policy: "1.3.6.1.4.1.1", serialNumber: 1 });
|
|
101
109
|
* (await pki.cms.verify(token)).valid; // true
|
|
@@ -200,7 +208,7 @@ function _assertImprint(mi) {
|
|
|
200
208
|
* @primitive pki.tsp.request
|
|
201
209
|
* @signature pki.tsp.request(messageImprint, opts) -> Buffer|string
|
|
202
210
|
* @since 0.2.19
|
|
203
|
-
* @status
|
|
211
|
+
* @status stable
|
|
204
212
|
* @spec RFC 3161
|
|
205
213
|
* @related pki.tsp.parseRequest, pki.tsp.sign
|
|
206
214
|
*
|
|
@@ -215,6 +223,7 @@ function _assertImprint(mi) {
|
|
|
215
223
|
* @opts extensions An array of encoded Extension DER buffers ([0] IMPLICIT Extensions).
|
|
216
224
|
* @opts pem Return a PEM "TIMESTAMP REQUEST" string instead of DER (boolean).
|
|
217
225
|
* @example
|
|
226
|
+
* var sha256Digest = Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello")));
|
|
218
227
|
* var req = pki.tsp.request({ hashAlgorithm: "sha256", hashedMessage: sha256Digest }, { nonce: 0x0102030405060708n, certReq: true });
|
|
219
228
|
*/
|
|
220
229
|
function request(messageImprint, opts) {
|
|
@@ -242,7 +251,7 @@ function request(messageImprint, opts) {
|
|
|
242
251
|
* @primitive pki.tsp.parseRequest
|
|
243
252
|
* @signature pki.tsp.parseRequest(input) -> timeStampReq
|
|
244
253
|
* @since 0.2.19
|
|
245
|
-
* @status
|
|
254
|
+
* @status stable
|
|
246
255
|
* @spec RFC 3161
|
|
247
256
|
* @related pki.tsp.request, pki.schema.tsp.parseRequest
|
|
248
257
|
*
|
|
@@ -251,6 +260,8 @@ function request(messageImprint, opts) {
|
|
|
251
260
|
* nonceHex, certReq, extensions }`; a malformed structure throws a typed `TspError`.
|
|
252
261
|
*
|
|
253
262
|
* @example
|
|
263
|
+
* var der = pki.tsp.request({ hashAlgorithm: "sha256", hashedMessage: Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello"))) },
|
|
264
|
+
* { certReq: true });
|
|
254
265
|
* var req = pki.tsp.parseRequest(der);
|
|
255
266
|
* req.certReq; // -> boolean
|
|
256
267
|
*/
|
|
@@ -260,7 +271,7 @@ function parseRequest(input) { return schemaTsp.parseRequest(input); }
|
|
|
260
271
|
* @primitive pki.tsp.response
|
|
261
272
|
* @signature pki.tsp.response(token, opts) -> Buffer|string
|
|
262
273
|
* @since 0.2.19
|
|
263
|
-
* @status
|
|
274
|
+
* @status stable
|
|
264
275
|
* @spec RFC 3161
|
|
265
276
|
* @related pki.tsp.parseResponse, pki.tsp.sign
|
|
266
277
|
*
|
|
@@ -275,6 +286,14 @@ function parseRequest(input) { return schemaTsp.parseRequest(input); }
|
|
|
275
286
|
* @opts statusString Human-readable PKIFreeText (string or array of strings).
|
|
276
287
|
* @opts pem Return a PEM "TIMESTAMP RESPONSE" string instead of DER (boolean).
|
|
277
288
|
* @example
|
|
289
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
290
|
+
* var key = await pki.key.export(pair.privateKey);
|
|
291
|
+
* var cert = await pki.x509.sign({ subject: "Example TSA", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
292
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
293
|
+
* extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["timeStamping"], extendedKeyUsageCritical: true } },
|
|
294
|
+
* { key: key });
|
|
295
|
+
* var token = await pki.tsp.sign({ hashAlgorithm: "sha256", hashedMessage: Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello"))) },
|
|
296
|
+
* { cert: cert, key: key }, { policy: "1.3.6.1.4.1.1", serialNumber: 1 });
|
|
278
297
|
* var resp = pki.tsp.response(token, {}); // granted
|
|
279
298
|
* var rej = pki.tsp.response(null, { status: 2, failInfo: ["badAlg"] }); // rejection
|
|
280
299
|
*/
|
|
@@ -308,7 +327,7 @@ function response(token, opts) {
|
|
|
308
327
|
* @primitive pki.tsp.parseResponse
|
|
309
328
|
* @signature pki.tsp.parseResponse(input) -> timeStampResp
|
|
310
329
|
* @since 0.2.19
|
|
311
|
-
* @status
|
|
330
|
+
* @status stable
|
|
312
331
|
* @spec RFC 3161
|
|
313
332
|
* @related pki.tsp.response, pki.schema.tsp.parse
|
|
314
333
|
*
|
|
@@ -317,6 +336,15 @@ function response(token, opts) {
|
|
|
317
336
|
* status-to-token coupling enforced; a granted response's token is decoded via `parseToken`.
|
|
318
337
|
*
|
|
319
338
|
* @example
|
|
339
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
340
|
+
* var key = await pki.key.export(pair.privateKey);
|
|
341
|
+
* var cert = await pki.x509.sign({ subject: "Example TSA", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
342
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
343
|
+
* extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["timeStamping"], extendedKeyUsageCritical: true } },
|
|
344
|
+
* { key: key });
|
|
345
|
+
* var token = await pki.tsp.sign({ hashAlgorithm: "sha256", hashedMessage: Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello"))) },
|
|
346
|
+
* { cert: cert, key: key }, { policy: "1.3.6.1.4.1.1", serialNumber: 1 });
|
|
347
|
+
* var der = pki.tsp.response(token, {});
|
|
320
348
|
* var resp = pki.tsp.parseResponse(der);
|
|
321
349
|
* resp.timeStampToken.tstInfo.genTime; // -> Date (on a granted response)
|
|
322
350
|
*/
|
|
@@ -534,7 +562,7 @@ function _buildTsaChains(leaf, pool) {
|
|
|
534
562
|
* @primitive pki.tsp.verify
|
|
535
563
|
* @signature pki.tsp.verify(token, data, opts) -> Promise<result>
|
|
536
564
|
* @since 0.2.19
|
|
537
|
-
* @status
|
|
565
|
+
* @status stable
|
|
538
566
|
* @spec RFC 3161, RFC 5816
|
|
539
567
|
* @related pki.tsp.sign, pki.cms.verify, pki.path.validate
|
|
540
568
|
*
|
|
@@ -563,6 +591,13 @@ function _buildTsaChains(leaf, pool) {
|
|
|
563
591
|
* token can still verify and chain.
|
|
564
592
|
* @opts revocationChecker Passed through to `pki.path.validate`.
|
|
565
593
|
* @example
|
|
594
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
595
|
+
* var signerKeyPkcs8 = await pki.key.export(pair.privateKey);
|
|
596
|
+
* var signerCertDer = await pki.x509.sign({ subject: "Example TSA", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
597
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
|
|
598
|
+
* extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["timeStamping"], extendedKeyUsageCritical: true } },
|
|
599
|
+
* { key: signerKeyPkcs8 });
|
|
600
|
+
* var sha256Digest = Buffer.from(await pki.webcrypto.subtle.digest("SHA-256", Buffer.from("hello")));
|
|
566
601
|
* var imprint = { hashAlgorithm: "sha256", hashedMessage: sha256Digest };
|
|
567
602
|
* var token = await pki.tsp.sign(imprint, { cert: signerCertDer, key: signerKeyPkcs8 }, { policy: "1.3.6.1.4.1.1", serialNumber: 1 });
|
|
568
603
|
* var res = await pki.tsp.verify(token, Buffer.from("hello"), {});
|
package/lib/vendor/README.md
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
# Vendored dependencies
|
|
2
2
|
|
|
3
|
-
`@blamejs/pki` ships with
|
|
4
|
-
|
|
3
|
+
`@blamejs/pki` ships with zero npm runtime dependencies and currently vendors
|
|
4
|
+
nothing. This directory holds only the manifest.
|
|
5
5
|
|
|
6
6
|
## Native-first crypto
|
|
7
7
|
|
|
8
8
|
The toolkit's cryptography runs entirely on Node's built-in `node:crypto`. The
|
|
9
9
|
engine floor (Node `>=24.19`) links OpenSSL 3.5, which provides:
|
|
10
10
|
|
|
11
|
-
- the full classical set
|
|
12
|
-
(Ed25519/Ed448), ECDH
|
|
13
|
-
PBKDF2, and the SHA-1/2/3 family; and
|
|
14
|
-
- the FIPS post-quantum set
|
|
11
|
+
- the full classical set: RSA (PKCS#1 v1.5, PSS, OAEP), ECDSA, EdDSA
|
|
12
|
+
(Ed25519/Ed448), ECDH including X25519 and X448, AES (GCM/CBC/CTR/KW), HMAC,
|
|
13
|
+
HKDF, PBKDF2, and the SHA-1/2/3 family; and
|
|
14
|
+
- the FIPS post-quantum set: **ML-KEM** (FIPS 203), **ML-DSA** (FIPS 204), and
|
|
15
15
|
**SLH-DSA** (FIPS 205).
|
|
16
16
|
|
|
17
|
-
A platform built-in ships
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
A platform built-in ships zero bytes, has nothing to hash-pin or keep current,
|
|
18
|
+
and is OpenSSL- and NSS-interoperable by construction, which is what the
|
|
19
|
+
toolkit's interoperability gate needs. There is no reason to vendor a crypto
|
|
20
|
+
library when the runtime already provides the primitive.
|
|
21
21
|
|
|
22
|
-
## When something
|
|
22
|
+
## When something is vendored
|
|
23
23
|
|
|
24
|
-
A package is added here
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
A package is added here only when a specific operation is confirmed missing from
|
|
25
|
+
the engine floor: for example a pure-JS fallback for a post-quantum operation
|
|
26
|
+
whose JS binding is absent on a supported Node version, or a cross-check
|
|
27
|
+
reference used only in tests. When that happens:
|
|
28
28
|
|
|
29
29
|
- `MANIFEST.json` records the package's version, SPDX license, upstream author,
|
|
30
30
|
source URL, exported surface, bundler invocation, CPE, and pinned SHA-256, so
|
|
31
31
|
any tampering is detectable and `scripts/check-vendor-currency.js` can gate
|
|
32
32
|
version drift.
|
|
33
33
|
- The top-level `NOTICE` gains the component's attribution.
|
|
34
|
-
- The reason and the re-open condition are recorded alongside the entry
|
|
35
|
-
vendored dependency is a deliberate, justified exception to native-first
|
|
36
|
-
a default.
|
|
34
|
+
- The reason and the re-open condition are recorded alongside the entry. A
|
|
35
|
+
vendored dependency is a deliberate, justified exception to native-first
|
|
36
|
+
rather than a default.
|
|
37
37
|
|
|
38
38
|
Bundles, when present, are produced with
|
|
39
39
|
`esbuild --format=cjs --minify --platform=node` against the pinned upstream
|
|
40
|
-
version
|
|
40
|
+
version. Refreshing one recomputes its SHA-256 and updates the bytes and the
|
|
41
41
|
matching `hashes.server` entry in the same change.
|