@blamejs/pki 0.6.13 → 0.6.15
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 +22 -1
- package/README.md +1 -1
- package/index.js +1 -1
- package/lib/acme.js +59 -815
- package/lib/asn1-der.js +7 -245
- package/lib/attrcert-sign.js +12 -260
- package/lib/attrcert-verify.js +1 -7
- package/lib/byte-reader.js +0 -8
- package/lib/byte-writer.js +0 -11
- package/lib/cbor-det.js +0 -54
- package/lib/cmc-build.js +15 -357
- package/lib/cmc-verify.js +6 -239
- package/lib/cmp-build.js +41 -317
- package/lib/cmp-session.js +73 -760
- package/lib/cmp-verify.js +32 -488
- package/lib/cms-compress.js +3 -32
- package/lib/cms-decrypt.js +29 -294
- package/lib/cms-encrypt.js +14 -234
- package/lib/cms-sign.js +29 -324
- package/lib/cms-verify.js +9 -500
- package/lib/composite-kem.js +2 -102
- package/lib/composite-sig.js +1 -77
- package/lib/constants.js +0 -249
- package/lib/crl-sign.js +9 -237
- package/lib/crl-verify.js +1 -10
- package/lib/crmf-sign.js +19 -198
- package/lib/crmf-verify.js +1 -12
- package/lib/csr-sign.js +3 -34
- package/lib/csr-verify.js +1 -12
- package/lib/ct.js +28 -253
- package/lib/edwards-point.js +10 -44
- package/lib/est.js +28 -764
- package/lib/framework-error.js +4 -182
- package/lib/guard-all.js +1 -58
- package/lib/guard-async.js +1 -36
- package/lib/guard-bytes.js +6 -650
- package/lib/guard-compress.js +5 -102
- package/lib/guard-crypto.js +1 -40
- package/lib/guard-der.js +2 -93
- package/lib/guard-encoding.js +2 -60
- package/lib/guard-header.js +1 -36
- package/lib/guard-identifier.js +7 -531
- package/lib/guard-intrinsic.js +1 -150
- package/lib/guard-json.js +10 -73
- package/lib/guard-limits.js +1 -77
- package/lib/guard-list.js +1 -49
- package/lib/guard-name.js +3 -209
- package/lib/guard-parsed.js +7 -335
- package/lib/guard-range.js +1 -71
- package/lib/guard-secret.js +1 -102
- package/lib/guard-text.js +1 -64
- package/lib/guard-time.js +1 -97
- package/lib/hpke.js +3 -105
- package/lib/http-digest.js +14 -142
- package/lib/http-retry-after.js +1 -47
- package/lib/http-transport.js +21 -131
- package/lib/inspect.js +30 -284
- package/lib/ip-utils.js +6 -47
- package/lib/jose.js +7 -142
- package/lib/key.js +2 -67
- package/lib/lint.js +9 -194
- package/lib/merkle.js +1 -27
- package/lib/mime.js +9 -82
- package/lib/ocsp-request-verify.js +1 -14
- package/lib/ocsp-verify.js +1 -82
- package/lib/ocsp.js +11 -169
- package/lib/oid.js +5 -337
- package/lib/path-validate.js +103 -1492
- package/lib/pbes2.js +2 -89
- package/lib/pkcs12-build.js +31 -379
- package/lib/pki-build.js +64 -290
- package/lib/rc2.js +2 -18
- package/lib/rfc3339.js +4 -27
- package/lib/scep.js +59 -233
- package/lib/schema-all.js +0 -122
- package/lib/schema-attrcert.js +4 -146
- package/lib/schema-c509.js +153 -802
- package/lib/schema-cmc.js +5 -220
- package/lib/schema-cmp.js +2 -223
- package/lib/schema-cms.js +13 -427
- package/lib/schema-crl.js +5 -68
- package/lib/schema-crmf.js +6 -167
- package/lib/schema-csr.js +1 -54
- package/lib/schema-csrattrs.js +2 -87
- package/lib/schema-engine.js +0 -152
- package/lib/schema-ocsp.js +0 -117
- package/lib/schema-pkcs12.js +2 -93
- package/lib/schema-pkcs8.js +3 -35
- package/lib/schema-pkix.js +24 -655
- package/lib/schema-smime.js +0 -54
- package/lib/schema-tsp.js +3 -99
- package/lib/schema-x509.js +4 -63
- package/lib/shbs.js +11 -95
- package/lib/sign-scheme.js +2 -97
- package/lib/sigstore.js +9 -169
- package/lib/sleep.js +2 -8
- package/lib/smime.js +15 -408
- package/lib/tls-cert-compress.js +0 -62
- package/lib/trust.js +19 -185
- package/lib/tsp-sign.js +16 -270
- package/lib/validator-all.js +1 -30
- package/lib/validator-attcert.js +2 -46
- package/lib/validator-cose.js +2 -153
- package/lib/validator-keydesc.js +1 -37
- package/lib/validator-sig.js +1 -46
- package/lib/validator-tls.js +1 -88
- package/lib/validator-tpm.js +19 -122
- package/lib/verify-seam.js +1 -24
- package/lib/webauthn-mds.js +3 -400
- package/lib/webauthn.js +12 -833
- package/lib/webcrypto.js +5 -485
- package/lib/x509-sign.js +4 -108
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/schema-csr.js
CHANGED
|
@@ -38,36 +38,15 @@ var frameworkError = require("./framework-error");
|
|
|
38
38
|
var CsrError = frameworkError.CsrError;
|
|
39
39
|
var PemError = frameworkError.PemError;
|
|
40
40
|
|
|
41
|
-
// The csr error namespace the schema engine walks under. Shared PKIX sub-schemas
|
|
42
|
-
// are instantiated here under csr/* so a structural fault reports a csr code.
|
|
43
41
|
var NS = pkix.makeNS("csr", CsrError, oid);
|
|
44
42
|
|
|
45
43
|
var NAME = pkix.name(NS);
|
|
46
44
|
var SPKI = pkix.spki(NS);
|
|
47
45
|
|
|
48
|
-
// CertificationRequestInfo version ::= INTEGER { v1(0) } (RFC 2986 sec. 4.1). A bare
|
|
49
|
-
// mandatory INTEGER whose one legal value is 0, the inverse of the cert/CRL
|
|
50
|
-
// readers, which reject 0 as the DER-forbidden default. Surface v1 as 1. A
|
|
51
|
-
// cert-shaped [0] EXPLICIT wrapper at this position makes asn1.read.integer throw
|
|
52
|
-
// asn1/* (fail-closed).
|
|
53
46
|
var CSR_VERSION = pkix.versionReader(NS, { "0": 1 });
|
|
54
47
|
|
|
55
|
-
// Attribute ::= SEQUENCE { type OID, values SET OF ANY }, the shared pkix factory
|
|
56
|
-
// under the csr NS (values raw DER, SET SIZE(1..MAX), no uniqueness). The same
|
|
57
|
-
// factory serves the PKCS#8 private-key attributes.
|
|
58
48
|
var ATTRIBUTE = pkix.attribute(NS);
|
|
59
49
|
|
|
60
|
-
// The two RECOGNIZED PKCS#9 request attributes get their value syntax enforced
|
|
61
|
-
// (RFC 2985 sec. 5.4.1 challengePassword / sec. 5.4.2 extensionRequest): both
|
|
62
|
-
// are SINGLE VALUE TRUE, extensionRequest carries one Extensions value
|
|
63
|
-
// (RFC 5280 sec. 4.1, SIZE(1..MAX)) and challengePassword one DirectoryString
|
|
64
|
-
// of 1..255 characters. A recognized type with a malformed, multi-valued, or
|
|
65
|
-
// wrong-syntax value fails closed (csr/bad-attribute-value) -- a CA pipeline
|
|
66
|
-
// reading requested extensions off csr.attributes must never receive garbage
|
|
67
|
-
// under the extensionRequest OID. An UNRECOGNIZED attribute type stays opaque
|
|
68
|
-
// raw DER and never fails the parse, and duplicate attribute TYPES stay legal
|
|
69
|
-
// (RFC 2986 puts no uniqueness on the attributes SET). Registry rows keyed by
|
|
70
|
-
// the stable dotted OID, not a switch; values are still surfaced raw.
|
|
71
50
|
var EXTENSIONS = pkix.extensions(NS);
|
|
72
51
|
var DIRECTORY_STRING_TAGS = [
|
|
73
52
|
asn1.TAGS.UTF8_STRING, asn1.TAGS.PRINTABLE_STRING, asn1.TAGS.TELETEX_STRING,
|
|
@@ -75,10 +54,6 @@ var DIRECTORY_STRING_TAGS = [
|
|
|
75
54
|
];
|
|
76
55
|
var RECOGNIZED_ATTRIBUTE_VALUE = {};
|
|
77
56
|
RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("extensionRequest")] = function (node, ctx) {
|
|
78
|
-
// Surface the requested extensions decoded (same {oid,name,critical,value}
|
|
79
|
-
// shape as a certificate's extensions) so a CA pipeline, and the EST
|
|
80
|
-
// re-enroll guard, read them off the attribute instead of re-walking the
|
|
81
|
-
// raw Extensions bytes. Returned as an enrichment merged onto the attribute.
|
|
82
57
|
try { return { extensions: schema.walk(EXTENSIONS, node, ctx).result }; }
|
|
83
58
|
catch (e) {
|
|
84
59
|
throw ctx.E("csr/bad-attribute-value",
|
|
@@ -97,11 +72,6 @@ RECOGNIZED_ATTRIBUTE_VALUE[oid.byName("challengePassword")] = function (node, ct
|
|
|
97
72
|
}
|
|
98
73
|
};
|
|
99
74
|
|
|
100
|
-
// CertificationRequestInfo ::= SEQUENCE { version, subject Name,
|
|
101
|
-
// subjectPKInfo SubjectPublicKeyInfo, attributes [0] IMPLICIT SET OF Attribute }.
|
|
102
|
-
// attributes is a REQUIRED field (a CRI omitting [0] is a missing-required-field
|
|
103
|
-
// fault, not silently accepted) modeled as an IMPLICIT [0] SET OF with min:0 (an
|
|
104
|
-
// empty attributes SET is legal). subject MAY be empty, so there is no non-empty-DN guard.
|
|
105
75
|
var CERTIFICATION_REQUEST_INFO = schema.seq([
|
|
106
76
|
schema.field("version", CSR_VERSION),
|
|
107
77
|
schema.field("subject", NAME),
|
|
@@ -115,7 +85,6 @@ var CERTIFICATION_REQUEST_INFO = schema.seq([
|
|
|
115
85
|
var checkValue = RECOGNIZED_ATTRIBUTE_VALUE[a.type];
|
|
116
86
|
if (checkValue) {
|
|
117
87
|
var valueItems = it.value.fields.values.value.items;
|
|
118
|
-
// Both recognized PKCS#9 types are SINGLE VALUE TRUE (RFC 2985 sec. 5.4).
|
|
119
88
|
if (valueItems.length !== 1) {
|
|
120
89
|
throw ctx.E("csr/bad-attribute-value", (a.name || a.type) + " is a SINGLE VALUE attribute (RFC 2985 sec. 5.4)");
|
|
121
90
|
}
|
|
@@ -126,19 +95,13 @@ var CERTIFICATION_REQUEST_INFO = schema.seq([
|
|
|
126
95
|
});
|
|
127
96
|
return {
|
|
128
97
|
version: m.fields.version.value,
|
|
129
|
-
subject: m.fields.subject.value.result,
|
|
98
|
+
subject: m.fields.subject.value.result,
|
|
130
99
|
subjectPublicKeyInfo: m.fields.subjectPKInfo.value.result,
|
|
131
100
|
attributes: attributes,
|
|
132
101
|
};
|
|
133
102
|
},
|
|
134
103
|
});
|
|
135
104
|
|
|
136
|
-
// CertificationRequest ::= SEQUENCE { certificationRequestInfo, signatureAlgorithm,
|
|
137
|
-
// signature BIT STRING }, the shared SIGNED envelope. It diverges from the
|
|
138
|
-
// cert/CRL builders by omitting the outer-vs-inner signatureAlgorithm agreement
|
|
139
|
-
// check (the CRI has no inner signature AlgorithmIdentifier) and the
|
|
140
|
-
// non-empty-subject guard (a CSR subject MAY be empty). The omission is
|
|
141
|
-
// structural: this build simply never references the agreement bytes.
|
|
142
105
|
var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO, {
|
|
143
106
|
code: "csr/not-a-certification-request", what: "CertificationRequest",
|
|
144
107
|
build: function (e) {
|
|
@@ -185,9 +148,6 @@ var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO,
|
|
|
185
148
|
* csr.subject.dn; // -> "CN=req.example"
|
|
186
149
|
* csr.attributes[0].type; // -> "1.2.840.113549.1.9.14"
|
|
187
150
|
*/
|
|
188
|
-
// Recording, because pki.csr.verify reaches a verdict from this result: the certificationRequestInfo
|
|
189
|
-
// byte range, the key it proves possession of, and the subject and requested extensions that range
|
|
190
|
-
// encodes are separate properties here, so the record is what binds them to one another.
|
|
191
151
|
var parse = pkix.makeRecordingParser({ pemLabel: "CERTIFICATE REQUEST", PemError: PemError, ErrorClass: CsrError, prefix: "csr", what: "certification request", topSchema: CERTIFICATION_REQUEST, ns: NS }, "csr");
|
|
192
152
|
|
|
193
153
|
/**
|
|
@@ -228,14 +188,6 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label || "CERTIFIC
|
|
|
228
188
|
*/
|
|
229
189
|
function pemEncode(der, label) { return pkix.pemEncode(der, label || "CERTIFICATE REQUEST", PemError); }
|
|
230
190
|
|
|
231
|
-
// A CertificationRequest shares the outer SEQUENCE-of-3 shape with a certificate
|
|
232
|
-
// and a CRL; a CSR is distinguished by its CertificationRequestInfo -- a SEQUENCE
|
|
233
|
-
// of EXACTLY four children {version INTEGER, subject SEQUENCE, subjectPKInfo
|
|
234
|
-
// SEQUENCE, attributes [0]}. The mandatory trailing context-[0] attributes
|
|
235
|
-
// element is what a cert (whose tbs leads with [0] EXPLICIT version or an INTEGER
|
|
236
|
-
// serial and never ends the leading run this way) and a CRL (whose tbs reaches a
|
|
237
|
-
// bare Time at the validity position) never present, so the three detectors are
|
|
238
|
-
// mutually exclusive.
|
|
239
191
|
function matches(root) {
|
|
240
192
|
var TAGS = asn1.TAGS;
|
|
241
193
|
var cri = pkix.signedEnvelopeTbs(root);
|
|
@@ -253,10 +205,5 @@ module.exports = {
|
|
|
253
205
|
pemDecode: pemDecode,
|
|
254
206
|
pemEncode: pemEncode,
|
|
255
207
|
matches: matches,
|
|
256
|
-
// The top schema, exposed (not on the curated pki.schema.csr surface) so a
|
|
257
|
-
// composer can drive the encode direction -- schema.encode(schema, v) -> a
|
|
258
|
-
// CertificationRequest -- and prove the round-trip. The EST builder uses it
|
|
259
|
-
// to re-encode a CSR with added attributes (the crmf certReqMessagesSchema
|
|
260
|
-
// precedent).
|
|
261
208
|
certificationRequestSchema: CERTIFICATION_REQUEST,
|
|
262
209
|
};
|
package/lib/schema-csrattrs.js
CHANGED
|
@@ -55,37 +55,19 @@ var CsrattrsError = frameworkError.CsrattrsError;
|
|
|
55
55
|
var NS = pkix.makeNS("csrattrs", CsrattrsError, oid);
|
|
56
56
|
var T = asn1.TAGS;
|
|
57
57
|
|
|
58
|
-
// The base Attribute is SET SIZE(1..MAX); ATTRIBUTE_KEYTYPE lowers the floor to 0
|
|
59
|
-
// only for the ecPublicKey / rsaEncryption key-type hints, whose empty values SET
|
|
60
|
-
// means "any key of this type" (RFC 9908 sec. 3.2). Every other attribute, and
|
|
61
|
-
// every template inner attribute, keeps the non-empty floor, so an empty
|
|
62
|
-
// challengePassword or unknown attribute still fails closed.
|
|
63
|
-
// ATTRIBUTE keeps the base SET SIZE(1..MAX); ATTRIBUTE_OPTIONAL_VALUES lowers the
|
|
64
|
-
// floor to 0. Only the recognized NON-KEY attributes that require a value
|
|
65
|
-
// (id-ExtensionReq, the request-info template) use the strict form; a key-type
|
|
66
|
-
// hint's empty SET means "any key of this type" (RFC 9908 sec. 3.2), and an
|
|
67
|
-
// UNKNOWN attribute (a key type this build does not know yet, or any other OID) is
|
|
68
|
-
// TOLERATED with an empty SET too -- RFC 8951 ignores what it does not recognize,
|
|
69
|
-
// so an unfamiliar OID must not fail the whole response.
|
|
70
58
|
var ATTRIBUTE = pkix.attribute(NS);
|
|
71
59
|
var ATTRIBUTE_OPTIONAL_VALUES = pkix.attribute(NS, { minValues: 0 });
|
|
72
60
|
var EXTENSIONS = pkix.extensions(NS);
|
|
73
61
|
var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
|
|
74
62
|
|
|
75
|
-
|
|
76
|
-
var OID_EXTENSION_REQUEST = oid.byName("extensionRequest"); // id-ExtensionReq
|
|
63
|
+
var OID_EXTENSION_REQUEST = oid.byName("extensionRequest");
|
|
77
64
|
var OID_EC_PUBLIC_KEY = oid.byName("ecPublicKey");
|
|
78
65
|
var OID_RSA_ENCRYPTION = oid.byName("rsaEncryption");
|
|
79
66
|
var OID_TEMPLATE = oid.byName("certificationRequestInfoTemplate");
|
|
80
67
|
var OID_EXT_REQ_TEMPLATE = oid.byName("extensionReqTemplate");
|
|
81
68
|
|
|
82
|
-
// The recognized non-key attributes that MUST carry a value (empty SET rejected).
|
|
83
69
|
var STRICT_VALUES_OIDS = new Set([OID_EXTENSION_REQUEST, OID_TEMPLATE]);
|
|
84
70
|
|
|
85
|
-
// The recognized public-key type OIDs -- used to FLAG a parsed attribute isKeyType
|
|
86
|
-
// for the enroll planner (rsaEncryption / ecPublicKey are only the RFC 9908 sec. 3.2
|
|
87
|
-
// examples; a no-parameter key like Ed25519 or an ML-DSA / SLH-DSA / ML-KEM type is
|
|
88
|
-
// equally valid). Built by registered NAME (a typo fails at load), never literals.
|
|
89
71
|
var KEY_TYPE_OIDS = new Set([
|
|
90
72
|
"rsaEncryption", "ecPublicKey", "Ed25519", "Ed448", "X25519", "X448",
|
|
91
73
|
"id-ml-dsa-44", "id-ml-dsa-65", "id-ml-dsa-87",
|
|
@@ -100,19 +82,13 @@ var KEY_TYPE_OIDS = new Set([
|
|
|
100
82
|
return d;
|
|
101
83
|
}));
|
|
102
84
|
|
|
103
|
-
// ---- RFC 9908 sec. 3.4 CertificationRequestInfoTemplate ------------------
|
|
104
85
|
|
|
105
|
-
// version MUST be v1(0). A dedicated leaf (not pkix.versionReader) so the reject
|
|
106
|
-
// carries the template-specific code the RFC 9908 sec. 3.4 MUST names.
|
|
107
86
|
var TEMPLATE_VERSION = schema.decode(function (n, ctx) {
|
|
108
87
|
var v = asn1.read.integer(n);
|
|
109
88
|
if (v !== 0n) throw ctx.E("csrattrs/bad-template-version", "CertificationRequestInfoTemplate version must be v1(0) (RFC 9908 sec. 3.4)");
|
|
110
89
|
return 0;
|
|
111
90
|
}, function () { return asn1.build.integer(0n); });
|
|
112
91
|
|
|
113
|
-
// SingleAttributeTemplate ::= SEQUENCE { type OID, value ANY OPTIONAL }, where a
|
|
114
|
-
// value-absent element means "the client fills this in" (RFC 9908 sec. 3.4). The
|
|
115
|
-
// trailing OPTIONAL ANY is the algorithmIdentifier-parameters shape.
|
|
116
92
|
var SINGLE_ATTR_TEMPLATE = schema.seq([
|
|
117
93
|
schema.field("type", schema.oidLeaf()),
|
|
118
94
|
schema.optional("value", schema.any(), { whenAny: true }),
|
|
@@ -124,29 +100,19 @@ var SINGLE_ATTR_TEMPLATE = schema.seq([
|
|
|
124
100
|
},
|
|
125
101
|
});
|
|
126
102
|
|
|
127
|
-
// RelativeDistinguishedNameTemplate ::= SET SIZE (1..MAX) OF SingleAttributeTemplate.
|
|
128
103
|
var RDN_TEMPLATE = schema.setOf(SINGLE_ATTR_TEMPLATE, {
|
|
129
104
|
assert: "set", min: 1, code: "csrattrs/bad-name-template", what: "RelativeDistinguishedNameTemplate",
|
|
130
105
|
build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
|
|
131
106
|
});
|
|
132
|
-
// NameTemplate ::= RDNSequence (a SEQUENCE OF RDN-template SETs) -> array of RDNs,
|
|
133
|
-
// each an array of { type, name, value } (value null = "the client fills it in").
|
|
134
107
|
var NAME_TEMPLATE = schema.seqOf(RDN_TEMPLATE, {
|
|
135
108
|
assert: "sequence", code: "csrattrs/bad-name-template", what: "NameTemplate",
|
|
136
109
|
build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
|
|
137
110
|
});
|
|
138
111
|
|
|
139
|
-
// SubjectPublicKeyInfoTemplate ::= SEQUENCE { algorithm AlgorithmIdentifier,
|
|
140
|
-
// subjectPublicKey BIT STRING OPTIONAL }, where the key is OPTIONAL (present
|
|
141
|
-
// only as an RSA modulus-size placeholder), so pkix.spki (key required, arity 2)
|
|
142
|
-
// cannot be reused.
|
|
143
112
|
var SPKI_TEMPLATE = schema.seq([
|
|
144
113
|
schema.field("algorithm", ALGORITHM_IDENTIFIER),
|
|
145
114
|
schema.optional("placeholderKey", schema.bitString(), { whenUniversal: [T.BIT_STRING] }),
|
|
146
115
|
], {
|
|
147
|
-
// subjectPKInfo is [0] IMPLICIT (RFC 9908 sec. 3.4), so the context tag replaces
|
|
148
|
-
// the universal SEQUENCE tag, so the node is context-[0] constructed and its
|
|
149
|
-
// children are read directly (the pwri keyDerivationAlgorithm [0] precedent).
|
|
150
116
|
assert: "implicit", implicitTag: 0, arity: { min: 1, max: 2 }, code: "csrattrs/bad-spki-template", what: "SubjectPublicKeyInfoTemplate",
|
|
151
117
|
build: function (m) {
|
|
152
118
|
return { algorithm: m.fields.algorithm.value.result,
|
|
@@ -154,11 +120,6 @@ var SPKI_TEMPLATE = schema.seq([
|
|
|
154
120
|
},
|
|
155
121
|
});
|
|
156
122
|
|
|
157
|
-
// ExtensionTemplate ::= SEQUENCE { extnID OID, critical BOOLEAN DEFAULT FALSE,
|
|
158
|
-
// extnValue OCTET STRING OPTIONAL }, where extnValue absent means "client supplies";
|
|
159
|
-
// an explicit critical FALSE is non-DER (BOOLEAN DEFAULT FALSE). Not reusable
|
|
160
|
-
// from pkix.extension (whose extnValue is required), so the DER-critical rule
|
|
161
|
-
// is applied here directly.
|
|
162
123
|
var EXTENSION_TEMPLATE = schema.decode(function (n, ctx) {
|
|
163
124
|
if (!schema.isUniversal(n, T.SEQUENCE) || !n.children || n.children.length < 1 || n.children.length > 3) {
|
|
164
125
|
throw ctx.E("csrattrs/bad-extension-template", "ExtensionTemplate must be a SEQUENCE of {extnID, critical?, extnValue?}");
|
|
@@ -176,20 +137,11 @@ var EXTENSION_TEMPLATE = schema.decode(function (n, ctx) {
|
|
|
176
137
|
return { oid: extnID, name: ctx.oid.name(extnID) || null, critical: critical, value: value };
|
|
177
138
|
});
|
|
178
139
|
|
|
179
|
-
// ExtensionReqTemplate ::= ExtensionTemplates ::= SEQUENCE SIZE (1..MAX) OF
|
|
180
|
-
// ExtensionTemplate (RFC 9908 sec. 3.4) -- the id-aa-extensionReqTemplate value
|
|
181
|
-
// is a SEQUENCE OF ExtensionTemplate, not a single one.
|
|
182
140
|
var EXTENSION_REQ_TEMPLATE = schema.seqOf(EXTENSION_TEMPLATE, {
|
|
183
141
|
assert: "sequence", min: 1, code: "csrattrs/bad-extension-template", what: "ExtensionReqTemplate",
|
|
184
142
|
build: function (m) { return m.items.map(function (it) { return it.value; }); },
|
|
185
143
|
});
|
|
186
144
|
|
|
187
|
-
// CertificationRequestInfoTemplate ::= SEQUENCE { version, subject NameTemplate
|
|
188
|
-
// OPTIONAL, subjectPKInfo [0] IMPLICIT OPTIONAL, attributes [1] IMPLICIT
|
|
189
|
-
// Attributes }. attributes is present (may be an empty SET). The RFC 9908
|
|
190
|
-
// sec. 3.4 inner-attribute MUSTs (<=1 extensionReqTemplate; not both
|
|
191
|
-
// extension-request kinds; a values SET of exactly one ExtensionTemplate) are
|
|
192
|
-
// enforced in the build.
|
|
193
145
|
var CERT_REQ_INFO_TEMPLATE = schema.seq([
|
|
194
146
|
schema.field("version", TEMPLATE_VERSION),
|
|
195
147
|
schema.optional("subject", NAME_TEMPLATE, { whenUniversal: [T.SEQUENCE] }),
|
|
@@ -205,16 +157,11 @@ var CERT_REQ_INFO_TEMPLATE = schema.seq([
|
|
|
205
157
|
if (a.type === OID_EXTENSION_REQUEST) {
|
|
206
158
|
hasExtReq = true;
|
|
207
159
|
extReqs += 1;
|
|
208
|
-
// A template id-ExtensionReq carries one Extensions value (RFC 9908 sec. 3.2);
|
|
209
|
-
// decode it so a client reads the requirements off .extensions instead of
|
|
210
|
-
// re-parsing raw bytes (the top-level extensionRequest exposes it the same way).
|
|
211
160
|
if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "a template id-ExtensionReq values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
|
|
212
161
|
extensions = schema.walk(EXTENSIONS, asn1.decode(a.values[0]), ctx).result;
|
|
213
162
|
}
|
|
214
163
|
if (a.type === OID_EXT_REQ_TEMPLATE) {
|
|
215
164
|
extReqTemplates += 1;
|
|
216
|
-
// The attribute's values SET holds exactly one ExtensionReqTemplate
|
|
217
|
-
// (RFC 9908 sec. 3.4); that value is itself a SEQUENCE OF ExtensionTemplate.
|
|
218
165
|
if (a.values.length !== 1) throw NS.E("csrattrs/bad-template-attrs", "an id-aa-extensionReqTemplate values must be a SET of exactly one ExtensionReqTemplate (RFC 9908 sec. 3.4)");
|
|
219
166
|
extensionTemplates = extensionTemplates.concat(schema.walk(EXTENSION_REQ_TEMPLATE, asn1.decode(a.values[0]), ctx).result);
|
|
220
167
|
}
|
|
@@ -233,35 +180,24 @@ var CERT_REQ_INFO_TEMPLATE = schema.seq([
|
|
|
233
180
|
},
|
|
234
181
|
});
|
|
235
182
|
|
|
236
|
-
// ---- AttrOrOID + the semantic enrichment ---------------------------------
|
|
237
183
|
|
|
238
|
-
// Decode the three RFC 9908-meaningful attribute types onto an already-walked
|
|
239
|
-
// Attribute { type, name, values }. Unknown types keep only their raw values.
|
|
240
|
-
// A recognized public-key type is flagged isKeyType so a consumer (the pki.est
|
|
241
|
-
// enroll planner) treats every accepted key type uniformly, not just RSA/EC.
|
|
242
184
|
function _enrichAttribute(item, ctx) {
|
|
243
185
|
if (KEY_TYPE_OIDS.has(item.oid)) item.isKeyType = true;
|
|
244
186
|
if (item.oid === OID_EXTENSION_REQUEST) {
|
|
245
187
|
if (item.values.length !== 1) throw ctx.E("csrattrs/bad-extension-req", "an id-ExtensionReq attribute values must be a SET of exactly one Extensions (RFC 9908 sec. 3.2)");
|
|
246
188
|
item.extensions = schema.walk(EXTENSIONS, asn1.decode(item.values[0]), ctx).result;
|
|
247
189
|
} else if (item.oid === OID_EC_PUBLIC_KEY) {
|
|
248
|
-
// A key-type hint's values SET is empty ("any curve") or a singleton naming
|
|
249
|
-
// one curve (RFC 9908 sec. 3.2); a multi-valued SET is ambiguous, so it fails
|
|
250
|
-
// closed instead of letting DER ordering pick the advertised constraint.
|
|
251
190
|
if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute values must be empty or a SET of exactly one named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)");
|
|
252
191
|
if (item.values.length === 1) {
|
|
253
192
|
try { item.curve = asn1.read.oid(asn1.decode(item.values[0])); }
|
|
254
193
|
catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an ecPublicKey attribute value must be a named-curve OBJECT IDENTIFIER (RFC 9908 sec. 3.2)", e); }
|
|
255
194
|
}
|
|
256
195
|
} else if (item.oid === OID_RSA_ENCRYPTION) {
|
|
257
|
-
// Empty ("any size") or a singleton naming one key size; reject a multi-valued SET.
|
|
258
196
|
if (item.values.length > 1) throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute values must be empty or a SET of exactly one INTEGER key size (RFC 9908 sec. 3.2)");
|
|
259
197
|
if (item.values.length === 1) {
|
|
260
198
|
var sz;
|
|
261
199
|
try { sz = asn1.read.integer(asn1.decode(item.values[0])); }
|
|
262
200
|
catch (e) { throw ctx.E("csrattrs/bad-key-type-attr", "an rsaEncryption attribute value must be an INTEGER key size (RFC 9908 sec. 3.2)", e); }
|
|
263
|
-
// Bound before narrowing to a Number: an RSA modulus-size hint of 1..65536
|
|
264
|
-
// bits covers every real key; a value past 2^53 would round silently.
|
|
265
201
|
if (sz < 1n || sz > 65536n) throw ctx.E("csrattrs/bad-key-type-attr", "the rsaEncryption key size " + sz + " is out of range (1..65536 bits)");
|
|
266
202
|
item.keySize = Number(sz);
|
|
267
203
|
}
|
|
@@ -271,36 +207,25 @@ function _enrichAttribute(item, ctx) {
|
|
|
271
207
|
}
|
|
272
208
|
}
|
|
273
209
|
|
|
274
|
-
// AttrOrOID ::= CHOICE { oid OBJECT IDENTIFIER, attribute Attribute }. The two
|
|
275
|
-
// arms are the two universal tags; anything else is not an AttrOrOID. A decode
|
|
276
|
-
// leaf (not schema.choice) so the enrichment + the paired write live together.
|
|
277
210
|
var ATTR_OR_OID = schema.decode(function (n, ctx) {
|
|
278
211
|
if (schema.isUniversal(n, T.OBJECT_IDENTIFIER) && !n.constructed) {
|
|
279
212
|
var o = asn1.read.oid(n);
|
|
280
213
|
return { kind: "oid", oid: o, name: ctx.oid.name(o) || null };
|
|
281
214
|
}
|
|
282
215
|
if (schema.isUniversal(n, T.SEQUENCE) && n.children) {
|
|
283
|
-
// Peek the type OID to choose the values-arity rule: only a recognized non-key
|
|
284
|
-
// attribute (id-ExtensionReq / template) requires SET SIZE(1..MAX); a key-type
|
|
285
|
-
// hint OR an unknown OID MAY carry an empty SET (RFC 9908 sec. 3.2 / RFC 8951).
|
|
286
216
|
var typeOid = (n.children.length >= 1 && schema.isUniversal(n.children[0], T.OBJECT_IDENTIFIER) && !n.children[0].constructed) ? asn1.read.oid(n.children[0]) : null;
|
|
287
217
|
var attrSchema = STRICT_VALUES_OIDS.has(typeOid) ? ATTRIBUTE : ATTRIBUTE_OPTIONAL_VALUES;
|
|
288
|
-
var a = schema.walk(attrSchema, n, ctx).result;
|
|
218
|
+
var a = schema.walk(attrSchema, n, ctx).result;
|
|
289
219
|
var item = { kind: "attribute", oid: a.type, name: a.name, values: a.values };
|
|
290
220
|
_enrichAttribute(item, ctx);
|
|
291
221
|
return item;
|
|
292
222
|
}
|
|
293
223
|
throw ctx.E("csrattrs/bad-attr-or-oid", "each CsrAttrs element must be an OBJECT IDENTIFIER or an Attribute SEQUENCE (RFC 8951 sec. 3.5)");
|
|
294
224
|
}, function (item) {
|
|
295
|
-
// Paired encoder (one structure, both directions): reconstruct from the arm's
|
|
296
|
-
// identifying fields plus raw values, since the typed enrichment is decode-only.
|
|
297
225
|
if (item.kind === "oid") return asn1.build.oid(item.oid);
|
|
298
226
|
return asn1.build.sequence([asn1.build.oid(item.oid), asn1.build.set(item.values)]);
|
|
299
227
|
});
|
|
300
228
|
|
|
301
|
-
// CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID. min:0, because an empty SEQUENCE is
|
|
302
|
-
// a complete valid document. The cross-element MUSTs (RFC 9908 sec. 3.2 single
|
|
303
|
-
// id-ExtensionReq; sec. 3.4 single template) are enforced in the build.
|
|
304
229
|
var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
|
|
305
230
|
assert: "sequence", code: "csrattrs/not-csrattrs", what: "CsrAttrs",
|
|
306
231
|
build: function (m) {
|
|
@@ -347,21 +272,13 @@ var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
|
|
|
347
272
|
*/
|
|
348
273
|
var parse = pkix.makeParser({ pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CsrattrsError, prefix: "csrattrs", what: "CsrAttrs", topSchema: CSR_ATTRS, ns: NS });
|
|
349
274
|
|
|
350
|
-
// matches(root): a CsrAttrs is a universal SEQUENCE whose children are each a
|
|
351
|
-
// bare universal OID or an Attribute (a universal SEQUENCE of exactly 2 whose
|
|
352
|
-
// first child is an OID and second a SET). An empty SEQUENCE (30 00) is a valid
|
|
353
|
-
// CsrAttrs and no other registered document root accepts it. Registered BEFORE
|
|
354
|
-
// ocsp-request (a permissive superset probe) as the strict refinement, the same
|
|
355
|
-
// resolution tsp / crmf already use.
|
|
356
275
|
function matches(root) {
|
|
357
276
|
var k = pkix.rootSequenceChildren(root, 0);
|
|
358
277
|
if (!k) return false;
|
|
359
278
|
if (k.length === 0) return true;
|
|
360
279
|
for (var i = 0; i < k.length; i++) {
|
|
361
280
|
var c = k[i];
|
|
362
|
-
// bare-OID arm: a primitive universal OBJECT IDENTIFIER.
|
|
363
281
|
if (schema.isUniversal(c, T.OBJECT_IDENTIFIER) && !c.constructed) continue;
|
|
364
|
-
// Attribute arm: a universal SEQUENCE of exactly { OID, SET }.
|
|
365
282
|
if (!schema.isUniversal(c, T.SEQUENCE) || !c.children || c.children.length !== 2) return false;
|
|
366
283
|
if (!schema.isUniversal(c.children[0], T.OBJECT_IDENTIFIER)) return false;
|
|
367
284
|
if (!(schema.isUniversal(c.children[1], T.SET) && c.children[1].children)) return false;
|
|
@@ -372,7 +289,5 @@ function matches(root) {
|
|
|
372
289
|
module.exports = {
|
|
373
290
|
parse: parse,
|
|
374
291
|
matches: matches,
|
|
375
|
-
// The top schema, exposed (not on the curated pki.schema.csrattrs surface) so a
|
|
376
|
-
// composer can drive the encode direction and prove the round-trip.
|
|
377
292
|
csrAttrsSchema: CSR_ATTRS,
|
|
378
293
|
};
|