@blamejs/pki 0.8.17 → 0.8.19

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/lib/oid.js CHANGED
@@ -118,11 +118,39 @@ var FAMILIES = Object.assign(Object.create(null), {
118
118
 
119
119
  pkixOn: { base: [1, 3, 6, 1, 5, 5, 7, 8], of: { hardwareModuleName: 4, dnsSRV: 7, smtpUtf8Mailbox: 9, macAddress: 12 } },
120
120
 
121
+ /** @internal The S/MIME BR reserved policy identifiers of sec. 7.1.6.1 are a 4x3 matrix of
122
+ * certificate type by generation, and a subscriber certificate asserts exactly one. Reading it
123
+ * is how a linter learns which generation's table to hold the certificate to, so all twelve are
124
+ * named rather than only the current ones. */
121
125
  cabfPolicy: { base: [2, 23, 140, 1], of: {
122
- "ev-guidelines": 1, "domain-validated": [2, 1], "organization-validated": [2, 2], "individual-validated": [2, 3] } },
126
+ "ev-guidelines": 1, "domain-validated": [2, 1], "organization-validated": [2, 2], "individual-validated": [2, 3],
127
+ "smime-mailbox-legacy": [5, 1, 1], "smime-mailbox-multipurpose": [5, 1, 2], "smime-mailbox-strict": [5, 1, 3],
128
+ "smime-organization-legacy": [5, 2, 1], "smime-organization-multipurpose": [5, 2, 2], "smime-organization-strict": [5, 2, 3],
129
+ "smime-sponsor-legacy": [5, 3, 1], "smime-sponsor-multipurpose": [5, 3, 2], "smime-sponsor-strict": [5, 3, 3],
130
+ "smime-individual-legacy": [5, 4, 1], "smime-individual-multipurpose": [5, 4, 2], "smime-individual-strict": [5, 4, 3],
131
+ "code-signing-ev": 3, "code-signing": [4, 1], "code-signing-timestamping": [4, 2] } },
123
132
 
124
133
  idCp: { base: [1, 3, 6, 1, 5, 5, 7, 14], of: { "id-cp-ipAddr-asNumber": 2, "id-cp-ipAddr-asNumber-v2": 3 } },
125
134
 
