@blamejs/pki 0.6.14 → 0.6.16
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 +27 -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 +140 -286
- 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-all.js
CHANGED
|
@@ -46,200 +46,89 @@ var crmf = require("./schema-crmf");
|
|
|
46
46
|
var cmp = require("./schema-cmp");
|
|
47
47
|
var csrattrs = require("./schema-csrattrs");
|
|
48
48
|
var attrcert = require("./schema-attrcert");
|
|
49
|
-
// smime is a companion decoder for CMS signed-attribute values and not a top-level
|
|
50
|
-
// format: it has no self-describing DER root (an ESS attribute value is a bare
|
|
51
|
-
// SEQUENCE) so it is deliberately absent from FORMATS / the detect-and-route
|
|
52
|
-
// `parse`; it is reached only by explicit OID dispatch on a CMS attribute.
|
|
53
49
|
var smime = require("./schema-smime");
|
|
54
|
-
// cmc is likewise a COMPANION decoder, for the same reason arrived at from the
|
|
55
|
-
// other direction: a CMC message's outer DER root IS a CMS ContentInfo, which
|
|
56
|
-
// `cms.matches` already claims below. A `cmc` FORMATS row would either shadow CMS
|
|
57
|
-
// or be shadowed by it, and there is no structurally disjoint root to detect --
|
|
58
|
-
// the discriminator is the encapsulated content type, one layer in. So it is
|
|
59
|
-
// reached by explicit call, or by dispatching on
|
|
60
|
-
// `pki.schema.cms.parse(der).encapContentInfo.eContentType`, and exports no
|
|
61
|
-
// `matches` for nobody to call.
|
|
62
50
|
var cmc = require("./schema-cmc");
|
|
63
51
|
var frameworkError = require("./framework-error");
|
|
64
52
|
|
|
65
53
|
var SchemaError = frameworkError.SchemaError;
|
|
66
54
|
var PemError = frameworkError.PemError;
|
|
67
55
|
|
|
68
|
-
// The shared parse-entry opts for the orchestrator: label-agnostic PEM unwrap
|
|
69
|
-
// (any block type routes), the schema/* error family. Detection needs a decoded
|
|
70
|
-
// root, so the coerced bytes are what gets routed to the matched format. The
|
|
71
|
-
// ber mode lets a BER-encoded PFX (the dominant real-world .p12 shape) decode
|
|
72
|
-
// far enough to detect; a BER input matching a strict-DER-only format still
|
|
73
|
-
// fails typed inside that format's own parse.
|
|
74
56
|
var ENTRY = { pemLabel: null, PemError: PemError, ErrorClass: SchemaError, prefix: "schema", what: "input", ber: true };
|
|
75
57
|
|
|
76
|
-
// REGISTRY -- each format is declarative data: a name, a `detect(root)` that
|
|
77
|
-
// recognizes the decoded DER root as this format's outer structure, and the
|
|
78
|
-
// member's own `parse`. Adding a format is a table entry, not new dispatch
|
|
79
|
-
// logic. Order matters: the most specific detector wins, so a new member is
|
|
80
|
-
// inserted ahead of any more-permissive one.
|
|
81
58
|
var FORMATS = [
|
|
82
59
|
{
|
|
83
|
-
// CMS ContentInfo (RFC 5652 sec. 3) -- the only registered root that leads with an
|
|
84
|
-
// OBJECT IDENTIFIER child (a SEQUENCE of exactly 2: contentType OID + a
|
|
85
|
-
// context [0] EXPLICIT content wrapper). Disjoint from the INTEGER-first pkcs8
|
|
86
|
-
// and the tbs-SEQUENCE-first signed-envelope trio, so it detects unambiguously.
|
|
87
|
-
// A non-SignedData content type routes here and gets a precise
|
|
88
|
-
// cms/unsupported-content-type instead of schema/unknown-format.
|
|
89
60
|
name: "cms",
|
|
90
61
|
module: cms,
|
|
91
62
|
detect: cms.matches,
|
|
92
63
|
parse: function (input) { return cms.parse(input); },
|
|
93
64
|
},
|
|
94
65
|
{
|
|
95
|
-
// TimeStampResp ::= SEQUENCE { status PKIStatusInfo, timeStampToken OPTIONAL } --
|
|
96
|
-
// a SEQUENCE of 1-2 whose first child is a PKIStatusInfo SEQUENCE whose own first
|
|
97
|
-
// child is an INTEGER status. This detector is a strict REFINEMENT of the
|
|
98
|
-
// ocsp-request one (both are SEQUENCE-of-1-2 with a SEQUENCE first child), so it
|
|
99
|
-
// MUST be checked first: a tokenless TimeStampResp (a bare PKIStatusInfo) would
|
|
100
|
-
// otherwise be shadowed by ocsp-request, whereas an OCSPRequest's tbsRequest never
|
|
101
|
-
// leads with a universal INTEGER and so never matches here (RFC 3161 sec. 2.4.2). A
|
|
102
|
-
// bare timestamp token is a CMS ContentInfo and routes to cms; a bare TSTInfo is
|
|
103
|
-
// an internal payload (reached via pki.schema.tsp.parseTstInfo).
|
|
104
66
|
name: "tsp",
|
|
105
67
|
module: tsp,
|
|
106
68
|
detect: tsp.matches,
|
|
107
69
|
parse: function (input) { return tsp.parse(input); },
|
|
108
70
|
},
|
|
109
71
|
{
|
|
110
|
-
// CertReqMessages ::= SEQUENCE SIZE(1..MAX) OF CertReqMsg (RFC 4211 sec. 3): a
|
|
111
|
-
// SEQUENCE whose first CertReqMsg's CertRequest leads with a universal INTEGER
|
|
112
|
-
// (certReqId) then a universal SEQUENCE (certTemplate). Leads with a SEQUENCE
|
|
113
|
-
// like the signed-envelope trio and the ocsp-request, but the INTEGER-then-
|
|
114
|
-
// SEQUENCE pair at that depth is disjoint from both. Registered AHEAD of
|
|
115
|
-
// ocsp-request: a single-message CertReqMessages is the only remaining overlap
|
|
116
|
-
// with the ocsp-request detector, and crmf's deeper probe is the more specific.
|
|
117
72
|
name: "crmf",
|
|
118
73
|
module: crmf,
|
|
119
74
|
detect: crmf.matches,
|
|
120
75
|
parse: function (input) { return crmf.parse(input); },
|
|
121
76
|
},
|
|
122
77
|
{
|
|
123
|
-
// PKIMessage ::= SEQUENCE { header PKIHeader, body PKIBody [0..26],
|
|
124
|
-
// protection [0]?, extraCerts [1]? } (RFC 9810 sec. 5.1): a SEQUENCE of 2-4
|
|
125
|
-
// whose first child is a >=3-child SEQUENCE leading with a bare INTEGER
|
|
126
|
-
// (pvno) and whose second child is context-constructed [0..26]. Order is
|
|
127
|
-
// load-bearing here: a 2-child PKIMessage whose body is ir [0] also
|
|
128
|
-
// satisfies the shallow ocsp-request probe below (k[0] SEQUENCE +
|
|
129
|
-
// k[1] context-[0]), while no OCSPRequest satisfies this detector (its
|
|
130
|
-
// tbsRequest never leads with a bare INTEGER), so cmp MUST sit ahead of
|
|
131
|
-
// ocsp-request for the pair to dispatch deterministically.
|
|
132
78
|
name: "cmp",
|
|
133
79
|
module: cmp,
|
|
134
80
|
detect: cmp.matches,
|
|
135
81
|
parse: function (input) { return cmp.parse(input); },
|
|
136
82
|
},
|
|
137
83
|
{
|
|
138
|
-
// CsrAttrs ::= SEQUENCE SIZE (0..MAX) OF AttrOrOID (RFC 8951 sec. 3.5): a
|
|
139
|
-
// SEQUENCE whose every child is a bare universal OID or an Attribute (a
|
|
140
|
-
// universal SEQUENCE of exactly 2: OID + SET). A 1-2-element all-Attribute
|
|
141
|
-
// CsrAttrs satisfies the permissive ocsp-request probe below (SEQUENCE +
|
|
142
|
-
// constructed first child), and the empty 30 00 is a CsrAttrs no other root
|
|
143
|
-
// accepts -- so csrattrs is the strict refinement and MUST sit ahead of
|
|
144
|
-
// ocsp-request, the same resolution tsp / cmp use. Disjoint from cmp (whose
|
|
145
|
-
// body child is context-[0..26], never a universal OID/Attribute).
|
|
146
84
|
name: "csrattrs",
|
|
147
85
|
module: csrattrs,
|
|
148
86
|
detect: csrattrs.matches,
|
|
149
87
|
parse: function (input) { return csrattrs.parse(input); },
|
|
150
88
|
},
|
|
151
89
|
{
|
|
152
|
-
// OCSPRequest ::= SEQUENCE { tbsRequest SEQUENCE, optionalSignature [0] EXPLICIT
|
|
153
|
-
// OPTIONAL }: a SEQUENCE of 1-2 whose first child is the tbsRequest SEQUENCE.
|
|
154
|
-
// Leads with a SEQUENCE like the signed-envelope trio, but is excluded by arity
|
|
155
|
-
// (the trio is exactly 3 children; an OCSPRequest is 1-2). Checked after tsp,
|
|
156
|
-
// whose detector is a strict refinement (RFC 6960 sec. 4.1.1), and after cmp,
|
|
157
|
-
// whose 2-child ir-body shape this probe would otherwise shadow.
|
|
158
90
|
name: "ocsp-request",
|
|
159
91
|
module: ocsp,
|
|
160
92
|
detect: ocsp.matchesRequest,
|
|
161
93
|
parse: function (input) { return ocsp.parseRequest(input); },
|
|
162
94
|
},
|
|
163
95
|
{
|
|
164
|
-
// OCSPResponse ::= SEQUENCE { responseStatus ENUMERATED, responseBytes [0]
|
|
165
|
-
// EXPLICIT OPTIONAL }: the only registered root that leads with an ENUMERATED
|
|
166
|
-
// child, so it is disjoint from every other format (RFC 6960 sec. 4.2.1).
|
|
167
96
|
name: "ocsp-response",
|
|
168
97
|
module: ocsp,
|
|
169
98
|
detect: ocsp.matchesResponse,
|
|
170
99
|
parse: function (input) { return ocsp.parseResponse(input); },
|
|
171
100
|
},
|
|
172
101
|
{
|
|
173
|
-
// PKCS#12 PFX ::= SEQUENCE { version INTEGER, authSafe ContentInfo, macData
|
|
174
|
-
// OPTIONAL }: INTEGER-first like pkcs8, so the discriminators are deeper.
|
|
175
|
-
// children[1] is a ContentInfo (SEQUENCE of exactly 2: OID + [0] constructed,
|
|
176
|
-
// a shape a PrivateKeyInfo's AlgorithmIdentifier never presents) and
|
|
177
|
-
// children[2] is a MacData SEQUENCE or absent (pkcs8 requires an OCTET STRING
|
|
178
|
-
// there). Shape-disjoint from pkcs8, and registered ahead of it as the more
|
|
179
|
-
// specific probe (RFC 7292 sec. 4). A BER-encoded PFX detects through the
|
|
180
|
-
// orchestrator's BER decode fallback and routes here.
|
|
181
102
|
name: "pkcs12",
|
|
182
103
|
module: pkcs12,
|
|
183
104
|
detect: pkcs12.matches,
|
|
184
105
|
parse: function (input) { return pkcs12.parse(input); },
|
|
185
106
|
},
|
|
186
107
|
{
|
|
187
|
-
// PKCS#8 PrivateKeyInfo / OneAsymmetricKey: a SEQUENCE whose first child is an
|
|
188
|
-
// INTEGER (version) and third an OCTET STRING (privateKey); disjoint from the
|
|
189
|
-
// signed-envelope trio. (EncryptedPrivateKeyInfo is deliberately not
|
|
190
|
-
// auto-routed: its SEQUENCE{SEQUENCE, OCTET STRING} shape is ambiguous, since a
|
|
191
|
-
// PKCS#1 DigestInfo is identical, so structural detection cannot classify it
|
|
192
|
-
// without a validated encryption-algorithm discriminator, which arrives with
|
|
193
|
-
// the PBES layer. It is reached explicitly via pki.schema.pkcs8.parseEncrypted.)
|
|
194
108
|
name: "pkcs8",
|
|
195
109
|
module: pkcs8,
|
|
196
110
|
detect: pkcs8.matches,
|
|
197
111
|
parse: function (input) { return pkcs8.parse(input); },
|
|
198
112
|
},
|
|
199
113
|
{
|
|
200
|
-
// CertificationRequest ::= SEQUENCE { certificationRequestInfo,
|
|
201
|
-
// signatureAlgorithm, signature }: the same outer 3-element shape,
|
|
202
|
-
// distinguished by a CertificationRequestInfo of exactly four children
|
|
203
|
-
// ending in the IMPLICIT [0] attributes element. Checked first because that
|
|
204
|
-
// detector is the most specific and mutually exclusive with the others.
|
|
205
114
|
name: "csr",
|
|
206
115
|
module: csr,
|
|
207
116
|
detect: csr.matches,
|
|
208
117
|
parse: function (input) { return csr.parse(input); },
|
|
209
118
|
},
|
|
210
119
|
{
|
|
211
|
-
// AttributeCertificate ::= SEQUENCE { acinfo, signatureAlgorithm, signatureValue }
|
|
212
|
-
// -- the signed-envelope trio, recognized by an acinfo that LEADS WITH a bare
|
|
213
|
-
// INTEGER version and carries a 2-GeneralizedTime attrCertValidityPeriod at
|
|
214
|
-
// children[5] (RFC 5755, section 4.1). Order-independent versus crl / x509 / csr:
|
|
215
|
-
// a v2 acinfo puts the AlgorithmIdentifier at the position where their probes
|
|
216
|
-
// require a bare Time / a 2-Time Validity / a 4-child CRI, and none of their tbs
|
|
217
|
-
// shapes carry the 2-GeneralizedTime marker at children[5].
|
|
218
120
|
name: "attrcert",
|
|
219
121
|
module: attrcert,
|
|
220
122
|
detect: attrcert.matches,
|
|
221
123
|
parse: function (input) { return attrcert.parse(input); },
|
|
222
124
|
},
|
|
223
125
|
{
|
|
224
|
-
// AttributeCertificateV1 (X.509-1997, RFC 5652, section 10.2) -- the obsolete
|
|
225
|
-
// predecessor whose acInfo LEADS WITH the subject CHOICE (context [0]/[1]).
|
|
226
|
-
// Recognized and deferred with a precise attrcert/legacy-v1-not-supported rather
|
|
227
|
-
// than routed to a wrong format. ORDER IS LOAD-BEARING against x509: a [0]-subject
|
|
228
|
-
// v1 AC ALSO satisfies x509.matches (the [0] child reads as the certificate's
|
|
229
|
-
// EXPLICIT version marker, putting the 2-GeneralizedTime attrCertValidityPeriod at
|
|
230
|
-
// the Validity probe offset), so this entry MUST sit ahead of x509 for first-match
|
|
231
|
-
// dispatch to defer it here. children[1] == SEQUENCE keeps a v3 certificate (whose
|
|
232
|
-
// [0] version is followed by an INTEGER serialNumber) from matching in the other
|
|
233
|
-
// direction.
|
|
234
126
|
name: "attrcert-v1",
|
|
235
127
|
module: attrcert,
|
|
236
128
|
detect: attrcert.matchesV1,
|
|
237
129
|
parse: function (input) { return attrcert.parseV1(input); },
|
|
238
130
|
},
|
|
239
131
|
{
|
|
240
|
-
// CertificateList ::= SEQUENCE { tbsCertList, signatureAlgorithm,
|
|
241
|
-
// signatureValue }: the same outer shape as a certificate, distinguished
|
|
242
|
-
// by its tbsCertList (a bare Time at the certificate's Validity position).
|
|
243
132
|
name: "crl",
|
|
244
133
|
module: crl,
|
|
245
134
|
detect: crl.matches,
|
|
@@ -248,9 +137,6 @@ var FORMATS = [
|
|
|
248
137
|
{
|
|
249
138
|
name: "x509",
|
|
250
139
|
module: x509,
|
|
251
|
-
// Certificate, identified by a Validity (SEQUENCE of two Times) inside the
|
|
252
|
-
// tbs, so a CSR or other 3-element signed envelope is not misclassified as a
|
|
253
|
-
// certificate (it falls through to schema/unknown-format).
|
|
254
140
|
detect: x509.matches,
|
|
255
141
|
parse: function (input) { return x509.parse(input); },
|
|
256
142
|
},
|
|
@@ -293,9 +179,6 @@ function all() { return FORMATS.map(function (f) { return f.name; }); }
|
|
|
293
179
|
* var parsed = pki.schema.parse(der); // cert -> the pki.schema.x509 shape
|
|
294
180
|
*/
|
|
295
181
|
function parse(input) {
|
|
296
|
-
// Coerce + decode via the shared parse-entry, then route the COERCED DER (a
|
|
297
|
-
// PEM string/Buffer is already unwrapped, so the matched format parses DER
|
|
298
|
-
// directly and never re-treats the armor as DER).
|
|
299
182
|
var der = pkix.coerceToDer(input, ENTRY);
|
|
300
183
|
var root = pkix.decodeRoot(der, ENTRY);
|
|
301
184
|
for (var i = 0; i < FORMATS.length; i++) {
|
|
@@ -336,14 +219,9 @@ function detectFormat(input) {
|
|
|
336
219
|
return null;
|
|
337
220
|
}
|
|
338
221
|
|
|
339
|
-
// Curated public surface: each format exposes only its operator primitives. The
|
|
340
|
-
// `matches` detector is internal dispatch infrastructure (used by FORMATS above),
|
|
341
|
-
// not an operator API, so it is NOT re-exported here.
|
|
342
222
|
module.exports = {
|
|
343
223
|
engine: engine,
|
|
344
224
|
x509: { parse: x509.parse, pemDecode: x509.pemDecode, pemEncode: x509.pemEncode },
|
|
345
|
-
// C509 is CBOR, not DER: an explicit-call surface only, NOT added to FORMATS / the detect-and-route
|
|
346
|
-
// parse() below (which detect DER shapes). No pemDecode/pemEncode -- C509 is binary CBOR.
|
|
347
225
|
c509: { parse: c509.parse, encode: c509.encode },
|
|
348
226
|
crl: { parse: crl.parse, pemDecode: crl.pemDecode, pemEncode: crl.pemEncode },
|
|
349
227
|
csr: { parse: csr.parse, pemDecode: csr.pemDecode, pemEncode: csr.pemEncode },
|
package/lib/schema-attrcert.js
CHANGED
|
@@ -40,8 +40,6 @@ var pkix = require("./schema-pkix");
|
|
|
40
40
|
var oid = require("./oid");
|
|
41
41
|
var guard = require("./guard-all");
|
|
42
42
|
var intrinsic = require("./guard-intrinsic");
|
|
43
|
-
// Own-key membership through an operation taken at load. Written out, the question reads two
|
|
44
|
-
// replaceable properties to answer one thing, and here it decides which object-digest types resolve.
|
|
45
43
|
var _hasOwn = intrinsic.hasOwn;
|
|
46
44
|
var frameworkError = require("./framework-error");
|
|
47
45
|
|
|
@@ -55,20 +53,11 @@ var TAGS = asn1.TAGS;
|
|
|
55
53
|
var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
|
|
56
54
|
var EXTENSIONS = pkix.extensions(NS);
|
|
57
55
|
|
|
58
|
-
// AttCertVersion ::= INTEGER { v2(1) }, a bare mandatory INTEGER (not the x509
|
|
59
|
-
// [0] EXPLICIT DEFAULT shape). The only legal value is v2, surfaced as 2.
|
|
60
56
|
var VERSION = pkix.versionReader(NS, { "1": 2 });
|
|
61
57
|
|
|
62
|
-
// ---- shared leaves ---------------------------------------------------
|
|
63
58
|
|
|
64
|
-
// AttCertValidityPeriod times are GeneralizedTime (RFC 5755 sec. 4.2.6) -- a UTCTime is
|
|
65
|
-
// rejected. Non-fractional YYYYMMDDHHMMSSZ is enforced by the codec.
|
|
66
59
|
var GENERALIZED_TIME = pkix.generalizedTime(NS, { code: "attrcert/bad-time", message: "AttCertValidityPeriod times must be GeneralizedTime (RFC 5755 sec. 4.2.6)" });
|
|
67
60
|
|
|
68
|
-
// digestedObjectType ::= ENUMERATED { publicKey(0), publicKeyCert(1),
|
|
69
|
-
// otherObjectTypes(2) } (RFC 5755 sec. 4.1). An undefined value is rejected; a
|
|
70
|
-
// non-ENUMERATED tag fails at the codec (asn1/*).
|
|
71
|
-
// objectDigestInfo digested-object-type names -- single source pki.C.NAMES.OBJECT_DIGEST_TYPE.
|
|
72
61
|
var ODT_NAMES = constants.NAMES.OBJECT_DIGEST_TYPE;
|
|
73
62
|
var DIGESTED_OBJECT_TYPE = schema.decode(function (n, ctx) {
|
|
74
63
|
var v = asn1.read.enumerated(n);
|
|
@@ -76,22 +65,13 @@ var DIGESTED_OBJECT_TYPE = schema.decode(function (n, ctx) {
|
|
|
76
65
|
if (!_hasOwn(ODT_NAMES, k)) {
|
|
77
66
|
throw ctx.E("attrcert/bad-digested-object-type", "digestedObjectType " + k + " is not a defined value (RFC 5755 sec. 4.1)");
|
|
78
67
|
}
|
|
79
|
-
// RFC 5755 sec. 7.3 -- a conformant AC MUST NOT use otherObjectTypes(2); the digested
|
|
80
|
-
// object is limited to a public key or a public-key certificate, so reject it
|
|
81
|
-
// fail-closed instead of parsing a digest whose object type is unidentifiable.
|
|
82
68
|
if (k === "2") {
|
|
83
69
|
throw ctx.E("attrcert/bad-digested-object-type", "otherObjectTypes(2) MUST NOT be used (RFC 5755 sec. 7.3)");
|
|
84
70
|
}
|
|
85
71
|
return { code: Number(v), name: ODT_NAMES[k] };
|
|
86
72
|
});
|
|
87
73
|
|
|
88
|
-
// ---- IssuerSerial / ObjectDigestInfo ---------------------------------
|
|
89
74
|
|
|
90
|
-
// IssuerSerial ::= SEQUENCE { issuer GeneralNames, serial CertificateSerialNumber,
|
|
91
|
-
// issuerUID UniqueIdentifier OPTIONAL } (RFC 5755 sec. 4.1). Reached as an IMPLICIT
|
|
92
|
-
// [n] node (Holder [0] / V2Form [0]) whose tag replaces the SEQUENCE tag, so the
|
|
93
|
-
// shape assertion is "constructed" (the tag is pinned by the enclosing trailing);
|
|
94
|
-
// a context [n] PRIMITIVE node has no children and fails closed here.
|
|
95
75
|
var ISSUER_SERIAL = schema.seq([
|
|
96
76
|
schema.field("issuer", pkix.generalNames(NS, { code: "attrcert/bad-issuer-serial" })),
|
|
97
77
|
schema.field("serial", schema.integerLeaf()),
|
|
@@ -108,9 +88,6 @@ var ISSUER_SERIAL = schema.seq([
|
|
|
108
88
|
},
|
|
109
89
|
});
|
|
110
90
|
|
|
111
|
-
// ObjectDigestInfo ::= SEQUENCE { digestedObjectType ENUMERATED, otherObjectTypeID
|
|
112
|
-
// OBJECT IDENTIFIER OPTIONAL, digestAlgorithm AlgorithmIdentifier, objectDigest BIT
|
|
113
|
-
// STRING } (RFC 5755 sec. 4.1). otherObjectTypeID is present only for otherObjectTypes(2).
|
|
114
91
|
var OBJECT_DIGEST_INFO = schema.seq([
|
|
115
92
|
schema.field("digestedObjectType", DIGESTED_OBJECT_TYPE),
|
|
116
93
|
schema.optional("otherObjectTypeID", schema.oidLeaf(), { whenUniversal: [TAGS.OBJECT_IDENTIFIER] }),
|
|
@@ -120,15 +97,9 @@ var OBJECT_DIGEST_INFO = schema.seq([
|
|
|
120
97
|
assert: "constructed", code: "attrcert/bad-object-digest-info", what: "ObjectDigestInfo",
|
|
121
98
|
build: function (m, ctx) {
|
|
122
99
|
var t = m.fields.digestedObjectType.value;
|
|
123
|
-
// otherObjectTypeID identifies a non-certificate object type, meaningful only with
|
|
124
|
-
// otherObjectTypes(2) -- which RFC 5755 sec. 7.3 forbids (rejected at the leaf above) --
|
|
125
|
-
// so a present otherObjectTypeID is never valid here and is rejected fail-closed.
|
|
126
100
|
if (m.fields.otherObjectTypeID.present) {
|
|
127
101
|
throw ctx.E("attrcert/bad-object-digest-info", "otherObjectTypeID is only valid with otherObjectTypes(2), which RFC 5755 sec. 7.3 forbids");
|
|
128
102
|
}
|
|
129
|
-
// The objectDigest is a whole-octet digest over the identified object; a
|
|
130
|
-
// non-octet-aligned BIT STRING is malformed (RFC 5755 sec. 4.1) and has no
|
|
131
|
-
// in-tree verify layer to catch it later, so reject it at parse.
|
|
132
103
|
guard.crypto.assertOctetAligned(m.fields.objectDigest.value, ctx.E, "attrcert/bad-object-digest-info", "objectDigest");
|
|
133
104
|
return {
|
|
134
105
|
digestedObjectType: t,
|
|
@@ -139,13 +110,7 @@ var OBJECT_DIGEST_INFO = schema.seq([
|
|
|
139
110
|
},
|
|
140
111
|
});
|
|
141
112
|
|
|
142
|
-
// ---- Holder / AttCertIssuer / V2Form ---------------------------------
|
|
143
113
|
|
|
144
|
-
// Holder ::= SEQUENCE { baseCertificateID [0] IMPLICIT IssuerSerial OPTIONAL,
|
|
145
|
-
// entityName [1] IMPLICIT GeneralNames OPTIONAL, objectDigestInfo [2] IMPLICIT
|
|
146
|
-
// ObjectDigestInfo OPTIONAL } (RFC 5755 sec. 4.1). All three are IMPLICIT + OPTIONAL;
|
|
147
|
-
// the profile RECOMMENDS exactly one, but the parser surfaces all three (null when
|
|
148
|
-
// absent) and does not enforce the cardinality.
|
|
149
114
|
var HOLDER = schema.seq([
|
|
150
115
|
schema.trailing([
|
|
151
116
|
{ tag: 0, name: "baseCertificateID", schema: ISSUER_SERIAL },
|
|
@@ -163,13 +128,6 @@ var HOLDER = schema.seq([
|
|
|
163
128
|
},
|
|
164
129
|
});
|
|
165
130
|
|
|
166
|
-
// V2Form ::= SEQUENCE { issuerName GeneralNames OPTIONAL, baseCertificateID [0]
|
|
167
|
-
// IMPLICIT IssuerSerial OPTIONAL, objectDigestInfo [1] IMPLICIT ObjectDigestInfo
|
|
168
|
-
// OPTIONAL } (RFC 5755 sec. 4.1). Reached via the AttCertIssuer CHOICE on a context [0]
|
|
169
|
-
// node, so the shape is "constructed". The build enforces the sec. 4.2.3 issuer
|
|
170
|
-
// profile MUSTs: every field is syntactically OPTIONAL, but a conformant AC's
|
|
171
|
-
// issuerName is present with one and only one GeneralName (a non-empty
|
|
172
|
-
// directoryName) and baseCertificateID / objectDigestInfo are absent.
|
|
173
131
|
var V2_FORM = schema.seq([
|
|
174
132
|
schema.optional("issuerName", pkix.generalNames(NS, { code: "attrcert/bad-issuer-name" }), { whenUniversal: [TAGS.SEQUENCE] }),
|
|
175
133
|
schema.trailing([
|
|
@@ -189,9 +147,6 @@ var V2_FORM = schema.seq([
|
|
|
189
147
|
if (issuerName.names[0].tagNumber !== 4) {
|
|
190
148
|
throw ctx.E("attrcert/bad-issuer-name", "the issuerName GeneralName must be a directoryName [4] (RFC 5755 sec. 4.2.3)");
|
|
191
149
|
}
|
|
192
|
-
// directoryName [4] EXPLICIT wraps exactly one Name (the shared GeneralName
|
|
193
|
-
// grammar validated that); a zero-RDN Name is an empty DN identifying no
|
|
194
|
-
// issuer, which sec. 4.2.3 forbids.
|
|
195
150
|
var dirName = asn1.decode(issuerName.names[0].bytes).children[0];
|
|
196
151
|
if (!dirName.children || dirName.children.length < 1) {
|
|
197
152
|
throw ctx.E("attrcert/bad-issuer-name", "the issuerName directoryName must be a non-empty distinguished name (RFC 5755 sec. 4.2.3)");
|
|
@@ -203,10 +158,6 @@ var V2_FORM = schema.seq([
|
|
|
203
158
|
},
|
|
204
159
|
});
|
|
205
160
|
|
|
206
|
-
// AttCertIssuer ::= CHOICE { v1Form GeneralNames, v2Form [0] IMPLICIT V2Form } (RFC
|
|
207
|
-
// 5755 sec. 4.1). A universal SEQUENCE is the (obsolete but structurally recognizable)
|
|
208
|
-
// v1Form, which a conformant AC MUST NOT use (sec. 4.2.3). The arm is recognized and
|
|
209
|
-
// rejected with a precise verdict instead of mis-dispatched; a context [0] is v2Form.
|
|
210
161
|
var ATT_CERT_ISSUER = schema.choice([
|
|
211
162
|
{ when: { tagClass: "universal", tagNumber: TAGS.SEQUENCE },
|
|
212
163
|
schema: schema.decode(function (n, ctx) {
|
|
@@ -215,10 +166,7 @@ var ATT_CERT_ISSUER = schema.choice([
|
|
|
215
166
|
{ when: { tagClass: "context", tagNumber: 0 }, schema: V2_FORM },
|
|
216
167
|
], { code: "attrcert/bad-issuer" });
|
|
217
168
|
|
|
218
|
-
// ---- validity + attributes -------------------------------------------
|
|
219
169
|
|
|
220
|
-
// AttCertValidityPeriod ::= SEQUENCE { notBeforeTime GeneralizedTime, notAfterTime
|
|
221
|
-
// GeneralizedTime } (RFC 5755 sec. 4.2.6).
|
|
222
170
|
var VALIDITY = schema.seq([
|
|
223
171
|
schema.field("notBeforeTime", GENERALIZED_TIME),
|
|
224
172
|
schema.field("notAfterTime", GENERALIZED_TIME),
|
|
@@ -227,20 +175,13 @@ var VALIDITY = schema.seq([
|
|
|
227
175
|
build: function (m) { return { notBeforeTime: m.fields.notBeforeTime.value, notAfterTime: m.fields.notAfterTime.value }; },
|
|
228
176
|
});
|
|
229
177
|
|
|
230
|
-
// attributes ::= SEQUENCE OF Attribute (RFC 5755 sec. 4.2.7), which MUST be non-empty and
|
|
231
|
-
// each AttributeType OID unique. Order-preserving (SEQUENCE OF, not SET OF).
|
|
232
178
|
var ATTRIBUTES = schema.seqOf(pkix.attribute(NS), {
|
|
233
179
|
assert: "sequence", min: 1, code: "attrcert/bad-attributes", what: "attributes",
|
|
234
180
|
unique: function (it) { return it.value.result.type; }, dupCode: "attrcert/duplicate-attribute",
|
|
235
181
|
build: function (m) { return m.items.map(function (it) { return it.value.result; }); },
|
|
236
182
|
});
|
|
237
183
|
|
|
238
|
-
// ---- AttributeCertificateInfo / AttributeCertificate -----------------
|
|
239
184
|
|
|
240
|
-
// AttributeCertificateInfo ::= SEQUENCE { version, holder, issuer, signature
|
|
241
|
-
// AlgorithmIdentifier, serialNumber, attrCertValidityPeriod, attributes,
|
|
242
|
-
// issuerUniqueID OPTIONAL, extensions OPTIONAL } (RFC 5755 sec. 4.1). The tbs body the
|
|
243
|
-
// signed envelope wraps; the cross-field invariants live in the envelope build.
|
|
244
185
|
var ACINFO = schema.seq([
|
|
245
186
|
schema.field("version", VERSION),
|
|
246
187
|
schema.field("holder", HOLDER),
|
|
@@ -253,24 +194,15 @@ var ACINFO = schema.seq([
|
|
|
253
194
|
schema.optional("extensions", EXTENSIONS, { whenUniversal: [TAGS.SEQUENCE] }),
|
|
254
195
|
], { assert: "sequence", code: "attrcert/bad-acinfo", what: "AttributeCertificateInfo" });
|
|
255
196
|
|
|
256
|
-
// AttributeCertificate ::= SEQUENCE { acinfo, signatureAlgorithm, signatureValue
|
|
257
|
-
// BIT STRING }, the shared SIGNED envelope (RFC 5755 sec. 4.1). The AC-specific
|
|
258
|
-
// invariants (sec. 4.2.4 sig-alg agreement, sec. 4.2.5 positive-and-<=20-octet serialNumber)
|
|
259
|
-
// run in the build; the envelope owns the SEQUENCE-of-3 shape + signature extraction.
|
|
260
197
|
var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
261
198
|
code: "attrcert/not-an-attribute-certificate", what: "AttributeCertificate",
|
|
262
199
|
build: function (e, ctx) {
|
|
263
200
|
var acinfo = e.tbsMatch;
|
|
264
201
|
|
|
265
|
-
// RFC 5755 sec. 4.2.4 -- the outer signatureAlgorithm MUST equal acinfo.signature.
|
|
266
202
|
if (!e.outerSignatureAlgorithmBytes.equals(acinfo.fields.signature.node.bytes)) {
|
|
267
203
|
throw ctx.E("attrcert/bad-signature-algorithm", "signatureAlgorithm must match AttributeCertificateInfo.signature (RFC 5755 sec. 4.2.4)");
|
|
268
204
|
}
|
|
269
205
|
|
|
270
|
-
// RFC 5755 sec. 4.2.5 -- serialNumber MUST be a positive INTEGER of at most 20 content
|
|
271
|
-
// octets. Positive excludes both a negative (DER sign bit set) and zero (a minimal
|
|
272
|
-
// INTEGER 0 is a single 0x00 octet, and the codec already rejected any non-minimal
|
|
273
|
-
// zero). Surface it lossless (BigInt) + as hex.
|
|
274
206
|
var serialNode = acinfo.fields.serialNumber.node;
|
|
275
207
|
var sc = serialNode.content;
|
|
276
208
|
if (sc.length === 0 || (sc[0] & 0x80) !== 0 || (sc.length === 1 && sc[0] === 0)) {
|
|
@@ -280,22 +212,14 @@ var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
|
280
212
|
throw ctx.E("attrcert/bad-serial-number", "serialNumber must not exceed 20 content octets (RFC 5755 sec. 4.2.5)");
|
|
281
213
|
}
|
|
282
214
|
|
|
283
|
-
// AttCertIssuer is a CHOICE whose v1Form arm rejects at the leaf (sec. 4.2.3), so
|
|
284
|
-
// the surviving arm is always v2Form. The { form, v2Form, v1Form } shape is
|
|
285
|
-
// kept stable for consumers keying off `form`.
|
|
286
215
|
var issuer = { form: "v2Form", v2Form: acinfo.fields.issuer.value.result, v1Form: null };
|
|
287
216
|
|
|
288
|
-
// RFC 5755 sec. 4.4 -- decode each attribute's value(s) additively: a recognized attribute type
|
|
289
|
-
// gains `decoded` (parallel to `values`); an unrecognized type falls back to { opaque, bytes } so
|
|
290
|
-
// the parse never fails on an unknown attribute, and a recognized-but-malformed value fails closed.
|
|
291
217
|
var attributes = acinfo.fields.attributes.value.result;
|
|
292
218
|
attributes.forEach(function (a) {
|
|
293
219
|
var dec = _ATTR_VALUE_DECODERS[a.type];
|
|
294
220
|
a.decoded = a.values.map(function (v) { return dec ? dec(v) : { opaque: true, bytes: v }; });
|
|
295
221
|
});
|
|
296
222
|
|
|
297
|
-
// RFC 5755 sec. 4.3 -- decode each AC extension additively (extensions[i].decoded), same opaque
|
|
298
|
-
// fallback + fail-closed-on-malformed contract as the attributes above.
|
|
299
223
|
var extField = acinfo.fields.extensions;
|
|
300
224
|
var extensions = (extField && extField.present) ? extField.value.result : [];
|
|
301
225
|
extensions.forEach(function (x) {
|
|
@@ -304,7 +228,7 @@ var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
|
304
228
|
});
|
|
305
229
|
|
|
306
230
|
return {
|
|
307
|
-
version: acinfo.fields.version.value,
|
|
231
|
+
version: acinfo.fields.version.value,
|
|
308
232
|
holder: acinfo.fields.holder.value.result,
|
|
309
233
|
issuer: issuer,
|
|
310
234
|
signatureAlgorithm: e.signatureAlgorithm,
|
|
@@ -321,7 +245,6 @@ var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
|
321
245
|
},
|
|
322
246
|
});
|
|
323
247
|
|
|
324
|
-
// ---- parse -----------------------------------------------------------
|
|
325
248
|
|
|
326
249
|
/**
|
|
327
250
|
* @primitive pki.schema.attrcert.parse
|
|
@@ -365,23 +288,13 @@ function _legacyV1Error() {
|
|
|
365
288
|
|
|
366
289
|
function _parseAc(input) {
|
|
367
290
|
var root = pkix.decodeRoot(pkix.coerceToDer(input, PARSE_OPTS), PARSE_OPTS);
|
|
368
|
-
// A well-formed legacy AttributeCertificateV1 gets the advertised, stable
|
|
369
|
-
// attrcert/legacy-v1-not-supported on the DIRECT path too -- not a low-level asn1/*
|
|
370
|
-
// tag error from attempting the v2 walk -- so a direct caller of this entry sees the
|
|
371
|
-
// same error family for the recognized-but-deferred form as the orchestrator does.
|
|
372
291
|
if (matchesV1(root)) throw _legacyV1Error();
|
|
373
292
|
return schema.walk(ATTRIBUTE_CERTIFICATE, root, NS).result;
|
|
374
293
|
}
|
|
375
294
|
|
|
376
|
-
// Recording, because pki.attrcert.verify reaches a verdict from this result: the signed byte range,
|
|
377
|
-
// the holder the privileges attach to and the attributes themselves are separate properties here,
|
|
378
|
-
// so the record is what binds them to one another.
|
|
379
295
|
var parse = guard.parsed.recordingParser("attributeCertificate", _parseAc,
|
|
380
296
|
AttrCertError, "attrcert/bad-input", "an attribute certificate");
|
|
381
297
|
|
|
382
|
-
// The obsolete X.509-1997 AttributeCertificateV1 (RFC 5652 sec. 10.2) is recognized and
|
|
383
|
-
// deferred: decode the envelope (so a malformed input still fails as bad DER), then
|
|
384
|
-
// throw the precise diagnostic rather than routing it to a wrong format.
|
|
385
298
|
function parseV1(input) {
|
|
386
299
|
pkix.decodeRoot(pkix.coerceToDer(input, PARSE_OPTS), PARSE_OPTS);
|
|
387
300
|
throw _legacyV1Error();
|
|
@@ -440,11 +353,6 @@ function pemDecode(text, label) { return pkix.pemDecode(text, label === null ? n
|
|
|
440
353
|
*/
|
|
441
354
|
function pemEncode(der, label) { return pkix.pemEncode(der, label || "ATTRIBUTE CERTIFICATE", PemError); }
|
|
442
355
|
|
|
443
|
-
// matches(root): a v2 AttributeCertificate is the signed-envelope trio whose acinfo
|
|
444
|
-
// LEADS WITH a bare universal INTEGER version (== v2 = 1, NOT the x509 [0] EXPLICIT
|
|
445
|
-
// wrapper) and whose attrCertValidityPeriod at children[5] is a SEQUENCE of exactly
|
|
446
|
-
// two GeneralizedTime (RFC 5755 sec. 4.2.6 forbids UTCTime) -- a marker no cert / CRL /
|
|
447
|
-
// CSR presents at that position. Disjoint from matchesV1 by the children[0] tag class.
|
|
448
356
|
function matches(root) {
|
|
449
357
|
var acinfo = pkix.signedEnvelopeTbs(root);
|
|
450
358
|
if (!acinfo) return false;
|
|
@@ -457,11 +365,6 @@ function matches(root) {
|
|
|
457
365
|
return v.children.every(function (t) { return schema.isUniversal(t, TAGS.GENERALIZED_TIME); });
|
|
458
366
|
}
|
|
459
367
|
|
|
460
|
-
// matchesV1(root): the obsolete AttributeCertificateV1 -- its acInfo (version DEFAULT
|
|
461
|
-
// v1 OMITTED) LEADS WITH the subject CHOICE (a context [0]/[1]), and its children[1]
|
|
462
|
-
// is the issuer GeneralNames (a universal SEQUENCE). The children[1] == SEQUENCE test
|
|
463
|
-
// keeps it disjoint from a v3 certificate (whose [0] EXPLICIT version is followed by
|
|
464
|
-
// an INTEGER serialNumber), so v1-vs-cert dispatch is order-independent.
|
|
465
368
|
function matchesV1(root) {
|
|
466
369
|
var acinfo = pkix.signedEnvelopeTbs(root);
|
|
467
370
|
if (!acinfo) return false;
|
|
@@ -471,12 +374,6 @@ function matchesV1(root) {
|
|
|
471
374
|
return schema.isUniversal(k[1], TAGS.SEQUENCE);
|
|
472
375
|
}
|
|
473
376
|
|
|
474
|
-
// ---- RFC 5755 sec. 4.4 attribute-value decoders ----------------------
|
|
475
|
-
// A per-attribute-type decoder table (mirroring pkix.certExtensionDecoders): each takes the raw
|
|
476
|
-
// AttributeValue TLV Buffer and returns a structured value, throwing a typed attrcert/bad-* error on
|
|
477
|
-
// any non-conformant shape. Composes pkix's shared imperative helpers + generalName/generalNames.
|
|
478
|
-
// A single GeneralName decodes as the walk OBJECT itself (gn.tagNumber / gn.value); generalNames
|
|
479
|
-
// (plural) returns { names:[...] } on .result.
|
|
480
377
|
var _AV = pkix._decodeHelpers(NS);
|
|
481
378
|
var _decodeTop = _AV.decodeTop, _seqChildren = _AV.seqChildren, _readInt = _AV.readInt, _Oav = _AV.O;
|
|
482
379
|
var _GN = pkix.generalName(NS, { decodeValue: true, code: "attrcert/bad-general-name" });
|
|
@@ -492,19 +389,11 @@ function _oneGN(node, code) {
|
|
|
492
389
|
return { tagNumber: gn.tagNumber, value: gn.value };
|
|
493
390
|
}
|
|
494
391
|
|
|
495
|
-
//
|
|
496
|
-
// certificate is surfaced in.
|
|
497
|
-
//
|
|
498
|
-
// @internal -- exported so a verifier comparing a caller's GeneralName against one this module
|
|
499
|
-
// decoded puts BOTH sides through this one decoder. A second decoder would be a second set of
|
|
500
|
-
// per-form conventions, and a comparison whose two halves were produced by different rules is a
|
|
501
|
-
// comparison of the rules rather than of the names.
|
|
392
|
+
// @internal
|
|
502
393
|
function readGeneralName(der, code) {
|
|
503
394
|
return _oneGN(asn1.decode(der), code || "attrcert/bad-input");
|
|
504
395
|
}
|
|
505
396
|
|
|
506
|
-
// SvceAuthInfo ::= SEQUENCE { service GeneralName, ident GeneralName, authInfo OCTET STRING OPTIONAL }
|
|
507
|
-
// -- authenticationInfo (sec. 4.4.1) allows authInfo; accessIdentity (sec. 4.4.2) MUST omit it.
|
|
508
397
|
function _svceAuthInfo(authInfoAllowed, code) {
|
|
509
398
|
return function (buf) {
|
|
510
399
|
var kids = _seqChildren(buf, code, "SvceAuthInfo");
|
|
@@ -521,8 +410,6 @@ function _svceAuthInfo(authInfoAllowed, code) {
|
|
|
521
410
|
};
|
|
522
411
|
}
|
|
523
412
|
|
|
524
|
-
// IetfAttrSyntax ::= SEQUENCE { policyAuthority [0] IMPLICIT GeneralNames OPTIONAL,
|
|
525
|
-
// values SEQUENCE OF CHOICE { octets OCTET STRING, oid OBJECT IDENTIFIER, string UTF8String } }
|
|
526
413
|
function _ietfAttrSyntax(buf) {
|
|
527
414
|
var C = "attrcert/bad-ietf-attr";
|
|
528
415
|
var kids = _seqChildren(buf, C, "IetfAttrSyntax");
|
|
@@ -544,7 +431,6 @@ function _ietfAttrSyntax(buf) {
|
|
|
544
431
|
return { policyAuthority: policyAuthority, values: values, homogeneous: Object.keys(kinds).length === 1 };
|
|
545
432
|
}
|
|
546
433
|
|
|
547
|
-
// RoleSyntax ::= SEQUENCE { roleAuthority [0] IMPLICIT GeneralNames OPTIONAL, roleName [1] EXPLICIT GeneralName }
|
|
548
434
|
function _role(buf) {
|
|
549
435
|
var C = "attrcert/bad-role";
|
|
550
436
|
var kids = _seqChildren(buf, C, "RoleSyntax");
|
|
@@ -557,9 +443,6 @@ function _role(buf) {
|
|
|
557
443
|
return { roleAuthority: roleAuthority, roleName: _oneGN(rn.children[0], C) };
|
|
558
444
|
}
|
|
559
445
|
|
|
560
|
-
// Clearance ::= SEQUENCE { policyId OBJECT IDENTIFIER, classList ClassList DEFAULT {unclassified},
|
|
561
|
-
// securityCategories SET OF SecurityCategory OPTIONAL }.
|
|
562
|
-
// ClassList ::= BIT STRING { unmarked(0), unclassified(1), restricted(2), confidential(3), secret(4), topSecret(5) }.
|
|
563
446
|
var _CLASSLIST_NAMES = ["unmarked", "unclassified", "restricted", "confidential", "secret", "topSecret"];
|
|
564
447
|
function _decodeClassList(node, C) {
|
|
565
448
|
var bs;
|
|
@@ -574,7 +457,6 @@ function _decodeClassList(node, C) {
|
|
|
574
457
|
}
|
|
575
458
|
return { names: names, flags: flags, reservedBits: reserved };
|
|
576
459
|
}
|
|
577
|
-
// SecurityCategory ::= SEQUENCE { type [0] IMPLICIT OBJECT IDENTIFIER, value [1] EXPLICIT ANY }.
|
|
578
460
|
function _securityCategory(node, C) {
|
|
579
461
|
if (!_isU(node, TAGS.SEQUENCE) || !node.children || node.children.length !== 2) throw NS.E(C, "a SecurityCategory must be a SEQUENCE of a type and a value");
|
|
580
462
|
var typeNode = node.children[0], valueNode = node.children[1];
|
|
@@ -589,7 +471,7 @@ function _clearance(buf) {
|
|
|
589
471
|
if (!kids.length || kids.length > 3) throw NS.E(C, "Clearance must be a SEQUENCE { policyId, classList?, securityCategories? }");
|
|
590
472
|
if (!_isU(kids[0], TAGS.OBJECT_IDENTIFIER)) throw NS.E(C, "Clearance policyId must be an OBJECT IDENTIFIER");
|
|
591
473
|
var policyId; try { policyId = asn1.read.oid(kids[0]); } catch (e) { throw NS.E(C, "Clearance policyId must be an OBJECT IDENTIFIER", e); }
|
|
592
|
-
var classList = { names: ["unclassified"], flags: { unclassified: true }, reservedBits: [] }, i = 1;
|
|
474
|
+
var classList = { names: ["unclassified"], flags: { unclassified: true }, reservedBits: [] }, i = 1;
|
|
593
475
|
if (kids[i] && _isU(kids[i], TAGS.BIT_STRING)) {
|
|
594
476
|
classList = _decodeClassList(kids[i], C);
|
|
595
477
|
if (classList.names.length === 1 && classList.flags.unclassified && !classList.reservedBits.length) {
|
|
@@ -611,21 +493,13 @@ function _clearance(buf) {
|
|
|
611
493
|
var _ATTR_VALUE_DECODERS = {};
|
|
612
494
|
_ATTR_VALUE_DECODERS[_Oav("role")] = _role;
|
|
613
495
|
_ATTR_VALUE_DECODERS[_Oav("clearance")] = _clearance;
|
|
614
|
-
// RFC 5755 sec. 4.4.6 requires decoding the legacy RFC 3281 id-at-clearance too (the X.501
|
|
615
|
-
// selected-attribute-types arc, an alias of "clearance" -- built from arcs, never a dotted literal).
|
|
616
496
|
_ATTR_VALUE_DECODERS[oid.fromArcs([2, 5, 1, 5, 55])] = _clearance;
|
|
617
497
|
_ATTR_VALUE_DECODERS[_Oav("authenticationInfo")] = _svceAuthInfo(true, "attrcert/bad-svce-auth-info");
|
|
618
498
|
_ATTR_VALUE_DECODERS[_Oav("accessIdentity")] = _svceAuthInfo(false, "attrcert/bad-access-identity");
|
|
619
499
|
_ATTR_VALUE_DECODERS[_Oav("chargingIdentity")] = _ietfAttrSyntax;
|
|
620
500
|
_ATTR_VALUE_DECODERS[_Oav("group")] = _ietfAttrSyntax;
|
|
621
501
|
|
|
622
|
-
// ---- RFC 5755 sec. 4.3 AC-extension decoders -------------------------
|
|
623
|
-
// A per-extension-OID decoder table for the AC-specific extensions (kept in the AC domain, not the
|
|
624
|
-
// shared cert-extension table, because Targets/TargetCert reuse the local IssuerSerial). Each takes
|
|
625
|
-
// the raw extnValue content Buffer and returns a structured value, fail-closed with a typed error.
|
|
626
502
|
|
|
627
|
-
// AuditIdentity ::= OCTET STRING (sec. 4.3.1) -- an opaque audit tag, unconstrained (no SIZE), so an
|
|
628
|
-
// empty OCTET STRING (04 00) is valid; only the OCTET STRING type is enforced.
|
|
629
503
|
function _acAuditIdentity(buf) {
|
|
630
504
|
var C = "attrcert/bad-audit-identity";
|
|
631
505
|
var n = _decodeTop(buf, C, "AuditIdentity");
|
|
@@ -633,8 +507,6 @@ function _acAuditIdentity(buf) {
|
|
|
633
507
|
return Buffer.concat([asn1.read.octetString(n)]);
|
|
634
508
|
}
|
|
635
509
|
|
|
636
|
-
// NoRevAvail syntax is NULL (sec. 4.3.6: '0500'H is the DER encoding) -- the extnValue OCTET STRING
|
|
637
|
-
// contains a DER NULL. An empty or any-other-shape value is malformed and fails closed.
|
|
638
510
|
function _noRevAvail(buf) {
|
|
639
511
|
var C = "attrcert/bad-no-rev-avail";
|
|
640
512
|
var n = _decodeTop(buf, C, "NoRevAvail");
|
|
@@ -642,8 +514,6 @@ function _noRevAvail(buf) {
|
|
|
642
514
|
return { noRevAvail: true };
|
|
643
515
|
}
|
|
644
516
|
|
|
645
|
-
// Target ::= CHOICE { targetName [0] GeneralName, targetGroup [1] GeneralName, targetCert [2] TargetCert }.
|
|
646
|
-
// [0]/[1] wrap a GeneralName CHOICE (EXPLICIT); [2] is an IMPLICIT TargetCert SEQUENCE.
|
|
647
517
|
function _acTargetCert(node, C) {
|
|
648
518
|
if (!node.children || !node.children.length) throw NS.E(C, "a targetCert [2] must be a non-empty TargetCert SEQUENCE");
|
|
649
519
|
var out = { kind: "targetCert", targetCertificate: null, targetName: null, certDigestInfo: null }, i = 0;
|
|
@@ -664,14 +534,10 @@ function _acTarget(node, C, allowTargetCert) {
|
|
|
664
534
|
}
|
|
665
535
|
throw NS.E(C, "a Target must be [0] targetName, [1] targetGroup, or [2] targetCert");
|
|
666
536
|
}
|
|
667
|
-
// Targets ::= SEQUENCE OF Target -- decode a Targets SEQUENCE node into an array of Target.
|
|
668
537
|
function _acDecodeTargets(node, C, allowTargetCert) {
|
|
669
538
|
if (!_isU(node, TAGS.SEQUENCE) || !node.children || !node.children.length) throw NS.E(C, "Targets must be a non-empty SEQUENCE OF Target");
|
|
670
539
|
return node.children.map(function (t) { return _acTarget(t, C, allowTargetCert); });
|
|
671
540
|
}
|
|
672
|
-
// Both targetInformation (sec. 4.3.2) and ProxyInfo (sec. 7.4) are SEQUENCE OF Targets -- an outer
|
|
673
|
-
// SEQUENCE whose every element is itself a Targets (SEQUENCE OF Target). A conforming issuer emits one
|
|
674
|
-
// Targets, but users MUST accept several. proxying additionally forbids the targetCert [2] alternative.
|
|
675
541
|
function _seqOfTargets(buf, C, allowTargetCert) {
|
|
676
542
|
var kids = _seqChildren(buf, C, "SEQUENCE OF Targets");
|
|
677
543
|
if (!kids.length) throw NS.E(C, "a SEQUENCE OF Targets must be non-empty");
|
|
@@ -680,9 +546,6 @@ function _seqOfTargets(buf, C, allowTargetCert) {
|
|
|
680
546
|
function _targetInformation(buf) { return _seqOfTargets(buf, "attrcert/bad-targets", true); }
|
|
681
547
|
function _acProxying(buf) { return _seqOfTargets(buf, "attrcert/bad-proxy-info", false); }
|
|
682
548
|
|
|
683
|
-
// AAControls ::= SEQUENCE { pathLenConstraint INTEGER (0..MAX) OPTIONAL, permittedAttrs [0] AttrSpec
|
|
684
|
-
// OPTIONAL, excludedAttrs [1] AttrSpec OPTIONAL, permitUnSpecified BOOLEAN DEFAULT TRUE }.
|
|
685
|
-
// AttrSpec ::= SEQUENCE OF OBJECT IDENTIFIER (the [0]/[1] IMPLICIT tag replaces the SEQUENCE tag).
|
|
686
549
|
function _acAttrSpec(node, C) {
|
|
687
550
|
if (!node.children) throw NS.E(C, "an AttrSpec must be a SEQUENCE OF OBJECT IDENTIFIER");
|
|
688
551
|
return node.children.map(function (o) {
|
|
@@ -714,12 +577,7 @@ _AC_EXT_DECODERS[_Oav("noRevAvail")] = _noRevAvail;
|
|
|
714
577
|
_AC_EXT_DECODERS[_Oav("aaControls")] = _aaControls;
|
|
715
578
|
_AC_EXT_DECODERS[_Oav("acProxying")] = _acProxying;
|
|
716
579
|
|
|
717
|
-
// @internal
|
|
718
|
-
// the parser runs, so the attrcert-sign escape hatches (a caller's pre-encoded Attribute / Extension DER)
|
|
719
|
-
// cannot embed a structurally-malformed recognized value the strict parser would then reject. `type` /
|
|
720
|
-
// `extnOid` are dotted-OID strings; `valueDer` / `extnValueDer` are the raw AttributeValue / extnValue
|
|
721
|
-
// content Buffers (exactly what the parse loop passes). An unrecognized type returns null (stays opaque,
|
|
722
|
-
// no validation); a recognized-but-malformed value throws the frozen attrcert/bad-* code.
|
|
580
|
+
// @internal
|
|
723
581
|
function validateAttributeValue(type, valueDer) {
|
|
724
582
|
var dec = _ATTR_VALUE_DECODERS[type];
|
|
725
583
|
return dec ? dec(valueDer) : null;
|