@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.
Files changed (112) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/lib/acme.js +59 -815
  3. package/lib/asn1-der.js +7 -245
  4. package/lib/attrcert-sign.js +12 -260
  5. package/lib/attrcert-verify.js +1 -7
  6. package/lib/byte-reader.js +0 -8
  7. package/lib/byte-writer.js +0 -11
  8. package/lib/cbor-det.js +0 -54
  9. package/lib/cmc-build.js +15 -357
  10. package/lib/cmc-verify.js +6 -239
  11. package/lib/cmp-build.js +41 -317
  12. package/lib/cmp-session.js +73 -760
  13. package/lib/cmp-verify.js +32 -488
  14. package/lib/cms-compress.js +3 -32
  15. package/lib/cms-decrypt.js +29 -294
  16. package/lib/cms-encrypt.js +14 -234
  17. package/lib/cms-sign.js +29 -324
  18. package/lib/cms-verify.js +9 -500
  19. package/lib/composite-kem.js +2 -102
  20. package/lib/composite-sig.js +1 -77
  21. package/lib/constants.js +0 -249
  22. package/lib/crl-sign.js +9 -237
  23. package/lib/crl-verify.js +1 -10
  24. package/lib/crmf-sign.js +19 -198
  25. package/lib/crmf-verify.js +1 -12
  26. package/lib/csr-sign.js +3 -34
  27. package/lib/csr-verify.js +1 -12
  28. package/lib/ct.js +28 -253
  29. package/lib/edwards-point.js +10 -44
  30. package/lib/est.js +28 -764
  31. package/lib/framework-error.js +4 -182
  32. package/lib/guard-all.js +1 -58
  33. package/lib/guard-async.js +1 -36
  34. package/lib/guard-bytes.js +6 -650
  35. package/lib/guard-compress.js +5 -102
  36. package/lib/guard-crypto.js +1 -40
  37. package/lib/guard-der.js +2 -93
  38. package/lib/guard-encoding.js +2 -60
  39. package/lib/guard-header.js +1 -36
  40. package/lib/guard-identifier.js +7 -531
  41. package/lib/guard-intrinsic.js +1 -150
  42. package/lib/guard-json.js +10 -73
  43. package/lib/guard-limits.js +1 -77
  44. package/lib/guard-list.js +1 -49
  45. package/lib/guard-name.js +3 -209
  46. package/lib/guard-parsed.js +7 -335
  47. package/lib/guard-range.js +1 -71
  48. package/lib/guard-secret.js +1 -102
  49. package/lib/guard-text.js +1 -64
  50. package/lib/guard-time.js +1 -97
  51. package/lib/hpke.js +3 -105
  52. package/lib/http-digest.js +14 -142
  53. package/lib/http-retry-after.js +1 -47
  54. package/lib/http-transport.js +21 -131
  55. package/lib/inspect.js +30 -284
  56. package/lib/ip-utils.js +6 -47
  57. package/lib/jose.js +7 -142
  58. package/lib/key.js +2 -67
  59. package/lib/lint.js +9 -194
  60. package/lib/merkle.js +1 -27
  61. package/lib/mime.js +9 -82
  62. package/lib/ocsp-request-verify.js +1 -14
  63. package/lib/ocsp-verify.js +1 -82
  64. package/lib/ocsp.js +11 -169
  65. package/lib/oid.js +5 -337
  66. package/lib/path-validate.js +103 -1492
  67. package/lib/pbes2.js +2 -89
  68. package/lib/pkcs12-build.js +31 -379
  69. package/lib/pki-build.js +64 -290
  70. package/lib/rc2.js +2 -18
  71. package/lib/rfc3339.js +4 -27
  72. package/lib/scep.js +140 -286
  73. package/lib/schema-all.js +0 -122
  74. package/lib/schema-attrcert.js +4 -146
  75. package/lib/schema-c509.js +153 -802
  76. package/lib/schema-cmc.js +5 -220
  77. package/lib/schema-cmp.js +2 -223
  78. package/lib/schema-cms.js +13 -427
  79. package/lib/schema-crl.js +5 -68
  80. package/lib/schema-crmf.js +6 -167
  81. package/lib/schema-csr.js +1 -54
  82. package/lib/schema-csrattrs.js +2 -87
  83. package/lib/schema-engine.js +0 -152
  84. package/lib/schema-ocsp.js +0 -117
  85. package/lib/schema-pkcs12.js +2 -93
  86. package/lib/schema-pkcs8.js +3 -35
  87. package/lib/schema-pkix.js +24 -655
  88. package/lib/schema-smime.js +0 -54
  89. package/lib/schema-tsp.js +3 -99
  90. package/lib/schema-x509.js +4 -63
  91. package/lib/shbs.js +11 -95
  92. package/lib/sign-scheme.js +2 -97
  93. package/lib/sigstore.js +9 -169
  94. package/lib/sleep.js +2 -8
  95. package/lib/smime.js +15 -408
  96. package/lib/tls-cert-compress.js +0 -62
  97. package/lib/trust.js +19 -185
  98. package/lib/tsp-sign.js +16 -270
  99. package/lib/validator-all.js +1 -30
  100. package/lib/validator-attcert.js +2 -46
  101. package/lib/validator-cose.js +2 -153
  102. package/lib/validator-keydesc.js +1 -37
  103. package/lib/validator-sig.js +1 -46
  104. package/lib/validator-tls.js +1 -88
  105. package/lib/validator-tpm.js +19 -122
  106. package/lib/verify-seam.js +1 -24
  107. package/lib/webauthn-mds.js +3 -400
  108. package/lib/webauthn.js +12 -833
  109. package/lib/webcrypto.js +5 -485
  110. package/lib/x509-sign.js +4 -108
  111. package/package.json +1 -1
  112. package/sbom.cdx.json +6 -6
@@ -16,16 +16,6 @@
16
16
  * @spec RFC 5755
17
17
  * @card Build and sign an RFC 5755 attribute certificate as an Attribute Authority.
18
18
  */
19
- //
20
- // RFC 5755 is DEFINITIONS IMPLICIT TAGS (App. B): a context [n] on a non-CHOICE component replaces the
21
- // underlying tag (its children are the component's fields: Holder [0]/[1]/[2], AttCertIssuer v2Form [0],
22
- // RoleSyntax roleAuthority [0], IetfAttrSyntax policyAuthority [0], AAControls [0]/[1]), built with
23
- // b.contextConstructed(n, ...); a context [n] wrapping a GeneralName CHOICE (roleName [1], Target [0]/[1])
24
- // is EXPLICIT, built with b.explicit(n, ...). The signature algorithm resolves from the AA public key
25
- // through the shared sign-scheme registry (RSA / ECDSA / EdDSA / ML-DSA / SLH-DSA / composite). The name /
26
- // GeneralName / extension / SPKI encoders + the post-sign self-check are the shared lib/pki-build
27
- // primitives; the AC-specific structures are the byte-exact inverse of the schema-attrcert.js readers,
28
- // which re-validate every emitted structure on the round trip.
29
19
 
30
20
  var asn1 = require("./asn1-der");
31
21
  var oid = require("./oid");
@@ -34,13 +24,10 @@ var x509 = require("./schema-x509");
34
24
  var signScheme = require("./sign-scheme");
35
25
  var guard = require("./guard-all");
36
26
  var intrinsic = require("./guard-intrinsic");
37
- // Membership is asked through an operation taken at load. Written out, the question reads two
38
- // replaceable properties to answer one thing, and either answering true admits a name the table
39
- // never carried -- here, an unrecognized critical extension counted as one this profile supports.
40
27
  var _hasOwn = intrinsic.hasOwn;
41
28
  var pkix = require("./schema-pkix");
42
29
  var schema = require("./schema-engine");