135
+ /** @internal The Legal Entity Identifier extensions of S/MIME BR sec. 7.1.2.3 (l), which the
136
+ * certificate type decides the admissibility of. */
137
+ lei: { base: [1, 3, 6, 1, 4, 1, 52266], of: { "lei-identifier": 1, "lei-role": 2 } },
138
+
139
+ /** @internal The Adobe extensions of S/MIME BR sec. 7.1.2.3 (m), prohibited under the Strict
140
+ * generation. */
141
+ adobe: { base: [1, 2, 840, 113583, 1, 1, 9], of: { "adobe-timestamp": 1, "adobe-archive-rev-info": 2 } },
142
+
143
+ /** @internal The extended key purposes Code Signing BR sec. 7.1.2.3 (f) names as MAY beside
144
+ * id-kp-codeSigning, so a row reporting any other purpose can exclude them by name. Document
145
+ * Signing is registered twice: Microsoft assigns it 1.3.6.1.4.1.311.10.3.12, the sibling of the
146
+ * Lifetime Signing arc printed two lines above it in that clause, and the clause itself prints
147
+ * 1.3.6.1.4.1.311.3.10.3.12. Both resolve, so a certificate carrying either is read as the
148
+ * purpose the clause permits. */
149
+ msEku: { base: [1, 3, 6, 1, 4, 1, 311], of: {
150
+ "ms-lifetime-signing": [10, 3, 13],
151
+ "ms-document-signing": [10, 3, 12],
152
+ "ms-document-signing-as-printed": [3, 10, 3, 12] } },
153
+
126
154
  gsmaRspRole: { base: [2, 23, 146, 1, 2, 1], of: {
127
155
  "id-rspRole-ci": 0, "id-rspRole-euicc-v2": 1, "id-rspRole-euicc": [0, 0, 0, 0, 0],
128
156
  "id-rspRole-eum-v2": 2, "id-rspRole-eum": [0, 0, 0],
package/lib/pki-build.js CHANGED
@@ -42,6 +42,9 @@ function _isSubDelim(c) {
42
42
  }
43
43
  }
44
44
  function _isUserinfoByte(c) { return _isUnreserved(c) || _isSubDelim(c) || c === 58; }
45
+ /** @internal The bytes RFC 3986 sec. 3.2.2 admits in a reg-name, beside a percent-encoding. A DNS
46
+ * label admits fewer, which is why a reader does not hold a host it was given to that rule. */
47
+ function _isRegNameByte(c) { return _isUnreserved(c) || _isSubDelim(c); }
45
48
  function _isUriByte(c) {
46
49
  return _isUnreserved(c) || _isSubDelim(c) || c === 58 || c === 47 || c === 63 || c === 35 || c === 64;
47
50
  }
@@ -99,7 +102,61 @@ function _validUriIp6Host(s, from, to) {
99
102
  return packed !== null && intrinsic.sizeOf(packed) === 16;
100
103
  }
101
104
 
105
+ /** @internal A port as RFC 3986 sec. 3.2.3 writes it: ":" *DIGIT, or nothing. An empty port after
106
+ * the colon is what the grammar allows, so it is not a reason to refuse. */
107
+ function _validUriPort(s, at, to) {
108
+ if (at === to) return true;
109
+ if (_charCodeAt(s, at) !== 58) return false;
110
+ for (var i = at + 1; i < to; i += 1) { if (!_isDigitCode(_charCodeAt(s, i))) return false; }
111
+ return true;
112
+ }
113
+ /** @internal An IPvFuture literal, RFC 3986 sec. 3.2.2: "v" 1*HEXDIG "." 1*( unreserved /
114
+ * sub-delims / ":" ). */
115
+ function _validIpvFuture(s, from, to) {
116
+ if (to - from < 4) return false;
117
+ var c = _charCodeAt(s, from);
118
+ if (c !== 118 && c !== 86) return false;
119
+ var i = from + 1, hex = 0;
120
+ while (i < to && _isHexCode(_charCodeAt(s, i))) { i += 1; hex += 1; }
121
+ if (hex === 0 || i >= to || _charCodeAt(s, i) !== 46) return false;
122
+ i += 1;
123
+ if (i >= to) return false;
124
+ for (; i < to; i += 1) {
125
+ c = _charCodeAt(s, i);
126
+ if (!_isUnreserved(c) && !_isSubDelim(c) && c !== 58) return false;
127
+ }
128
+ return true;
129
+ }
130
+ /** @internal The authority of a URL a reader was GIVEN, as RFC 3986 sec. 3.2 writes it:
131
+ * [ userinfo "@" ] host [ ":" port ], where host is a non-empty reg-name, an IPv6 literal in
132
+ * brackets, or an IPvFuture literal. RFC 7230 sec. 2.7.1 forbids an empty host for http, so the
133
+ * host is required here. The structure is checked; the reg-name's own bytes are not held to DNS
134
+ * label rules, which is what a URL this toolkit EMITS must satisfy and is not what RFC 3986
135
+ * conformance means. Applying the emit rule to a value someone else wrote rejects legal URLs, and
136
+ * dropping the structure with it accepts "http://:80". */
137
+ function _validReadAuthority(s, from, to) {
138
+ var i, at = -1;
139
+ for (i = from; i < to; i += 1) { if (_charCodeAt(s, i) === 64) at = i; }
140
+ if (at !== -1 && !_componentBytesOk(s, from, at, _isUserinfoByte)) return false;
141
+ var hostStart = at === -1 ? from : at + 1;
142
+ if (hostStart >= to) return false;
143
+ if (_charCodeAt(s, hostStart) === 91) {
144
+ var close = -1;
145
+ for (i = hostStart + 1; i < to; i += 1) { if (_charCodeAt(s, i) === 93) { close = i; break; } }
146
+ if (close === -1) return false;
147
+ if (!_validUriIp6Host(s, hostStart + 1, close) && !_validIpvFuture(s, hostStart + 1, close)) return false;
148
+ return _validUriPort(s, close + 1, to);
149
+ }
150
+ var colon = -1;
151
+ for (i = hostStart; i < to; i += 1) { if (_charCodeAt(s, i) === 58) { colon = i; break; } }
152
+ var hostEnd = colon === -1 ? to : colon;
153
+ if (hostEnd === hostStart) return false;
154
+ if (!_componentBytesOk(s, hostStart, hostEnd, _isRegNameByte)) return false;
155
+ return colon === -1 ? true : _validUriPort(s, colon, to);
156
+ }
157
+
102
158
  function _validUriAuthority(s, from, to, shape) {
159
+ if (shape.anyAuthority) return _validReadAuthority(s, from, to);
103
160
  var i, c, at = -1;
104
161
  for (i = from; i < to; i += 1) {
105
162
  c = _charCodeAt(s, i);
@@ -136,6 +193,13 @@ var _URI_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: false,
136
193
  /** @internal An HTTP URL (RFC 2616 sec. 3.2.2: "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]):
137
194
  * no userinfo, a host of one label or many, a query only after an absolute path, no fragment. */
138
195
  var _HTTP_URL_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: true, userinfo: false, emptyAuthority: false, emptyHost: false, queryNeedsPath: true, fragment: false });
196
+ /** @internal An http or https URL as RFC 7230 sec. 2.7.1 and 2.7.2 write it: "http:" "//"
197
+ * authority path-abempty [ "?" query ], where path-abempty MAY be empty, so a query sits directly
198
+ * after the authority, and where a fragment is allowed on the URI reference (RFC 3986 sec. 3.5).
199
+ * This is the shape a reader holds a URL it was GIVEN to. The shape above is what the builders
200
+ * hold the URLs they EMIT to, which is deliberately narrower, and applying it to a value someone
201
+ * else wrote reports a conforming URL. */
202
+ var _HTTP_URL_READ_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: true, userinfo: true, emptyAuthority: false, emptyHost: false, queryNeedsPath: false, fragment: true, anyAuthority: true });
139
203
  /** @internal An LDAP URL (RFC 4516 sec. 2: scheme "://" [host [":" port]] ["/" dn ...]): no
140
204
  * userinfo, a host of any label count that may be left out, with or without a port, and no
141
205
  * fragment. The dn, attributes, scope and filter after the "/" are not parsed. */
