@blamejs/pki 0.8.10 → 0.8.11
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 +19 -0
- package/README.md +5 -5
- package/lib/attrcert-sign.js +14 -15
- package/lib/constants.js +5 -0
- package/lib/guard-parsed.js +1 -1
- package/lib/inspect.js +59 -0
- package/lib/lint.js +3 -3
- package/lib/schema-all.js +10 -5
- package/lib/schema-attrcert.js +108 -13
- package/lib/schema-crl.js +136 -38
- package/lib/schema-crmf.js +91 -6
- package/lib/schema-csr.js +116 -5
- package/lib/schema-pkix.js +494 -4
- package/lib/schema-x509.js +97 -3
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/schema-x509.js
CHANGED
|
@@ -35,6 +35,7 @@ var schema = require("./schema-engine");
|
|
|
35
35
|
var oid = require("./oid");
|
|
36
36
|
var frameworkError = require("./framework-error");
|
|
37
37
|
var pkix = require("./schema-pkix");
|
|
38
|
+
var intrinsic = require("./guard-intrinsic");
|
|
38
39
|
|
|
39
40
|
var CertificateError = frameworkError.CertificateError;
|
|
40
41
|
var PemError = frameworkError.PemError;
|
|
@@ -124,7 +125,7 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
|
|
|
124
125
|
build: function (e, ctx) {
|
|
125
126
|
var tbs = e.tbsMatch;
|
|
126
127
|
|
|
127
|
-
if (!e.outerSignatureAlgorithmBytes
|
|
128
|
+
if (!intrinsic.bufferEquals(e.outerSignatureAlgorithmBytes, tbs.fields.signature.node.bytes)) {
|
|
128
129
|
throw ctx.E("x509/bad-signature-algorithm", "signatureAlgorithm must match tbsCertificate.signature (RFC 5280 sec. 4.1.1.2)");
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -148,7 +149,7 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
|
|
|
148
149
|
return {
|
|
149
150
|
version: version,
|
|
150
151
|
serialNumber: tbs.fields.serialNumber.value,
|
|
151
|
-
serialNumberHex: serialNode.content
|
|
152
|
+
serialNumberHex: intrinsic.bufToString(serialNode.content, "hex"),
|
|
152
153
|
signatureAlgorithm: e.signatureAlgorithm,
|
|
153
154
|
tbsSignatureAlgorithm: tbs.fields.signature.value.result,
|
|
154
155
|
issuer: issuer,
|
|
@@ -213,14 +214,107 @@ function matches(root) {
|
|
|
213
214
|
var validity = kids[i + 3];
|
|
214
215
|
return schema.isUniversal(validity, TAGS.SEQUENCE) &&
|
|
215
216
|
!!validity.children && validity.children.length === 2 &&
|
|
216
|
-
validity.children
|
|
217
|
+
intrinsic.every(validity.children, function (t) {
|
|
217
218
|
return schema.isUniversalOneOf(t, [TAGS.UTC_TIME, TAGS.GENERALIZED_TIME]);
|
|
218
219
|
});
|
|
219
220
|
}
|
|
220
221
|
|
|
222
|
+
/** @internal The certificate scope, as the shared door reads it: RFC 5280 sec. 4.2's extension
|
|
223
|
+
* table and the criticality that profile fixes. One scope, so the single-extension verb takes no
|
|
224
|
+
* `opts.scope`. */
|
|
225
|
+
var CERT_SCOPES = intrinsic.assign(intrinsic.create(null), {
|
|
226
|
+
certificate: {
|
|
227
|
+
decoders: function (ctx) { return pkix.certExtensionDecoders(ctx).byOid; },
|
|
228
|
+
criticality: pkix.certFixedCriticality(oid),
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
var DOOR = pkix.extensionDoor({
|
|
232
|
+
ns: NS, ErrorClass: CertificateError, key: "x509", kind: "certificate", what: "the certificate",
|
|
233
|
+
parse: parse, scopes: CERT_SCOPES, defaultScope: "certificate",
|
|
234
|
+
segments: function (cert) { return [{ list: cert.extensions || [], scope: "certificate" }]; },
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @primitive pki.schema.x509.decodeExtensions
|
|
239
|
+
* @signature pki.schema.x509.decodeExtensions(certOrBytes, opts?) -> rows
|
|
240
|
+
* @since 0.8.11
|
|
241
|
+
* @status stable
|
|
242
|
+
* @spec RFC 5280 sec. 4.2
|
|
243
|
+
* @related pki.schema.x509.parse, pki.lint.certificate, pki.inspect.certificate
|
|
244
|
+
*
|
|
245
|
+
* Read a certificate's extensions as decoded records. `parse` hands back each extension's raw
|
|
246
|
+
* `extnValue` octets, because what an extension means is a question the reader asks rather than
|
|
247
|
+
* one the parse answers; this is the verb that asks it. The argument is the object `parse`
|
|
248
|
+
* returned or the bytes `parse` takes, and a parse result is read rather than re-derived.
|
|
249
|
+
*
|
|
250
|
+
* Each row is `{ oid, name, critical, value, scope, index, state, decoded, code, profile }`, with
|
|
251
|
+
* every field always present. `state` is the discriminator: `"decoded"` when the value read as the
|
|
252
|
+
* structure its identifier names, `"unrecognized"` when this toolkit registers no decoder for that
|
|
253
|
+
* OID, and `"undecodable"` when it does and the value did not read. Read `state` rather than
|
|
254
|
+
* testing `decoded`, because a valid `ocspNoCheck` decodes to `null`.
|
|
255
|
+
*
|
|
256
|
+
* `value` carries the raw octets in every arm, byte-identical to the certificate's, for a caller
|
|
257
|
+
* recomputing a hash or comparing an encoding. `code` is the typed error code in the undecodable
|
|
258
|
+
* arm and `null` elsewhere. `profile` reports the criticality the RFC fixes for that OID, as
|
|
259
|
+
* `{ criticalExpected, citation, deviates, violations }`, and is `null` for an extension whose
|
|
260
|
+
* criticality the issuer chooses.
|
|
261
|
+
*
|
|
262
|
+
* Nothing here is a verdict. An unrecognized critical extension is reported rather than refused,
|
|
263
|
+
* whatever `opts.strict` says, because RFC 5280 sec. 4.2's rule about one is the caller's to
|
|
264
|
+
* apply and refusing it would make a certificate carrying a private critical extension
|
|
265
|
+
* unreadable. The two facts that rule needs, `critical` and `state`, are on the row.
|
|
266
|
+
*
|
|
267
|
+
* @opts
|
|
268
|
+
* - `strict` (boolean) -- throw the decoder's own typed error instead of reporting an
|
|
269
|
+
* undecodable value. It does not turn an unrecognized OID into a throw.
|
|
270
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (integer) -- decode caps for this call. Each may only
|
|
271
|
+
* tighten the built-in ceiling, and each bounds the decoding this call performs.
|
|
272
|
+
* @example
|
|
273
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
274
|
+
* var certDer = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
275
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2027-01-01T00:00:00Z"),
|
|
276
|
+
* extensions: { basicConstraints: { cA: false }, subjectAltName: [{ dNSName: "leaf.example" }] } },
|
|
277
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
278
|
+
* var rows = pki.schema.x509.decodeExtensions(certDer);
|
|
279
|
+
* rows.filter(function (r) { return r.critical && r.state !== "decoded"; }).length; // -> 0
|
|
280
|
+
* // The filter above is the RFC 5280 sec. 4.2 rule: a relying party rejects a certificate whose
|
|
281
|
+
* // critical extensions it cannot read.
|
|
282
|
+
*/
|
|
283
|
+
var decodeExtensions = DOOR.decodeExtensions;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @primitive pki.schema.x509.decodeExtension
|
|
287
|
+
* @signature pki.schema.x509.decodeExtension(ext, opts?) -> row
|
|
288
|
+
* @since 0.8.11
|
|
289
|
+
* @status stable
|
|
290
|
+
* @spec RFC 5280 sec. 4.2
|
|
291
|
+
* @related pki.schema.x509.decodeExtensions
|
|
292
|
+
*
|
|
293
|
+
* Read one certificate extension record as a decoded row. The argument is one element of a
|
|
294
|
+
* `pki.schema.x509.parse` result's `extensions`, as `{ oid, name, critical, value }`, and the row
|
|
295
|
+
* is the one `decodeExtensions` would have produced for it, with `index` 0.
|
|
296
|
+
*
|
|
297
|
+
* @opts
|
|
298
|
+
* - `strict` (boolean) -- throw the decoder's own typed error instead of reporting an
|
|
299
|
+
* undecodable value.
|
|
300
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (integer) -- decode caps for this call. Each may only
|
|
301
|
+
* tighten the built-in ceiling.
|
|
302
|
+
* @example
|
|
303
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
304
|
+
* var certDer = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
305
|
+
* notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2027-01-01T00:00:00Z"),
|
|
306
|
+
* extensions: { basicConstraints: { cA: false } } },
|
|
307
|
+
* { key: await pki.key.export(pair.privateKey) });
|
|
308
|
+
* var parsed = pki.schema.x509.parse(certDer);
|
|
309
|
+
* pki.schema.x509.decodeExtension(parsed.extensions[0]).state; // -> "decoded"
|
|
310
|
+
*/
|
|
311
|
+
var decodeExtension = DOOR.decodeExtension;
|
|
312
|
+
|
|
221
313
|
module.exports = {
|
|
222
314
|
parse: parse,
|
|
223
315
|
pemDecode: pemDecode,
|
|
224
316
|
pemEncode: pemEncode,
|
|
225
317
|
matches: matches,
|
|
318
|
+
decodeExtensions: decodeExtensions,
|
|
319
|
+
decodeExtension: decodeExtension,
|
|
226
320
|
};
|
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:41170205-6ef3-4f77-9577-7ba33e5632bc",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-23T22:37:26.125Z",
|
|
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.8.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.8.11",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.11",
|
|
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.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.8.11",
|
|
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.8.
|
|
57
|
+
"ref": "@blamejs/pki@0.8.11",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|