43
- require("./path-validate"); // side-effect: path-validate injects its signature engine into attrcert-verify at load
30
+ require("./path-validate");
44
31
  var attrcertVerify = require("./attrcert-verify");
45
32
  var pkiBuild = require("./pki-build");
46
33
  var frameworkError = require("./framework-error");
@@ -58,20 +45,12 @@ var _b = pkiBuild.makeBuilder({
58
45
  NAME_SCHEMA: pkix.name(NS), SPKI_SCHEMA: pkix.spki(NS), EXT_DECODERS: EXT_DECODERS,
59
46
  });
60
47
 
61
- // The recognized spec keys; an unknown key is a typo and throws at config-time (a custom attribute /
62
- // extension is passed as pre-encoded DER via the array form).
63
48
  var KNOWN_SPEC_KEYS = { holder: 1, notBeforeTime: 1, notAfterTime: 1, serialNumber: 1, attributes: 1, extensions: 1 };
64
49
  var KNOWN_HOLDER_KEYS = { entityName: 1, baseCertificateID: 1, fromCertificate: 1, objectDigestInfo: 1 };
65
- // object key -> the registered OID name of the AC attribute type it emits.
66
50
  var ATTR_OID_NAME = {
67
51
  role: "role", clearance: "clearance", group: "group", chargingIdentity: "chargingIdentity",
68
52
  accessIdentity: "accessIdentity", authenticationInfo: "authenticationInfo",
69
53
  };