@@ -143,6 +207,17 @@ var _LDAP_URL_SHAPE = intrinsic.assign(intrinsic.create(null), { singleLabel: tr
143
207
 
144
208
  function _looksLikeUri(s) { return _uriShape(s, _URI_SHAPE); }
145
209
  function isHttpUrl(s) { return typeof s === "string" && guard.name.uriSchemeIs(s, "http") && _uriShape(s, _HTTP_URL_SHAPE); }
210
+ /** @internal The scheme of a well-formed http or https URL as a READER judges one, or null where
211
+ * the string is not one of either. Carrying the scheme token is not the same as being a URI of
212
+ * that scheme: RFC 7230 sec. 2.7.1 writes http-URI as "http:" "//" authority path-abempty and
213
+ * forbids an empty host, so "http:example.com/a" and "http://:80" are neither. A caller that
214
+ * admits one scheme and not the other compares the answer rather than testing a prefix. */
215
+ function httpUrlScheme(s) {
216
+ if (typeof s !== "string" || !_uriShape(s, _HTTP_URL_READ_SHAPE)) return null;
217
+ if (guard.name.uriSchemeIs(s, "http")) return "http";
218
+ if (guard.name.uriSchemeIs(s, "https")) return "https";
219
+ return null;
220
+ }
146
221
  function isLdapUrl(s) { return typeof s === "string" && guard.name.uriSchemeIs(s, "ldap") && _uriShape(s, _LDAP_URL_SHAPE); }
147
222
 
148
223
  function _uriShape(s, shape) {
@@ -1378,4 +1453,4 @@ function samePublicKey(spkiA, spkiB) {
1378
1453
  return _keyEquals(ka, kb) === true;
1379
1454
  }
1380
1455
 
1381
- module.exports = intrinsic.freeze({ makeBuilder: makeBuilder, reqDenseArray: reqDenseArrayImpl, KU_BIT: KU_BIT, tbsNameField: tbsNameField, tbsSerialNumber: tbsSerialNumber, randomSerial: randomSerial, skiValueOf: skiValueOf, isHttpUrl: isHttpUrl, isLdapUrl: isLdapUrl });
1456
+ module.exports = intrinsic.freeze({ makeBuilder: makeBuilder, reqDenseArray: reqDenseArrayImpl, KU_BIT: KU_BIT, tbsNameField: tbsNameField, tbsSerialNumber: tbsSerialNumber, randomSerial: randomSerial, skiValueOf: skiValueOf, isHttpUrl: isHttpUrl, httpUrlScheme: httpUrlScheme, isLdapUrl: isLdapUrl });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.8.17",
3
+ "version": "0.8.19",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:1b8d2783-3d1c-49be-ad22-5e029717a170",
5
+ "serialNumber": "urn:uuid:226c63e5-3f86-43a6-a5bd-ad58867e4706",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-24T06:15:30.953Z",
8
+ "timestamp": "2026-09-24T10:24:04.955Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/pki@0.8.17",
22
+ "bom-ref": "@blamejs/pki@0.8.19",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.8.17",
25
+ "version": "0.8.19",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
29
- "purl": "pkg:npm/%40blamejs/pki@0.8.17",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.8.19",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/pki@0.8.17",
57
+ "ref": "@blamejs/pki@0.8.19",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]