70
- // object key -> { oid name, critical } of the AC / AA extension it emits, with the RFC 5755 criticality:
71
- // auditIdentity MUST be critical (sec. 4.3.1), targetInformation MUST be critical (sec. 4.3.2), proxying
72
- // MUST be critical (sec. 7.2), noRevAvail MUST be non-critical (sec. 4.3.6), authorityKeyIdentifier MUST
73
- // be non-critical (sec. 4.3.3); AAControls MAY be critical (sec. 7.4) and is emitted critical as the safer
74
- // default for a delegation-constraint extension (a verifier that cannot process it MUST reject the AC).
75
54
  var EXT_META = {
76
55
  auditIdentity: { name: "acAuditIdentity", critical: true },
77
56
  targetInformation: { name: "targetInformation", critical: true },
@@ -80,43 +59,29 @@ var EXT_META = {
80
59
  acProxying: { name: "acProxying", critical: true },
81
60
  authorityKeyIdentifier: { name: "authorityKeyIdentifier", critical: false },
82
61
  };
83
- // The RFC 5755-mandated criticality per extension OID (from EXT_META), enforced on the pre-encoded array
84
- // hatch so an escape-hatch extension cannot ship with a criticality the profile forbids.
85
62
  var REQUIRED_CRITICALITY = {};
86
63
  Object.keys(EXT_META).forEach(function (k) { REQUIRED_CRITICALITY[O(EXT_META[k].name)] = EXT_META[k].critical; });
87
- // ClassList ::= BIT STRING { unmarked(0) .. topSecret(5) } (RFC 5755 sec. 4.4.4), the encode inverse of
88
- // the schema-attrcert.js _CLASSLIST_NAMES decode array; DEFAULT {unclassified} (bit 1) is omitted.
89
64
  var CLASSLIST_BIT = { unmarked: 0, unclassified: 1, restricted: 2, confidential: 3, secret: 4, topSecret: 5 };
90
65
 
91
- var _tbsNameBytes = pkiBuild.tbsNameField; // the AA issuerName / holder baseCertificateID chain exactly to a cert's DN
92
- // Parse a certificate DER/PEM (or accept a parsed certificate), re-typing a raw x509/* parse fault to the
93
- // attrcert domain so a malformed AA cert / holder cert surfaces attrcert/*, not a foreign CertificateError.
66
+ var _tbsNameBytes = pkiBuild.tbsNameField;
94
67
  function _parseCert(cert, what) {
95
- // Re-derived from the bytes its parser read. Issuer and serial together ARE the Holder's identity,
96
- // so a certificate assembled from parts could bind an attribute certificate to a holder that no
97
- // issuer ever named.
98
68
  return guard.parsed.acceptDerived(cert, "certificate", function (bytes) {
99
69
  try { return x509.parse(bytes); }
100
70
  catch (e) { if (e instanceof AttrCertError) throw e; throw _err("attrcert/bad-input", what + " is not a well-formed certificate", e); }
101
71
  }, _err, "attrcert/bad-input", what);
102
72
  }
103
- // The raw content octets of an OBJECT IDENTIFIER (past its own tag+len): the body of a [0] IMPLICIT OID.
104
73
  function _oidContent(name) {
105
74
  var dotted = O(name) || name;
106
75
  var enc;
107
76
  try { enc = b.oid(dotted); } catch (e) { throw _err("attrcert/bad-input", "not a valid object identifier: " + JSON.stringify(name), e); }
108
77
  return asn1.decode(enc).content;
109
78
  }
110
- // A GeneralNames spec (a single GeneralName object or an array of them) -> the member list.
111
79
  function _gnList(spec) {
112
80
  if (Array.isArray(spec)) return spec;
113
81
  return [spec];
114
82
  }
115
83
 
116
- // ---- structural encoders (byte-exact inverses of the schema-attrcert.js readers) ----
117
84
 
118
- // IssuerSerial ::= SEQUENCE { issuer GeneralNames, serial CertificateSerialNumber, issuerUID BIT STRING
119
- // OPTIONAL }. Returns the content (concatenated field TLVs) so a [n] IMPLICIT caller wraps it directly.
120
85
  function _issuerSerialContent(is) {
121
86
  if (!is || typeof is !== "object" || Buffer.isBuffer(is)) throw _err("attrcert/bad-input", "baseCertificateID must be an object { issuer, serial, issuerUID? }");
122
87
  if (is.issuer == null) throw _err("attrcert/bad-input", "baseCertificateID.issuer (a GeneralNames) is required");
@@ -127,9 +92,6 @@ function _issuerSerialContent(is) {
127
92
  }
128
93
  return Buffer.concat(parts);
129
94
  }
130
- // ObjectDigestInfo ::= SEQUENCE { digestedObjectType ENUMERATED, otherObjectTypeID OID OPTIONAL,
131
- // digestAlgorithm AlgorithmIdentifier, objectDigest BIT STRING }. otherObjectTypes(2) is forbidden (sec.
132
- // 7.3), so otherObjectTypeID is never emitted. Returns the content for a [n] IMPLICIT caller.
133
95
  var ODT_CODE = { publicKey: 0, publicKeyCert: 1 };
134
96
  function _objectDigestInfoContent(odi) {
135
97
  if (!odi || typeof odi !== "object" || Buffer.isBuffer(odi)) throw _err("attrcert/bad-input", "objectDigestInfo must be an object");
@@ -142,44 +104,31 @@ function _objectDigestInfoContent(odi) {
142
104
  try { algTlv = b.sequence([b.oid(algOid)]); } catch (e) { throw _err("attrcert/bad-input", "objectDigestInfo.digestAlgorithm is not a valid algorithm identifier", e); }
143
105
  return Buffer.concat([b.enumerated(BigInt(code)), algTlv, b.bitString(odi.objectDigest, 0)]);
144
106
  }
145
- // Holder ::= SEQUENCE { baseCertificateID [0] IMPLICIT IssuerSerial, entityName [1] IMPLICIT GeneralNames,
146
- // objectDigestInfo [2] IMPLICIT ObjectDigestInfo }, exactly one form (the profile binds a real holder).
147
107
  function _encodeHolder(holder) {
148
108
  if (!holder || typeof holder !== "object" || Buffer.isBuffer(holder)) throw _err("attrcert/bad-input", "holder must be an object with exactly one form");
149
109
  guard.identifier.assertKnownKeys(holder, KNOWN_HOLDER_KEYS, _err, "attrcert/bad-input", "unknown holder form ");
150
110
  var forms = Object.keys(holder).filter(function (k) { return holder[k] != null; });
151
111
  if (forms.length !== 1) throw _err("attrcert/bad-input", "holder must carry exactly one form (entityName, baseCertificateID, fromCertificate, or objectDigestInfo), got " + forms.length);
152
112
  if (holder.entityName != null) {
153
- // entityName [1] IMPLICIT GeneralNames -> the [1] node's children ARE the GeneralName members.
154
113
  return b.sequence([_b.encodeGeneralNames(_gnList(holder.entityName), 1)]);
155
114
  }
156
115
  if (holder.baseCertificateID != null) {
157
116
  return b.sequence([b.contextConstructed(0, _issuerSerialContent(holder.baseCertificateID))]);
158
117
  }
159
118
  if (holder.fromCertificate != null) {
160
- // Bind to a public-key certificate's identity: baseCertificateID = { issuer = the PKC's issuer DN as a
161
- // directoryName, serial = the PKC serialNumber } (RFC 5755 sec. 4.1 / 7.3).
162
- // Both halves come from the signed bytes. issuer and serial together are the identity, so deriving
163
- // the issuer from tbsBytes while reading the serial off the object let the two name different
164
- // certificates: a Holder with a genuine issuer DN and whatever serial the caller wrote.
165
119
  var pkc = _parseCert(holder.fromCertificate, "holder.fromCertificate");
166
120
  var content = _issuerSerialContent({ issuer: [{ directoryName: _tbsNameBytes(pkc, "issuer") }], serial: pkiBuild.tbsSerialNumber(pkc) });
167
121
  return b.sequence([b.contextConstructed(0, content)]);
168
122
  }
169
- // objectDigestInfo [2] IMPLICIT ObjectDigestInfo.
170
123
  return b.sequence([b.contextConstructed(2, _objectDigestInfoContent(holder.objectDigestInfo))]);
171
124
  }
172
125
 
173
- // AttCertIssuer v2Form [0] IMPLICIT V2Form { issuerName GeneralNames }, where issuerName is exactly one
174
- // directoryName [4] over a non-empty DN (RFC 5755 sec. 4.2.3). The [0] replaces the V2Form SEQUENCE tag.
175
126
  function _encodeV2FormIssuer(dnSpec) {
176
127
  var dnDer = _b.encodeName(dnSpec == null ? [] : dnSpec);
177
128
  if (_b.isEmptyName(dnDer)) throw _err("attrcert/bad-issuer-name", "the AA issuerName must be a non-empty distinguished name (RFC 5755 sec. 4.2.3)");
178
- var issuerNameGns = _b.encodeGeneralNames([{ directoryName: dnDer }]); // a universal SEQUENCE OF one directoryName
129
+ var issuerNameGns = _b.encodeGeneralNames([{ directoryName: dnDer }]);
179
130
  return b.contextConstructed(0, issuerNameGns);
180
131
  }
181
- // AttCertValidityPeriod ::= SEQUENCE { notBeforeTime GeneralizedTime, notAfterTime GeneralizedTime }
182
- // (RFC 5755 sec. 4.2.6): always GeneralizedTime, never UTCTime; reject an inverted window.
183
132
  function _encodeValidity(notBefore, notAfter) {
184
133
  guard.time.assertValid(notBefore, _err, "attrcert/bad-input", "notBeforeTime");
185
134
  guard.time.assertValid(notAfter, _err, "attrcert/bad-input", "notAfterTime");
@@ -188,10 +137,7 @@ function _encodeValidity(notBefore, notAfter) {
188
137
  return b.sequence([b.generalizedTime(notBefore), b.generalizedTime(notAfter)]);
189
138
  }
190
139
 
191
- // ---- attribute-value encoders (sec. 4.4) ----
192
140
 
193
- // RoleSyntax ::= SEQUENCE { roleAuthority [0] IMPLICIT GeneralNames OPTIONAL, roleName [1] EXPLICIT
194
- // GeneralName }. roleName is a GeneralName CHOICE -> EXPLICIT; roleAuthority a GeneralNames -> IMPLICIT [0].
195
141
  function _encodeRole(role) {
196
142
  if (!role || typeof role !== "object" || role.roleName == null) throw _err("attrcert/bad-input", "role must be an object with a roleName GeneralName");
197
143
  var parts = [];
@@ -199,8 +145,6 @@ function _encodeRole(role) {
199
145
  parts.push(b.explicit(1, _b.encodeGeneralName(role.roleName)));
200
146
  return b.sequence(parts);
201
147
  }
202
- // Clearance ::= SEQUENCE { policyId OID, classList BIT STRING DEFAULT {unclassified}, securityCategories
203
- // SET OF SecurityCategory OPTIONAL } (RFC 5755 sec. 4.4.4). A classList equal to the DEFAULT is omitted.
204
148
  function _encodeClearance(cl) {
205
149
  if (!cl || typeof cl !== "object" || cl.policyId == null) throw _err("attrcert/bad-input", "clearance must be an object with a policyId OID");
206
150
  var parts;
@@ -212,7 +156,6 @@ function _encodeClearance(cl) {
212
156
  if (pos == null) throw _err("attrcert/bad-input", "unknown clearance class " + JSON.stringify(n));
213
157
  return pos;
214
158
  });
215
- // A present classList equal to the DEFAULT {unclassified} is non-canonical DER (the parser rejects it).
216
159
  var isDefault = positions.length === 1 && positions[0] === CLASSLIST_BIT.unclassified;
217
160
  if (!isDefault) parts.push(b.namedBitString(positions));
218
161
  }
@@ -222,9 +165,6 @@ function _encodeClearance(cl) {
222
165
  }
223
166
  return b.sequence(parts);
224
167
  }
225
- // SecurityCategory ::= SEQUENCE { type [0] IMPLICIT OBJECT IDENTIFIER, value [1] EXPLICIT ANY }. The
226
- // value is one element the parser EXPLICIT [1] wrapper carries verbatim, so it MUST be a single
227
- // well-formed DER TLV -- validate it (no malformed / multi-element / trailing bytes) before signing.
228
168
  function _encodeSecurityCategory(sc) {
229
169
  if (!sc || typeof sc !== "object" || sc.type == null || !Buffer.isBuffer(sc.value)) throw _err("attrcert/bad-input", "each securityCategory must be { type: OID, value: DER Buffer }");
230
170
  var node;
@@ -232,8 +172,6 @@ function _encodeSecurityCategory(sc) {
232
172
  if (node.bytes.length !== sc.value.length) throw _err("attrcert/bad-input", "securityCategory value must be exactly one DER element (no trailing bytes)");
233
173
  return b.sequence([b.contextPrimitive(0, _oidContent(sc.type)), b.explicit(1, sc.value)]);
234
174
  }
235
- // IetfAttrSyntax ::= SEQUENCE { policyAuthority [0] IMPLICIT GeneralNames OPTIONAL, values SEQUENCE OF
236
- // CHOICE { octets OCTET STRING, oid OBJECT IDENTIFIER, string UTF8String } } (group / chargingIdentity).
237
175
  function _encodeIetfAttrSyntax(ia) {
238
176
  if (!ia || typeof ia !== "object" || !Array.isArray(ia.values) || !ia.values.length) throw _err("attrcert/bad-input", "an IetfAttrSyntax attribute must be an object with a non-empty values array");
239
177
  var parts = [];
@@ -247,8 +185,6 @@ function _encodeIetfAttrSyntax(ia) {
247
185
  })));
248
186
  return b.sequence(parts);
249
187
  }
250
- // SvceAuthInfo ::= SEQUENCE { service GeneralName, ident GeneralName, authInfo OCTET STRING OPTIONAL }.
251
- // authenticationInfo (sec. 4.4.1) permits authInfo; accessIdentity (sec. 4.4.2) MUST omit it.
252
188
  function _encodeSvceAuthInfo(sai, authInfoAllowed, label) {
253
189
  if (!sai || typeof sai !== "object" || sai.service == null || sai.ident == null) throw _err("attrcert/bad-input", label + " must be an object with a service and an ident GeneralName");
254
190
  var parts = [_b.encodeGeneralName(sai.service), _b.encodeGeneralName(sai.ident)];
@@ -269,25 +205,17 @@ var ATTR_VALUE_ENCODER = {
269
205
  accessIdentity: function (v) { return _encodeSvceAuthInfo(v, false, "accessIdentity"); },
270
206
  };
271
207
 
272
- // ---- extension-value encoders (sec. 4.3 / 7.4) ----
273
208
 
274
- // Target ::= CHOICE { targetName [0] EXPLICIT GeneralName, targetGroup [1] EXPLICIT GeneralName }
275
- // (targetCert [2] is out of v1 scope; use a pre-encoded Extension DER for a targetCert-bearing value).
276
209
  function _encodeTarget(t) {
277
210
  if (!t || typeof t !== "object") throw _err("attrcert/bad-input", "each target must be { targetName } or { targetGroup }");
278
211
  if (t.targetName != null) return b.explicit(0, _b.encodeGeneralName(t.targetName));
279
212
  if (t.targetGroup != null) return b.explicit(1, _b.encodeGeneralName(t.targetGroup));
280
213
  throw _err("attrcert/bad-input", "each target must be { targetName } or { targetGroup }");
281
214
  }
282
- // targetInformation / acProxying value ::= SEQUENCE OF Targets, Targets ::= SEQUENCE OF Target. A
283
- // conformant issuer emits exactly one Targets.
284
215
  function _encodeSeqOfTargets(targets) {
285
216
  if (!Array.isArray(targets) || !targets.length) throw _err("attrcert/bad-input", "a targets value must be a non-empty array of targets");
286
217
  return b.sequence([b.sequence(targets.map(_encodeTarget))]);
287
218
  }
288
- // AAControls ::= SEQUENCE { pathLenConstraint INTEGER OPTIONAL, permittedAttrs [0] IMPLICIT AttrSpec
289
- // OPTIONAL, excludedAttrs [1] IMPLICIT AttrSpec OPTIONAL, permitUnSpecified BOOLEAN DEFAULT TRUE }.
290
- // AttrSpec ::= SEQUENCE OF OID (the [0]/[1] IMPLICIT tag replaces the SEQUENCE tag).
291
219
  function _attrSpec(names, tag, label) {
292
220
  if (!Array.isArray(names)) throw _err("attrcert/bad-input", "aaControls." + label + " must be an array of attribute-type OIDs");
293
221
  var oids = names.map(function (n) {
@@ -299,19 +227,15 @@ function _encodeAAControls(aac) {
299
227
  if (!aac || typeof aac !== "object" || Buffer.isBuffer(aac)) throw _err("attrcert/bad-input", "aaControls must be an object");
300
228
  var parts = [];
301
229
  if (aac.pathLenConstraint != null) {
302
- // The parser narrows pathLenConstraint through guard.range.uint31 (0..2^31-1), so a larger value the
303
- // builder emits would fail the round trip, so bound it to the same range at build time.
304
230
  if (typeof aac.pathLenConstraint !== "number" || !Number.isInteger(aac.pathLenConstraint) || aac.pathLenConstraint < 0 || aac.pathLenConstraint > 0x7fffffff) throw _err("attrcert/bad-input", "aaControls.pathLenConstraint must be an integer in 0..2147483647 (RFC 5755 sec. 7.4)");
305
231
  parts.push(b.integer(BigInt(aac.pathLenConstraint)));
306
232
  }
307
233
  if (aac.permittedAttrs != null) parts.push(_attrSpec(aac.permittedAttrs, 0, "permittedAttrs"));
308
234
  if (aac.excludedAttrs != null) parts.push(_attrSpec(aac.excludedAttrs, 1, "excludedAttrs"));
309
- // permitUnSpecified DEFAULT TRUE -- a TRUE value equals the DEFAULT and is omitted (non-canonical DER).
310
235
  if (aac.permitUnSpecified === false) parts.push(b.boolean(false));
311
236
  else if (aac.permitUnSpecified != null && aac.permitUnSpecified !== true) throw _err("attrcert/bad-input", "aaControls.permitUnSpecified must be a boolean");
312
237
  return b.sequence(parts);
313
238
  }
314
- // Emit a single AC / AA extension's value DER from its object-form spec.
315
239
  function _extensionValue(key, val, aaSpki) {
316
240
  switch (key) {
317
241
  case "auditIdentity":
@@ -326,11 +250,7 @@ function _extensionValue(key, val, aaSpki) {
326
250
  }
327
251
  }
328
252
 
329
- // ---- attributes / extensions assembly ----
330
253
 
331
- // attributes ::= SEQUENCE OF Attribute (RFC 5755 sec. 4.2.7): non-empty, each AttributeType OID unique;
332
- // or an array of pre-encoded Attribute DER (validated in shape AND value). Each Attribute value SET is
333
- // DER-sorted.
334
254
  function _buildAttributes(attrSpec) {
335
255
  var attrs = [], seen = {};
336
256
  function add(type, valueTlv) {
@@ -349,8 +269,6 @@ function _buildAttributes(attrSpec) {
349
269
  if (!n.children[1].children || !n.children[1].children.length) throw _err("attrcert/bad-input", "pre-encoded attribute [" + i + "] value SET must contain at least one value");
350
270
  if (seen[at]) throw _err("attrcert/duplicate-attribute", "duplicate " + (oid.name(at) || at) + " attribute (RFC 5755 sec. 4.2.7)");
351
271
  seen[at] = true;
352
- // A recognized AC attribute type is validated against its real sec. 4.4 value decoder; an
353
- // unrecognized type stays opaque (the parser also leaves it opaque).
354
272
  n.children[1].children.forEach(function (valNode) {
355
273
  try { attrcert.validateAttributeValue(at, valNode.bytes); }
356
274
  catch (err) { if (err instanceof AttrCertError) throw err; throw _err("attrcert/bad-input", "pre-encoded " + (oid.name(at) || at) + " attribute value is malformed", err); }
@@ -371,12 +289,6 @@ function _buildAttributes(attrSpec) {
371
289
  return b.sequence(attrs);
372
290
  }
373
291
 
374
- // extensions ::= SEQUENCE OF Extension (RFC 5755 sec. 4.2.9): the recognized object form, or an array
375
- // of pre-encoded Extension DER. At most one instance of a particular extension OID. Returns a universal
376
- // RFC 5755 sec. 6 defines two revocation schemes and closes by making them exclusive: "An AC MUST
377
- // NOT contain both a noRevAvail extension and a 'pointer in AC'." Held over the OIDs an AC ends up
378
- // carrying, so BOTH extension forms meet it -- the object form and the pre-encoded array form, which
379
- // is the one that can name a pointer at all. `seen` is the OID-keyed set each branch already builds.
380
292
  function _assertRevocationSchemesExclusive(seen) {
381
293
  if (!_hasOwn(seen, O("noRevAvail"))) return;
382
294
  var names = Object.keys(REVOCATION_POINTERS);
@@ -388,7 +300,6 @@ function _assertRevocationSchemesExclusive(seen) {
388
300
  }
389
301
  }
390
302
 
391
- // SEQUENCE OF Extension, or null when none are requested.
392
303
  function _buildExtensions(extSpec, aaSpki) {
393
304
  if (extSpec == null) return null;
394
305
  if (Array.isArray(extSpec)) {
@@ -401,14 +312,10 @@ function _buildExtensions(extSpec, aaSpki) {
401
312
  var extnId = asn1.read.oid(n.children[0]);
402
313
  if (seenA[extnId]) throw _err("attrcert/bad-input", "duplicate extension " + extnId + " (RFC 5755 sec. 4.2.9)");
403
314
  seenA[extnId] = true;
404
- // A recognized RFC 5755-profiled extension MUST carry its mandated criticality even via the escape
405
- // hatch (assertValidExtension already rejected an explicit critical=FALSE, so 3 children == critical).
406
315
  var required = REQUIRED_CRITICALITY[extnId];
407
316
  if (required != null && (n.children.length === 3) !== required) {
408
317
  throw _err("attrcert/bad-input", "pre-encoded " + (oid.name(extnId) || extnId) + " extension must be marked " + (required ? "critical" : "non-critical") + " (RFC 5755)");
409
318
  }
410
- // Validate a recognized value against its real decoder: a cert-style AA extension (AKI / CRLDP /
411
- // AIA) through the RFC 5280 sec. 4.2.1 table, an AC-specific extension through the sec. 4.3 table.
412
319
  var extnValue = asn1.read.octetString(n.children[n.children.length - 1]);
413
320
  try {
414
321
  if (EXT_DECODERS[extnId]) EXT_DECODERS[extnId](extnValue);
@@ -425,7 +332,7 @@ function _buildExtensions(extSpec, aaSpki) {
425
332
  });
426
333
  var out = [], seen = {};
427
334
  Object.keys(extSpec).forEach(function (k) {
428
- if (extSpec[k] == null) return; // a null/omitted extension is not requested (matches the attribute form)
335
+ if (extSpec[k] == null) return;
429
336
  var meta = EXT_META[k], eOid = O(meta.name);
430
337
  if (seen[eOid]) throw _err("attrcert/bad-input", "duplicate extension " + JSON.stringify(k) + " (RFC 5755 sec. 4.2.9)");
431
338
  seen[eOid] = true;
@@ -446,18 +353,18 @@ function _buildExtensions(extSpec, aaSpki) {
446
353
  * @related pki.schema.attrcert.parse, pki.x509.sign
447
354
  *
448
355
  * Build, sign, and DER-encode an RFC 5755 attribute certificate as an Attribute Authority. `spec`
449
- * describes the certificate -- `holder` (exactly one form: `entityName`, `baseCertificateID`,
356
+ * describes the certificate: `holder` (exactly one form: `entityName`, `baseCertificateID`,
450
357
  * `fromCertificate` to bind a public-key certificate's identity, or `objectDigestInfo`), `notBeforeTime`
451
358
  * / `notAfterTime` (`Date`s -> GeneralizedTime), an optional `serialNumber` (positive, <= 20 octets;
452
359
  * a random 20-octet serial is generated when omitted), `attributes` (an object of the sec. 4.4 privilege
453
- * syntaxes -- role / clearance / group / chargingIdentity / accessIdentity / authenticationInfo -- or an
360
+ * syntaxes (role / clearance / group / chargingIdentity / accessIdentity / authenticationInfo), or an
454
361
  * array of pre-encoded Attribute DER), and optional `extensions` (an object of auditIdentity /
455
362
  * targetInformation / noRevAvail / aaControls / acProxying / authorityKeyIdentifier, or an array of
456
363
  * pre-encoded Extension DER). `issuer` is the signing AA: `{ cert, key }` (the AA certificate DER/PEM
457
364
  * and its private key) or `{ name, publicKey, key }` (an explicit issuer DN, AA SPKI DER, and key); an
458
365
  * attribute certificate is never self-signed. RFC 5755 section 6 defines two revocation schemes and
459
- * makes them exclusive -- "An AC MUST NOT contain both a noRevAvail extension and a 'pointer in AC'"
460
- * -- so `noRevAvail` beside a `crlDistributionPoints` or `authorityInfoAccess` extension is refused,
366
+ * makes them exclusive ("An AC MUST NOT contain both a noRevAvail extension and a 'pointer in AC'"),
367
+ * so `noRevAvail` beside a `crlDistributionPoints` or `authorityInfoAccess` extension is refused,
461
368
  * in the named form and the pre-encoded form alike. The signature algorithm is resolved from the AA key (RSA
462
369
  * PKCS#1 v1.5 or PSS, ECDSA, EdDSA, ML-DSA, SLH-DSA, or a composite arm), and the signature is verified
463
370
  * under the AA public key before the certificate is returned. Returns DER, or a PEM `ATTRIBUTE
@@ -485,8 +392,6 @@ function _buildExtensions(extSpec, aaSpki) {
485
392
  * pki.schema.attrcert.parse(ac).attributes[0].type; // the role attribute OID
486
393
  */
487
394
  function sign(spec, issuer, opts) {
488
- // Every caller-owned argument copied at entry and released when the call settles -- see the note
489
- // on the same call in x509-sign.
490
395
  return guard.bytes.fixedCall(AttrCertError, "attrcert/bad-input", [
491
396
  [spec, "the attribute-certificate spec"], [issuer, "the issuer"], [opts, "pki.attrcert.sign options"],
492
397
  ], _sign);
@@ -499,9 +404,6 @@ function _sign(spec, issuer, opts) {
499
404
  issuer = issuer || {};
500
405
  if (issuer.key == null) throw _err("attrcert/bad-input", "a signing key (issuer.key, the AA's WebCrypto CryptoKey or PKCS#8 private key DER/PEM) is required");
501
406
 
502
- // Resolve the AA issuer DN + signing-key SPKI. An attribute certificate is NEVER self-signed. No CA
503
- // gate on issuer.cert -- an AA is NOT a certificate authority (its PKC MUST NOT assert keyCertSign,
504
- // RFC 5755 sec. 4.5), so requiring cA/keyCertSign would reject every conformant AA certificate.
505
407
  var issuerDnSpec, aaSpki;
506
408
  if (issuer.cert != null) {
507
409
  var aaCert = _parseCert(issuer.cert, "issuer.cert");
@@ -521,21 +423,16 @@ function _sign(spec, issuer, opts) {
521
423
  var attributesDer = _buildAttributes(spec.attributes);
522
424
  var extsDer = _buildExtensions(spec.extensions, aaSpki);
523
425
 
524
- // Resolve the signature scheme from the AA (signing) key's SPKI -- the whole registry, for free.
525
426
  var scheme = signScheme.resolveSignScheme(_b.certLikeFromSpki(aaSpki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
526
427
 
527
- // AttributeCertificateInfo ::= SEQUENCE { version(bare INTEGER 1), holder, issuer, signature
528
- // AlgorithmIdentifier, serialNumber, attrCertValidityPeriod, attributes, [issuerUniqueID], [extensions] }.
529
- // signature == the outer signatureAlgorithm (RFC 5755 sec. 4.2.4), single source scheme.sigAlgId.
530
428
  var acinfoChildren = [
531
429
  b.integer(1n), holderDer, issuerDer, scheme.sigAlgId,
532
430
  _b.serialInteger(spec.serialNumber), validityDer, attributesDer,
533
431
  ];
534
- if (extsDer) acinfoChildren.push(extsDer); // issuerUniqueID omitted (sec. 4.2.8); extensions is a bare universal SEQUENCE
432
+ if (extsDer) acinfoChildren.push(extsDer);
535
433
  var acinfoDer = b.sequence(acinfoChildren);
536
434
 
537
435
  return signScheme.signOverTbs(scheme, issuer.key, acinfoDer, _signE).then(function (sig) {
538
- // The signature MUST verify under the AA public key (the AA proof); composite verifies both arms.
539
436
  return Promise.resolve(_b.assertSignatureVerifies(acinfoDer, sig, aaSpki, scheme)).then(function () {
540
437
  var acDer = b.sequence([acinfoDer, scheme.sigAlgId, b.bitString(sig, 0)]);
541
438
  return opts.pem ? attrcert.pemEncode(acDer, "ATTRIBUTE CERTIFICATE") : acDer;
@@ -547,15 +444,11 @@ function _sign(spec, issuer, opts) {
547
444
  }
548
445
 
549
446
  var KNOWN_VERIFY_OPTS = { time: 1, target: 1, revocationStatus: 1 };
550
- // The two answers a caller can give for RFC 5755 sec. 6, spelled out so a typo is refused instead of
551
- // read as the safe one. Built without a prototype, so an inherited name cannot answer the lookup.
552
447
  var REVOCATION_STATUS = Object.create(null);
553
448
  REVOCATION_STATUS.notRevoked = 1;
554
449
  REVOCATION_STATUS.revoked = 1;
555
450
  var _NAME_SCHEMA = pkix.name(NS);
556
451
 
557
- // A Name DER, read through the one Name reader, so every distinguished name this verb compares is
558
- // in the shape guard.name.dnEqual takes.
559
452
  function _readName(der, what) {
560
453
  try { return schema.walk(_NAME_SCHEMA, asn1.decode(der), NS).result; }
561
454
  catch (e) {
@@ -564,9 +457,6 @@ function _readName(der, what) {
564
457
  }
565
458
  }
566
459
 
567
- // The AC issuer's distinguished name. The parser has already established that issuerName holds
568
- // exactly one non-empty directoryName [4] (RFC 5755 sec. 4.2.3) and surfaces it as a raw node, so
569
- // the DN itself is one EXPLICIT unwrap away.
570
460
  function _acIssuerName(parsed) {
571
461
  var node = asn1.decode(parsed.issuer.v2Form.issuerName.names[0].bytes);
572
462
  if (!node.children || node.children.length !== 1) {
@@ -580,9 +470,6 @@ function _coerceAc(input) {
580
470
  "attrcert/bad-input", "the attribute certificate");
581
471
  }
582
472
 
583
- // The AC issuer this caller directly trusts as an AC issuer (RFC 5755 sec. 5, item 4). That is a
584
- // configuration decision the certificate cannot make for itself, so it is an argument, and an
585
- // argument this verb refuses to infer.
586
473
  function _resolveIssuer(issuer) {
587
474
  if (issuer == null || typeof issuer !== "object" || Buffer.isBuffer(issuer)) {
588
475
  throw _err("attrcert/bad-input", "an issuer { name, publicKey } is required -- RFC 5755 sec. 5 item 4 makes trusting an AC issuer the verifier's own configuration");
@@ -593,14 +480,6 @@ function _resolveIssuer(issuer) {
593
480
  if (issuer.name == null) {
594
481
  throw _err("attrcert/bad-input", "issuer.name (the distinguished name this verifier trusts as an AC issuer) is required");
595
482
  }
596
- // Every name form pki.attrcert.sign accepts for the issuing AA is a name this verb has to be able
597
- // to trust: a string, an array of RDNs, or raw Name DER. The forms come from the one Name encoder
598
- // both sides use, so an AC issued under a multi-RDN AA name is verifiable under that same name.
599
- //
600
- // The trusted name is compared as a distinguished name, never as a string: RFC 5280 sec. 7.1
601
- // identity is not string equality, and guard.name owns that comparison. Encoding the caller's
602
- // name and reading it back through the SAME Name reader the parser used puts both sides in the
603
- // one shape dnEqual takes.
604
483
  var trustedDer;
605
484
  try { trustedDer = _b.encodeName(issuer.name); }
606
485
  catch (e) {
@@ -608,44 +487,19 @@ function _resolveIssuer(issuer) {
608
487
  throw _err("attrcert/bad-input", "issuer.name is not a distinguished name", e);
609
488
  }
610
489
  var rdns = _readName(trustedDer, "issuer.name").rdns;
611
- // Checked on the decoded name, so every input form is held to it. An empty DN names no issuer, and
612
- // RFC 5755 sec. 4.2.3 requires the AC's own issuerName to be a non-empty distinguished name, so an
613
- // empty trusted name could never match a conformant AC and would only mask the caller's mistake.
614
490
  if (!rdns.length) {
615
491
  throw _err("attrcert/bad-input", "issuer.name is an empty distinguished name, which names no AC issuer (RFC 5755 sec. 4.2.3)");
616
492
  }
617
493
  return {
618
494
  rdns: rdns,
619
- // Copied, never viewed. Signature verification suspends this call, and the signature engine
620
- // holds this buffer across that suspension -- a composite arm keeps slices of it and imports
621
- // them only after its digest settles. A view would leave the trust key writable for that whole
622
- // window, so a caller could hand in an unrelated key of the same length, overwrite it with the
623
- // real issuer's while the digest ran, and be told the certificate verified under the key they
624
- // named. The verdict answers for the key the call was made with.
625
495
  spki: guard.bytes.snapshot(issuer.publicKey, AttrCertError, "attrcert/bad-input", "issuer.publicKey"),
626
496
  };
627
497
  }
628
498
 
629
- // RFC 5755 sec. 4.3.2: a targeted AC is valid only at the servers it names, and "servers not named
630
- // MUST reject the AC". An absent extension means untargeted, so there is nothing to check.
631
- //
632
- // Only the decoded targetName and targetGroup alternatives are compared. Searching the extension's
633
- // raw bytes for the caller's encoded GeneralName would also match a name nested inside a targetCert,
634
- // where it identifies the TARGET CERTIFICATE'S ISSUER rather than a target, and would then accept an
635
- // AC at a server it never named. A match against a targetGroup does count: sec. 4.3.2 targets "named
636
- // targets or groups", so a verifier presenting its group name is naming itself among them.
637
- //
638
- // The caller's GeneralName goes through the shared builder, then back through the SAME GeneralName
639
- // reader the parser used, so both sides of every comparison are the one decoded shape. Reading it
640
- // back rather than dereferencing a context node's `content` also keeps this off a field that is
641
- // null whenever the node is constructed.
642
499
  function _callerTarget(target) {
643
500
  return attrcert.readGeneralName(_b.encodeGeneralName(target), "attrcert/bad-input");
644
501
  }
645
502
 
646
- // RFC 5280 sec. 7.5: two mailboxes match when the local-part is an exact match AND the host-part
647
- // matches case-insensitively. The split is on the LAST "@", since a quoted local-part may contain
648
- // one; a value with no "@" has no host-part to fold and compares exactly.
649
503
  function _mailboxEqual(a, bx) {
650
504
  var i = a.lastIndexOf("@"), j = bx.lastIndexOf("@");
651
505
  if (i < 0 || j < 0) return a === bx;
@@ -653,37 +507,21 @@ function _mailboxEqual(a, bx) {
653
507
  a.slice(i + 1).toLowerCase() === bx.slice(j + 1).toLowerCase();
654
508
  }
655
509
 
656
- // Whether a target the AC names is this verifier, under the matching rule each GeneralName form
657
- // defines. A form whose rule this build does not implement compares exactly, which can refuse a
658
- // name a fuller comparison would accept and can never accept one it would refuse.
659
510
  function _generalNameMatches(entry, want) {
660
511
  if (!entry || entry.tagNumber !== want.tagNumber) return false;
661
512
  switch (entry.tagNumber) {
662
- // RFC 5280 sec. 7.2: "When comparing DNS names for equality, conforming implementations MUST
663
- // perform a case-insensitive exact match on the entire DNS name."
664
513
  case 2: return String(entry.value).toLowerCase() === String(want.value).toLowerCase();
665
- // sec. 7.5, as above.
666
514
  case 1: return _mailboxEqual(String(entry.value), String(want.value));
667
- // A directoryName is a distinguished name, and sec. 7.1 identity is not string equality, so it
668
- // goes through the one DN comparator rather than comparing the printed form.
669
515
  case 4:
670
516
  return !!(entry.value && want.value) &&
671
517
  guard.name.dnEqual(entry.value.rdns, want.value.rdns, _err, "attrcert/bad-input", "the target name");
672
- // sec. 7.4 makes a URI comparison a full RFC 3987 normalization: percent-encoding, path
673
- // segments and scheme-based rules, not merely lowercasing the scheme and host. A partial
674
- // normalization would be a guess that could match a URI it should not, so the encoded value is
675
- // compared as it stands. Re-open condition: an RFC 3987 normalizer in the toolkit.
676
518
  default:
677
519
  if (Buffer.isBuffer(entry.value) && Buffer.isBuffer(want.value)) return entry.value.equals(want.value);
678
520
  if (typeof entry.value === "string" && typeof want.value === "string") return entry.value === want.value;
679
- // A form whose decoded value is neither (otherName, ediPartyName, x400Address) has no
680
- // comparison here; the caller is told so rather than given a silent mismatch.
681
521
  return null;
682
522
  }
683
523
  }
684
524
 
685
- // `want` is the caller's target already decoded, so this runs against the target the call was made
686
- // with. See _fixVerifyOptions.
687
525
  function _checkTargeting(ac, want) {
688
526
  var ext = null;
689
527
  for (var i = 0; i < ac.extensions.length; i++) {
@@ -694,26 +532,7 @@ function _checkTargeting(ac, want) {
694
532
  return { checked: false, ok: false,
695
533
  reason: "this attribute certificate is targeted, and no opts.target names this verifier (RFC 5755 sec. 4.3.2)" };
696
534
  }
697
- // The extension's syntax is a SEQUENCE OF Targets, and its groups are FLATTENED rather than
698
- // required one by one. RFC 5755 sec. 4.3.2: "If more than one Targets element is found in an AC,
699
- // the extension MUST be treated as if all Target elements had been found within one Targets
700
- // element." An issuer conforming to the same paragraph produces only one group anyway, so the
701
- // nesting carries no meaning to honor; requiring a match in every group would refuse ACs the
702
- // paragraph says to accept.
703
535
  var groups = ext.decoded || [];
704
- // sec. 4.3.2 defines the check exactly: it "passes if the current server (recipient) is one of the
705
- // targetName fields in the Targets SEQUENCE, or if the current server is a member of one of the
706
- // targetGroup fields". The third arm is excluded by the same section -- "The targetCert CHOICE
707
- // within the Target structure is only present to allow future compatibility with [X.509-2000] and
708
- // MUST NOT be used" -- and the names inside it identify a certificate, not a target.
709
- //
710
- // An AC using it is refused before any match is considered, the same way sec. 6's "An AC MUST NOT
711
- // contain both a noRevAvail extension and a 'pointer in AC'" is enforced here. Both are MUST NOTs
712
- // the issuer broke, and a certificate that breaks its own profile is refused rather than partly
713
- // honored: passing it because some OTHER entry happened to match would resolve the violation in
714
- // the accepting direction, and would leave the verdict depending on which entries an attacker
715
- // chose to include alongside the forbidden one. The targets check itself never runs, so its slot
716
- // says so.
717
536
  for (var g0 = 0; g0 < groups.length; g0++) {
718
537
  for (var t0 = 0; t0 < groups[g0].length; t0++) {
719
538
  if (groups[g0][t0].kind !== "targetCert") continue;
@@ -732,7 +551,6 @@ function _checkTargeting(ac, want) {
732
551
  if (m === null) uncomparable = entry.name && entry.name.tagNumber;
733
552
  }
734
553
  }
735
- // A target this build cannot compare leaves the check unperformed, which cannot read as a pass.
736
554
  if (uncomparable !== null) {
737
555
  return { checked: false, ok: false,
738
556
  reason: "this attribute certificate names a target in a GeneralName form ([" + uncomparable +
@@ -742,21 +560,6 @@ function _checkTargeting(ac, want) {
742
560
  reason: "this attribute certificate does not name this verifier among its targets (RFC 5755 sec. 4.3.2)" };
743
561
  }
744
562
 
745
- // The critical extensions this verb SUPPORTS, by OID. RFC 5755 sec. 5 defines support in two parts:
746
- // the verifier must be able to parse the value, AND "where the extension value causes the AC to be
747
- // rejected, the AC verifier MUST reject the AC". Parsing alone satisfies only the first, so an
748
- // extension whose constraints this verb never evaluates cannot be called supported however cleanly
749
- // it decodes.
750
- //
751
- // targetInformation -- evaluated, by the sec. 4.3.2 check below.
752
- // acAuditIdentity -- sec. 4.3.1 is an audit/logging identity and states no rule that rejects an
753
- // AC, so there is no second part to satisfy. It rides out on the verdict's
754
- // `extensions` for the logging the section asks for.
755
- //
756
- // Everything else critical is refused, including extensions this build parses but does not act on:
757
- // aaControls (sec. 7.4) constrains what an AA may delegate and acProxying (sec. 7.2) constrains
758
- // proxy use, and an unevaluated constraint is exactly what item 7 exists to stop. A critical
759
- // extension defined in future defaults to refused, which is the safe direction.
760
563
  var SUPPORTED_CRITICAL = {};
761
564
  SUPPORTED_CRITICAL[O("targetInformation")] = 1;
762
565
  SUPPORTED_CRITICAL[O("acAuditIdentity")] = 1;
@@ -765,10 +568,7 @@ function _unsupportedCritical(ac) {
765
568
  for (var i = 0; i < ac.extensions.length; i++) {
766
569
  var e = ac.extensions[i];
767
570
  if (e.critical !== true) continue;
768
- // Own-property membership, so an extension OID that happens to name something on Object.prototype
769
- // cannot read as supported.
770
571
  if (!_hasOwn(SUPPORTED_CRITICAL, e.oid)) return e.oid;
771
- // A supported OID whose value this build could not interpret is still unusable.
772
572
  if (e.decoded === null || e.decoded === undefined || e.decoded.opaque === true) return e.oid;
773
573
  }
774
574
  return null;
@@ -873,13 +673,6 @@ function _unsupportedCritical(ac) {
873
673
  function verify(ac, issuer, opts) {
874
674
  return guard.async.deferred(function () { return _verify(ac, issuer, opts); });
875
675
  }
876
- // Every caller-owned value the verdict depends on, read HERE and reduced to a value the caller no
877
- // longer reaches: the instant rather than the Date (a Date is mutable through setTime even when the
878
- // property is never reassigned), and the target already encoded and decoded rather than the object.
879
- // Signature verification suspends this call for at least a turn, and an option re-read after it
880
- // resumes answers for whatever the caller last wrote, so a caller could hand in an expired instant,
881
- // replace it while WebCrypto works, and receive `verified: true`. The reduction is returned rather
882
- // than performed at each use, so reading an option late is not an available mistake.
883
676
  function _fixVerifyOptions(opts) {
884
677
  var o = guard.identifier.optionsObject(opts, _err, "attrcert/bad-input", "pki.attrcert.verify options");
885
678
  guard.identifier.assertKnownKeys(o, KNOWN_VERIFY_OPTS, _err, "attrcert/bad-input",
@@ -897,24 +690,16 @@ function _fixVerifyOptions(opts) {
897
690
  }
898
691
  revocationStatus = o.revocationStatus;
899
692
  }
900
- // A supplied target is encoded and read back whether or not the AC turns out to be targeted, so a
901
- // malformed one is refused at the call that supplied it.
902
693
  return {
903
694
  at: at, revocationStatus: revocationStatus,
904
695
  target: o.target === undefined ? undefined : _callerTarget(o.target),
905
696
  };
906
697
  }
907
698
 
908
- // RFC 5755 sec. 6 "pointer in AC": "ACs may 'point' to sources of revocation status information,
909
- // using either an authorityInfoAccess extension or a crlDistributionPoints extension within the AC."
910
- // Named by OID, since the OID is what an issuer signs and a display name is not.
911
699
  var REVOCATION_POINTERS = Object.create(null);
912
700
  REVOCATION_POINTERS[O("cRLDistributionPoints")] = "crlDistributionPoints";
913
701
  REVOCATION_POINTERS[O("authorityInfoAccess")] = "authorityInfoAccess";
914
702
 
915
- // The two revocation schemes an AC declares, read from its extensions. RFC 5755 sec. 4.3.6 / sec. 6:
916
- // noRevAvail is the issuer stating that no revocation information will ever be made available for
917
- // this AC, and it is a bare NULL, so its presence is the whole content.
918
703
  function _revocationScheme(ac) {
919
704
  var out = { noRevAvail: false, pointer: null };
920
705
  for (var i = 0; i < ac.extensions.length; i++) {
@@ -936,8 +721,6 @@ function _verify(ac, issuer, opts) {
936
721
  holder: parsed.holder,
937
722
  issuer: acIssuer,
938
723
  attributes: parsed.attributes,
939
- // Carried so a caller can act on what rode along: sec. 4.3.1 asks that an audit identity be
940
- // used for audit and logging, which it cannot be if the verdict drops it.
941
724
  extensions: parsed.extensions,
942
725
  notBefore: parsed.validity.notBeforeTime,
943
726
  notAfter: parsed.validity.notAfterTime,
@@ -947,71 +730,41 @@ function _verify(ac, issuer, opts) {
947
730
  targetingChecked: false,
948
731
  revocationChecked: false,
949
732
  noRevAvail: false,
950
- holderBindingChecked: false, // item 1 needs the holder's certificate, which this verb is not given
951
- issuerPathChecked: false, // items 2 and 3 need the issuer's chain, likewise
952
- valid: false, // canonical toolkit-wide verdict alias, tracks `verified`
733
+ holderBindingChecked: false,
734
+ issuerPathChecked: false,
735
+ valid: false,
953
736
  verified: false,
954
737
  reason: undefined,
955
738
  };
956
739
 
957
- // The signature runs first so `signatureValid` is answered even when a later gate refuses: an
958
- // operator reading an out-of-window verdict still learns whether the bytes were authentic.
959
740
  return Promise.resolve(attrcertVerify.verifyAcSignature(parsed, trust.spki)).then(function (sigOk) {
960
741
  result.signatureValid = sigOk === true;
961
742
  var fail = function (reason) { result.reason = reason; return result; };
962
743
  if (!result.signatureValid) return fail("the signature does not verify under the issuer public key");
963
744
 
964
- // Item 4: the caller trusts a named AC issuer, and this AC must be the one they named.
965
745
  if (!guard.name.dnEqual(acIssuer.rdns, trust.rdns, _err,
966
746
  "attrcert/bad-input", "the AC issuer")) {
967
747
  return fail("this attribute certificate names issuer " + JSON.stringify(acIssuer.dn) +
968
748
  ", which is not the AC issuer this verifier trusts");
969
749
  }
970
750
 
971
- // Item 7, before the fields are read: an unsupported critical extension makes the whole AC
972
- // unusable, so a caller must not act on attributes carried beside one.
973
751
  var badExt = _unsupportedCritical(parsed);
974
752
  if (badExt) return fail("this attribute certificate carries an unsupported critical extension (" + badExt + "), which RFC 5755 sec. 5 item 7 requires be rejected");
975
753
 
976
- // Item 6.
977
754
  var targeting = _checkTargeting(parsed, fixed.target);
978
755
  result.targetingChecked = targeting.checked;
979
756
  if (!targeting.ok) return fail(targeting.reason);
980
757
 
981
- // Item 5. An absent instant asks nothing, which cannot read as a pass.
982
758
  if (fixed.at === null) {
983
759
  return fail("no opts.time was supplied, so RFC 5755 sec. 5 item 5 (the evaluation instant lies within the validity) went unasked");
984
760
  }
985
761
  result.validityChecked = true;
986
- // "If the evaluation time is equal to either notBeforeTime or notAfterTime, then the AC is
987
- // timely and this check succeeds" -- both bounds are inclusive.
988
762
  if (fixed.at < guard.time.instantOf(result.notBefore) || fixed.at > guard.time.instantOf(result.notAfter)) {
989
763
  return fail("the evaluation instant lies outside this attribute certificate's validity");
990
764
  }
991
765
 
992
- // RFC 5755 sec. 6. This verb implements the "never revoke" scheme: it holds no revocation
993
- // evidence of its own and follows no pointer out of the certificate. The section says exactly
994
- // what that obliges -- "If only the 'never revoke' scheme is supported, then all ACs that do not
995
- // contain a noRevAvail extension, MUST be rejected" -- because where noRevAvail is absent "the
996
- // AC issuer is implicitly stating that revocation status checks are supported", so a verdict
997
- // that skipped one would grant privileges the issuer expected to be able to withdraw. A caller
998
- // who has established the status passes it as opts.revocationStatus; the AC's own
999
- // crlDistributionPoints / authorityInfoAccess pointers ride out on the verdict's `extensions`
1000
- // for them to follow.
1001
- //
1002
- // That status is accepted whether or not the AC carries a pointer, because the section closes by
1003
- // saying where it may come from: "An AC verifier MAY use any source for AC revocation status
1004
- // information." Requiring a pointer in the certificate would refuse a verifier who obtained the
1005
- // status from a directory, an out-of-band CRL, or a local record, all of which that sentence
1006
- // permits. The verdict keeps the two apart: `noRevAvail` says the issuer declared none would
1007
- // exist, and its absence beside `revocationChecked: true` says the caller supplied one.
1008
766
  var scheme = _revocationScheme(parsed);
1009
767
  result.noRevAvail = scheme.noRevAvail;
1010
- // The two schemes are alternatives, and the section closes by saying so: "An AC MUST NOT contain
1011
- // both a noRevAvail extension and a 'pointer in AC'." An AC carrying both tells the verifier two
1012
- // different things about its own revocation, and reading the never-revoke claim as settling the
1013
- // question would resolve that contradiction in the accepting direction. It is refused whichever
1014
- // way the caller answers, since the certificate itself is the thing that is wrong.
1015
768
  if (scheme.noRevAvail && scheme.pointer) {
1016
769
  return fail("this attribute certificate carries both noRevAvail and a " + scheme.pointer +
1017
770
  " revocation pointer, which RFC 5755 sec. 6 says an AC MUST NOT do");
@@ -1022,7 +775,6 @@ function _verify(ac, issuer, opts) {
1022
775
  return fail("this attribute certificate is revoked, as opts.revocationStatus reports");
1023
776
  }
1024
777
  } else if (result.noRevAvail) {
1025
- // The issuer has stated no revocation information will exist, so there is no status to obtain.
1026
778
  result.revocationChecked = true;
1027
779
  } else {
1028
780
  return fail("this attribute certificate carries no noRevAvail extension, so its issuer supports revocation status checks and RFC 5755 sec. 6 requires one; establish the status from the certificate's own pointers and pass it as opts.revocationStatus");