@blamejs/pki 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/lib/guard-limits.js +48 -1
- package/lib/guard-parsed.js +2 -2
- package/lib/schema-all.js +29 -18
- package/lib/schema-attrcert.js +16 -9
- package/lib/schema-c509.js +20 -4
- package/lib/schema-cmc.js +52 -16
- package/lib/schema-cmp.js +6 -1
- package/lib/schema-cms.js +6 -1
- package/lib/schema-crl.js +6 -1
- package/lib/schema-crmf.js +6 -1
- package/lib/schema-csr.js +6 -1
- package/lib/schema-csrattrs.js +6 -1
- package/lib/schema-ocsp.js +12 -2
- package/lib/schema-pkcs12.js +6 -1
- package/lib/schema-pkcs8.js +12 -2
- package/lib/schema-pkix.js +151 -5
- package/lib/schema-smime.js +12 -2
- package/lib/schema-tsp.js +38 -6
- package/lib/schema-x509.js +6 -1
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to `@blamejs/pki` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this
|
|
5
5
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## v0.8.3 — 2026-09-25
|
|
8
|
+
|
|
9
|
+
A parser takes decode caps from its caller, and a resource refusal says so instead of reading as malformed input.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Every parse function takes an optional second argument of decode caps: `maxBytes`, `maxDepth` and `maxItems`. That includes `pki.schema.parse`, the format-detecting door, where the caps bound both the detection decode and the decode of whichever format matches. Each may tighten below the corresponding `pki.C.LIMITS` default and is refused with `<format>/bad-input` if it names a value above it, so a caller can bound a parse more strictly than the toolkit does and cannot grant itself more resource than the built-in refusal allows. An option outside that set is named in the refusal rather than ignored.
|
|
14
|
+
- A new `<format>/too-large` code on each format, reported when a decode limit refuses the input.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- An input refused for exceeding a decode limit reports `<format>/too-large` where it previously reported `<format>/bad-der`. The two say different things to whoever reads them: one is answered by raising a cap, the other by fixing the bytes. A caller matching on `bad-der` to detect malformed input will stop seeing oversized and over-nested inputs under that code.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- A parse that exhausts its decode budget cannot report anything but a refusal, even when code inside the parse catches the failure. The budget latches on exhaustion, and each parser door re-reads that latch after its walk and before returning a result, so a `catch` between the two can absorb the exception and still not produce a value. This is the guarantee that makes the caps worth relying on: without it any of the toolkit's error-absorbing paths could turn `over budget` into an ordinary absent value and change a verdict.
|
|
23
|
+
- The caps a caller names are read into a fresh object, and no flag is ever written onto the object the caller passed or onto the one the decode receives. A resource option therefore cannot alter which encodings a parse accepts; the strictness of a parse is the same whatever caps are asked for.
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
- The caps bound the decode of the input a parser is given, which is what bounds a parse overall, since everything a parse reads comes from those bytes. A structure decoded separately from inside that input keeps the built-in `pki.C.LIMITS` defaults rather than a tighter figure the caller named.
|
|
28
|
+
|
|
7
29
|
## v0.8.2 — 2026-09-25
|
|
8
30
|
|
|
9
31
|
A distinguished name can be read back from its string form, and twelve attributes the name table published can finally be encoded.
|
package/lib/guard-limits.js
CHANGED
|
@@ -65,4 +65,51 @@ function byteCap(buf, max, E, code, label) {
|
|
|
65
65
|
return buf;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
/** @internal Thrown when a parse exhausts its resource budget. It is not a PkiError subclass,
|
|
69
|
+
* so a `catch (e) { if (e instanceof PkiError) ...; throw e; }` re-throws it. A parser door
|
|
70
|
+
* converts it to that door's typed refusal, so the public contract is unchanged. */
|
|
71
|
+
function BudgetExceeded(message) {
|
|
72
|
+
var e = new Error(message);
|
|
73
|
+
e.name = "BudgetExceeded";
|
|
74
|
+
e.budgetExceeded = true;
|
|
75
|
+
return e;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isBudgetExceeded(e) {
|
|
79
|
+
return !!(e && e.budgetExceeded === true);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @internal One budget per top-level parse, carried into every nested decode. `exhausted`
|
|
83
|
+
* latches, and the object is frozen, so a caller that catches the throw cannot clear it. A
|
|
84
|
+
* door that re-reads the latch before returning a result therefore still refuses, whatever
|
|
85
|
+
* code between the two caught the exception. */
|
|
86
|
+
function budget(limits) {
|
|
87
|
+
var spent = 0;
|
|
88
|
+
var exhausted = false;
|
|
89
|
+
var max = cap(limits ? limits.maxBytes : undefined, "maxBytes", constants.LIMITS.DER_MAX_BYTES);
|
|
90
|
+
var self = {
|
|
91
|
+
spend: function (n, what) {
|
|
92
|
+
if (!_isInteger(n) || n < 0) throw new TypeError("guard.limits.budget: spend takes a non-negative integer");
|
|
93
|
+
spent += n;
|
|
94
|
+
if (spent > max) {
|
|
95
|
+
exhausted = true;
|
|
96
|
+
throw BudgetExceeded((what || "the parse") + " exceeds the " + max + "-byte budget for this parse");
|
|
97
|
+
}
|
|
98
|
+
return n;
|
|
99
|
+
},
|
|
100
|
+
trip: function (what) {
|
|
101
|
+
exhausted = true;
|
|
102
|
+
throw BudgetExceeded((what || "the parse") + " exceeds the budget for this parse");
|
|
103
|
+
},
|
|
104
|
+
exhausted: function () { return exhausted; },
|
|
105
|
+
spent: function () { return spent; },
|
|
106
|
+
remaining: function () { return max - spent; },
|
|
107
|
+
max: function () { return max; },
|
|
108
|
+
};
|
|
109
|
+
return _freeze(self);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = _freeze({
|
|
113
|
+
cap: cap, depthCap: depthCap, counter: counter, byteCap: byteCap,
|
|
114
|
+
budget: budget, isBudgetExceeded: isBudgetExceeded,
|
|
115
|
+
});
|
package/lib/guard-parsed.js
CHANGED
|
@@ -144,10 +144,10 @@ var PROVENANCE = new _WeakMap();
|
|
|
144
144
|
|
|
145
145
|
// @enforced-by guard-shape-reinlined -- shares the fromTrustedSource shape below; a
|
|
146
146
|
function recordingParser(kind, parse, ErrorClass, code, label) {
|
|
147
|
-
return function (input) {
|
|
147
|
+
return function (input, callerOpts) {
|
|
148
148
|
var isText = typeof input === "string";
|
|
149
149
|
var snap = isText ? input : bytes.snapshotSource(input, ErrorClass, code, label);
|
|
150
|
-
var out = parse(snap);
|
|
150
|
+
var out = parse(snap, callerOpts);
|
|
151
151
|
if (out && typeof out === "object") {
|
|
152
152
|
_weakSet(PROVENANCE, out, { kind: kind, source: isText ? snap : _bufferFrom(snap),
|
|
153
153
|
shape: _shapeOf(out) });
|
package/lib/schema-all.js
CHANGED
|
@@ -60,85 +60,85 @@ var FORMATS = [
|
|
|
60
60
|
name: "cms",
|
|
61
61
|
module: cms,
|
|
62
62
|
detect: cms.matches,
|
|
63
|
-
parse: function (input) { return cms.parse(input); },
|
|
63
|
+
parse: function (input, caps) { return cms.parse(input, caps); },
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
name: "tsp",
|
|
67
67
|
module: tsp,
|
|
68
68
|
detect: tsp.matches,
|
|
69
|
-
parse: function (input) { return tsp.parse(input); },
|
|
69
|
+
parse: function (input, caps) { return tsp.parse(input, caps); },
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
name: "crmf",
|
|
73
73
|
module: crmf,
|
|
74
74
|
detect: crmf.matches,
|
|
75
|
-
parse: function (input) { return crmf.parse(input); },
|
|
75
|
+
parse: function (input, caps) { return crmf.parse(input, caps); },
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
name: "cmp",
|
|
79
79
|
module: cmp,
|
|
80
80
|
detect: cmp.matches,
|
|
81
|
-
parse: function (input) { return cmp.parse(input); },
|
|
81
|
+
parse: function (input, caps) { return cmp.parse(input, caps); },
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
name: "csrattrs",
|
|
85
85
|
module: csrattrs,
|
|
86
86
|
detect: csrattrs.matches,
|
|
87
|
-
parse: function (input) { return csrattrs.parse(input); },
|
|
87
|
+
parse: function (input, caps) { return csrattrs.parse(input, caps); },
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
name: "ocsp-request",
|
|
91
91
|
module: ocsp,
|
|
92
92
|
detect: ocsp.matchesRequest,
|
|
93
|
-
parse: function (input) { return ocsp.parseRequest(input); },
|
|
93
|
+
parse: function (input, caps) { return ocsp.parseRequest(input, caps); },
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
name: "ocsp-response",
|
|
97
97
|
module: ocsp,
|
|
98
98
|
detect: ocsp.matchesResponse,
|
|
99
|
-
parse: function (input) { return ocsp.parseResponse(input); },
|
|
99
|
+
parse: function (input, caps) { return ocsp.parseResponse(input, caps); },
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
name: "pkcs12",
|
|
103
103
|
module: pkcs12,
|
|
104
104
|
detect: pkcs12.matches,
|
|
105
|
-
parse: function (input) { return pkcs12.parse(input); },
|
|
105
|
+
parse: function (input, caps) { return pkcs12.parse(input, caps); },
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
name: "pkcs8",
|
|
109
109
|
module: pkcs8,
|
|
110
110
|
detect: pkcs8.matches,
|
|
111
|
-
parse: function (input) { return pkcs8.parse(input); },
|
|
111
|
+
parse: function (input, caps) { return pkcs8.parse(input, caps); },
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
114
|
name: "csr",
|
|
115
115
|
module: csr,
|
|
116
116
|
detect: csr.matches,
|
|
117
|
-
parse: function (input) { return csr.parse(input); },
|
|
117
|
+
parse: function (input, caps) { return csr.parse(input, caps); },
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
name: "attrcert",
|
|
121
121
|
module: attrcert,
|
|
122
122
|
detect: attrcert.matches,
|
|
123
|
-
parse: function (input) { return attrcert.parse(input); },
|
|
123
|
+
parse: function (input, caps) { return attrcert.parse(input, caps); },
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
name: "attrcert-v1",
|
|
127
127
|
module: attrcert,
|
|
128
128
|
detect: attrcert.matchesV1,
|
|
129
|
-
parse: function (input) { return attrcert.parseV1(input); },
|
|
129
|
+
parse: function (input, caps) { return attrcert.parseV1(input, caps); },
|
|
130
130
|
},
|
|
131
131
|
{
|
|
132
132
|
name: "crl",
|
|
133
133
|
module: crl,
|
|
134
134
|
detect: crl.matches,
|
|
135
|
-
parse: function (input) { return crl.parse(input); },
|
|
135
|
+
parse: function (input, caps) { return crl.parse(input, caps); },
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
name: "x509",
|
|
139
139
|
module: x509,
|
|
140
140
|
detect: x509.matches,
|
|
141
|
-
parse: function (input) { return x509.parse(input); },
|
|
141
|
+
parse: function (input, caps) { return x509.parse(input, caps); },
|
|
142
142
|
},
|
|
143
143
|
];
|
|
144
144
|
|
|
@@ -159,7 +159,7 @@ function all() { return FORMATS.map(function (f) { return f.name; }); }
|
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
161
|
* @primitive pki.schema.parse
|
|
162
|
-
* @signature pki.schema.parse(input) -> parsed
|
|
162
|
+
* @signature pki.schema.parse(input, caps?) -> parsed
|
|
163
163
|
* @since 0.1.7
|
|
164
164
|
* @status stable
|
|
165
165
|
* @spec RFC 5280
|
|
@@ -171,6 +171,13 @@ function all() { return FORMATS.map(function (f) { return f.name; }); }
|
|
|
171
171
|
* the bytes match no registered format; the underlying decode / structural
|
|
172
172
|
* errors of the matched format propagate unchanged.
|
|
173
173
|
*
|
|
174
|
+
* @opts
|
|
175
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
176
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
177
|
+
* above it, or an option outside this set, is refused. They bound the detection decode
|
|
178
|
+
* and the decode of whichever format matches, and a parse that exceeds one is refused
|
|
179
|
+
* with the `/too-large` code of that format.
|
|
180
|
+
*
|
|
174
181
|
* @example
|
|
175
182
|
* var pair = await pki.key.generate("Ed25519");
|
|
176
183
|
* var der = await pki.x509.sign({ subject: "example.com", subjectPublicKey: await pki.key.export(pair.publicKey),
|
|
@@ -178,11 +185,15 @@ function all() { return FORMATS.map(function (f) { return f.name; }); }
|
|
|
178
185
|
* { key: await pki.key.export(pair.privateKey) });
|
|
179
186
|
* var parsed = pki.schema.parse(der); // cert -> the pki.schema.x509 shape
|
|
180
187
|
*/
|
|
181
|
-
function parse(input) {
|
|
188
|
+
function parse(input, callerOpts) {
|
|
189
|
+
/** @internal The caps are validated once here and the snapshot is what the chosen format
|
|
190
|
+
* receives, so the detection decode and the format's own decode are held to the same
|
|
191
|
+
* figures a caller named, read once. */
|
|
192
|
+
var caps = pkix.parseCaps(callerOpts, ENTRY);
|
|
182
193
|
var der = pkix.coerceToDer(input, ENTRY);
|
|
183
|
-
var root = pkix.decodeRoot(der, ENTRY);
|
|
194
|
+
var root = pkix.decodeRoot(der, ENTRY, caps);
|
|
184
195
|
for (var i = 0; i < FORMATS.length; i++) {
|
|
185
|
-
if (FORMATS[i].detect(root)) return FORMATS[i].parse(der);
|
|
196
|
+
if (FORMATS[i].detect(root)) return FORMATS[i].parse(der, caps);
|
|
186
197
|
}
|
|
187
198
|
throw new SchemaError("schema/unknown-format", "input does not match any registered PKI format (" + all().join(", ") + ")");
|
|
188
199
|
}
|
package/lib/schema-attrcert.js
CHANGED
|
@@ -248,7 +248,7 @@ var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
|
248
248
|
|
|
249
249
|
/**
|
|
250
250
|
* @primitive pki.schema.attrcert.parse
|
|
251
|
-
* @signature pki.schema.attrcert.parse(input) -> attributeCertificate
|
|
251
|
+
* @signature pki.schema.attrcert.parse(input, caps?) -> attributeCertificate
|
|
252
252
|
* @since 0.1.14
|
|
253
253
|
* @status stable
|
|
254
254
|
* @spec RFC 5755, X.509
|
|
@@ -279,25 +279,32 @@ var ATTRIBUTE_CERTIFICATE = pkix.signedEnvelope(NS, ACINFO, {
|
|
|
279
279
|
* var ac = pki.schema.attrcert.parse(der);
|
|
280
280
|
* ac.attributes[0].name; // "role"
|
|
281
281
|
* ac.validity.notAfterTime;// Date
|
|
282
|
+
* @opts
|
|
283
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
284
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
285
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
286
|
+
* refused with the `/too-large` code of this format.
|
|
282
287
|
*/
|
|
283
|
-
var PARSE_OPTS = intrinsic.assign(intrinsic.create(null), { pemLabel: "ATTRIBUTE CERTIFICATE", PemError: PemError, ErrorClass: AttrCertError, prefix: "attrcert", what: "attribute certificate" });
|
|
288
|
+
var PARSE_OPTS = intrinsic.assign(intrinsic.create(null), { pemLabel: "ATTRIBUTE CERTIFICATE", PemError: PemError, ErrorClass: AttrCertError, prefix: "attrcert", what: "attribute certificate", ns: NS });
|
|
284
289
|
|
|
285
290
|
function _legacyV1Error() {
|
|
286
291
|
return new AttrCertError("attrcert/legacy-v1-not-supported", "AttributeCertificateV1 (X.509-1997) is obsolete and not parsed by this build (RFC 5755 sec. 1)");
|
|
287
292
|
}
|
|
288
293
|
|
|
289
|
-
function _parseAc(input) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
function _parseAc(input, callerOpts) {
|
|
295
|
+
return pkix.runParseWith(input, PARSE_OPTS, callerOpts, function (root, ns) {
|
|
296
|
+
if (matchesV1(root)) throw _legacyV1Error();
|
|
297
|
+
return schema.walk(ATTRIBUTE_CERTIFICATE, root, ns).result;
|
|
298
|
+
});
|
|
293
299
|
}
|
|
294
300
|
|
|
295
301
|
var parse = guard.parsed.recordingParser("attributeCertificate", _parseAc,
|
|
296
302
|
AttrCertError, "attrcert/bad-input", "an attribute certificate");
|
|
297
303
|
|
|
298
|
-
function parseV1(input) {
|
|
299
|
-
pkix.
|
|
300
|
-
|
|
304
|
+
function parseV1(input, callerOpts) {
|
|
305
|
+
return pkix.runParseWith(input, PARSE_OPTS, callerOpts, function () {
|
|
306
|
+
throw _legacyV1Error();
|
|
307
|
+
});
|
|
301
308
|
}
|
|
302
309
|
|
|
303
310
|
/**
|
package/lib/schema-c509.js
CHANGED
|
@@ -1563,7 +1563,7 @@ function _reconstructDer(r, sigNode) {
|
|
|
1563
1563
|
|
|
1564
1564
|
/**
|
|
1565
1565
|
* @primitive pki.schema.c509.parse
|
|
1566
|
-
* @signature pki.schema.c509.parse(bytes) -> { certificateType, serialNumber, serialNumberHex, ... }
|
|
1566
|
+
* @signature pki.schema.c509.parse(bytes, caps?) -> { certificateType, serialNumber, serialNumberHex, ... }
|
|
1567
1567
|
* @since 0.2.30
|
|
1568
1568
|
* @status stable
|
|
1569
1569
|
* @spec draft-ietf-cose-cbor-encoded-cert, RFC 8949, RFC 9090, RFC 5280
|
|
@@ -1583,11 +1583,27 @@ function _reconstructDer(r, sigNode) {
|
|
|
1583
1583
|
* "hex");
|
|
1584
1584
|
* var c = pki.schema.c509.parse(bytes);
|
|
1585
1585
|
* c.certificateType; // 3
|
|
1586
|
+
* @opts
|
|
1587
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
1588
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
1589
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
1590
|
+
* refused with the `/too-large` code of this format.
|
|
1586
1591
|
*/
|
|
1587
|
-
|
|
1592
|
+
var _PARSE_OPTS = pkix.cborParseOpts(C509Error, "c509", "the C509 certificate");
|
|
1593
|
+
|
|
1594
|
+
function parse(input, callerOpts) {
|
|
1595
|
+
var caps = pkix.parseCaps(callerOpts, _PARSE_OPTS);
|
|
1588
1596
|
var root;
|
|
1589
|
-
try {
|
|
1590
|
-
|
|
1597
|
+
try {
|
|
1598
|
+
root = cbor.decode(input, { maxBytes: caps.maxBytes, maxDepth: caps.maxDepth, maxItems: caps.maxItems });
|
|
1599
|
+
} catch (e) {
|
|
1600
|
+
/** @internal A resource refusal from the CBOR reader says the cap was too small. Reading it
|
|
1601
|
+
* as "these bytes are not a certificate" would send a caller to look at the wrong thing. */
|
|
1602
|
+
if (pkix.isCborResourceRefusal(e)) {
|
|
1603
|
+
throw _err("c509/too-large", "the C509 certificate exceeds the decode budget for this parse: " + ((e && e.message) || ""), e);
|
|
1604
|
+
}
|
|
1605
|
+
throw _err("c509/not-a-certificate", "the input is not well-formed deterministic CBOR", e);
|
|
1606
|
+
}
|
|
1591
1607
|
if (root.majorType !== 4 || !root.children) throw _err("c509/not-a-certificate", "a C509 certificate must be a CBOR array");
|
|
1592
1608
|
var f = root.children;
|
|
1593
1609
|
if (f.length !== 11) throw _err("c509/bad-tbs", "a C509 certificate must be an array of exactly 11 elements, got " + f.length);
|
package/lib/schema-cmc.js
CHANGED
|
@@ -646,7 +646,7 @@ function _finishBody(body, where) {
|
|
|
646
646
|
|
|
647
647
|
/**
|
|
648
648
|
* @primitive pki.schema.cmc.parsePkiData
|
|
649
|
-
* @signature pki.schema.cmc.parsePkiData(der) -> parsed
|
|
649
|
+
* @signature pki.schema.cmc.parsePkiData(der, caps?) -> parsed
|
|
650
650
|
* @since 0.4.16
|
|
651
651
|
* @status stable
|
|
652
652
|
* @spec RFC 5272 sec. 3.2.1
|
|
@@ -664,17 +664,23 @@ function _finishBody(body, where) {
|
|
|
664
664
|
* var der = b.sequence([b.sequence([]), b.sequence([]), b.sequence([]), b.sequence([])]);
|
|
665
665
|
* var d = pki.schema.cmc.parsePkiData(der);
|
|
666
666
|
* d.controls.length; // 0 -- present and empty, which is legal
|
|
667
|
+
* @opts
|
|
668
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
669
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
670
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
671
|
+
* refused with the `/too-large` code of this format.
|
|
667
672
|
*/
|
|
668
|
-
function parsePkiData(input) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
+
function parsePkiData(input, callerOpts) {
|
|
674
|
+
return pkix.runParseWith(input, _BODY_PARSE_OPTS, callerOpts, function (root, ns) {
|
|
675
|
+
var body = schema.walk(PKI_DATA, root, ns).result;
|
|
676
|
+
body.bytes = root.bytes;
|
|
677
|
+
return _finishBody(body, "pkiData");
|
|
678
|
+
});
|
|
673
679
|
}
|
|
674
680
|
|
|
675
681
|
/**
|
|
676
682
|
* @primitive pki.schema.cmc.parsePkiResponse
|
|
677
|
-
* @signature pki.schema.cmc.parsePkiResponse(der) -> parsed
|
|
683
|
+
* @signature pki.schema.cmc.parsePkiResponse(der, caps?) -> parsed
|
|
678
684
|
* @since 0.4.16
|
|
679
685
|
* @status stable
|
|
680
686
|
* @spec RFC 5272 sec. 4.2.1
|
|
@@ -690,17 +696,33 @@ function parsePkiData(input) {
|
|
|
690
696
|
* var der = b.sequence([b.sequence([]), b.sequence([]), b.sequence([])]);
|
|
691
697
|
* var r = pki.schema.cmc.parsePkiResponse(der);
|
|
692
698
|
* r.statuses.length; // 0 -- no status control means success is assumed
|
|
699
|
+
* @opts
|
|
700
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
701
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
702
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
703
|
+
* refused with the `/too-large` code of this format.
|
|
693
704
|
*/
|
|
694
|
-
function parsePkiResponse(input) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
705
|
+
function parsePkiResponse(input, callerOpts) {
|
|
706
|
+
return pkix.runParseWith(input, _BODY_PARSE_OPTS, callerOpts, function (root, ns) {
|
|
707
|
+
var body = schema.walk(PKI_RESPONSE, root, ns).result;
|
|
708
|
+
body.bytes = root.bytes;
|
|
709
|
+
return _finishBody(body, "pkiResponse");
|
|
710
|
+
});
|
|
699
711
|
}
|
|
700
712
|
|
|
713
|
+
/** @internal The door options for the two body parsers, which read a bare DER body rather than
|
|
714
|
+
* a CMS carrier, so they take no PEM label. `rawDecodeErrors` keeps the codec's own code for a
|
|
715
|
+
* malformed body, which callers already pin. */
|
|
716
|
+
var _CARRIER_PARSE_OPTS = pkix.parseOpts({ ErrorClass: CmcError, prefix: "cmc", what: "the CMC message" });
|
|
717
|
+
|
|
718
|
+
var _BODY_PARSE_OPTS = pkix.parseOpts({
|
|
719
|
+
ns: NS, ErrorClass: CmcError, PemError: CmcError, prefix: "cmc",
|
|
720
|
+
what: "the CMC body", pemLabel: null, rawDecodeErrors: true,
|
|
721
|
+
});
|
|
722
|
+
|
|
701
723
|
/**
|
|
702
724
|
* @primitive pki.schema.cmc.parse
|
|
703
|
-
* @signature pki.schema.cmc.parse(input) -> parsed
|
|
725
|
+
* @signature pki.schema.cmc.parse(input, caps?) -> parsed
|
|
704
726
|
* @since 0.4.16
|
|
705
727
|
* @status stable
|
|
706
728
|
* @spec RFC 5272, RFC 6402
|
|
@@ -724,17 +746,31 @@ function parsePkiResponse(input) {
|
|
|
724
746
|
* var sd = b.sequence([b.integer(3n), b.set([]), encap, b.set([])]);
|
|
725
747
|
* var der = b.sequence([b.oid("1.2.840.113549.1.7.2"), b.explicit(0, sd)]);
|
|
726
748
|
* pki.schema.cmc.parse(der).kind; // "pkiData"
|
|
749
|
+
* @opts
|
|
750
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
751
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
752
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
753
|
+
* refused with the `/too-large` code of this format.
|
|
727
754
|
*/
|
|
728
|
-
function parse(input) {
|
|
755
|
+
function parse(input, callerOpts) {
|
|
756
|
+
/** @internal Before the branch, because the already-parsed arm reaches no decode and would
|
|
757
|
+
* otherwise hold a caller to the option contract only when they passed bytes. The snapshot
|
|
758
|
+
* is what travels onward: handing the caller's own object to the CMS parser would read each
|
|
759
|
+
* cap a second time, and a value read twice need not answer the same way twice. */
|
|
760
|
+
var caps = pkix.parseCaps(callerOpts, _CARRIER_PARSE_OPTS);
|
|
729
761
|
var alreadyParsed = input && typeof input === "object" && !ArrayBuffer.isView(input) &&
|
|
730
762
|
!guard.bytes.isByteSource(input) && input.encapContentInfo != null;
|
|
731
763
|
var parsedCms;
|
|
732
764
|
if (alreadyParsed) { parsedCms = input; }
|
|
733
765
|
else {
|
|
734
766
|
/** @internal Bytes that are not a CMS message at all are a CMC message this cannot read, and every
|
|
735
|
-
* other format parser answers for its own input in its own domain.
|
|
736
|
-
|
|
767
|
+
* other format parser answers for its own input in its own domain. A resource refusal is the one
|
|
768
|
+
* exception: it is not a statement about the bytes, so it keeps its own code. */
|
|
769
|
+
try { parsedCms = cms.parse(input, caps); }
|
|
737
770
|
catch (e) {
|
|
771
|
+
if (e && typeof e.code === "string" && e.code.indexOf("/too-large") !== -1) {
|
|
772
|
+
throw E("cmc/too-large", "the CMC message exceeds the decode budget for this parse: " + (e.message || ""), e);
|
|
773
|
+
}
|
|
738
774
|
throw E("cmc/bad-der",
|
|
739
775
|
"a CMC message is carried in a CMS SignedData or AuthenticatedData, and these bytes are not " +
|
|
740
776
|
"one: " + ((e && e.message) || "malformed") + " (RFC 5272 sec. 3.2 / 4.2)", e);
|
package/lib/schema-cmp.js
CHANGED
|
@@ -751,7 +751,7 @@ var readName = _valueParser("Name", pkix.name(NS));
|
|
|
751
751
|
|
|
752
752
|
/**
|
|
753
753
|
* @primitive pki.schema.cmp.parse
|
|
754
|
-
* @signature pki.schema.cmp.parse(input) -> pkiMessage
|
|
754
|
+
* @signature pki.schema.cmp.parse(input, caps?) -> pkiMessage
|
|
755
755
|
* @since 0.1.19
|
|
756
756
|
* @status stable
|
|
757
757
|
* @spec RFC 9810, RFC 9483, RFC 9481
|
|
@@ -805,6 +805,11 @@ var readName = _valueParser("Name", pkix.name(NS));
|
|
|
805
805
|
* var m = pki.schema.cmp.parse(der);
|
|
806
806
|
* m.body.arm; // "ir", "ip", "error", ...
|
|
807
807
|
* m.header.transactionID; // raw Buffer or null
|
|
808
|
+
* @opts
|
|
809
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
810
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
811
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
812
|
+
* refused with the `/too-large` code of this format.
|
|
808
813
|
*/
|
|
809
814
|
var parse = pkix.makeParser({
|
|
810
815
|
pemLabel: "CMP", PemError: PemError, ErrorClass: CmpError,
|
package/lib/schema-cms.js
CHANGED
|
@@ -934,7 +934,7 @@ var CONTENT_INFO = schema.seq([
|
|
|
934
934
|
|
|
935
935
|
/**
|
|
936
936
|
* @primitive pki.schema.cms.parse
|
|
937
|
-
* @signature pki.schema.cms.parse(input) -> content
|
|
937
|
+
* @signature pki.schema.cms.parse(input, caps?) -> content
|
|
938
938
|
* @since 0.1.10
|
|
939
939
|
* @status stable
|
|
940
940
|
* @spec RFC 5652, RFC 5083, RFC 9629
|
|
@@ -972,6 +972,11 @@ var CONTENT_INFO = schema.seq([
|
|
|
972
972
|
* var cms = pki.schema.cms.parse(der);
|
|
973
973
|
* cms.signerInfos[0].sid.serialNumberHex; // -> "0a1b"
|
|
974
974
|
* cms.encapContentInfo.eContent; // -> Buffer | null (detached)
|
|
975
|
+
* @opts
|
|
976
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
977
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
978
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
979
|
+
* refused with the `/too-large` code of this format.
|
|
975
980
|
*/
|
|
976
981
|
var parse = pkix.makeRecordingParser({ pemLabel: "CMS", PemError: PemError, ErrorClass: CmsError, prefix: "cms", what: "CMS ContentInfo", topSchema: CONTENT_INFO, ns: NS }, "cms");
|
|
977
982
|
|
package/lib/schema-crl.js
CHANGED
|
@@ -157,7 +157,7 @@ var CERTIFICATE_LIST = pkix.signedEnvelope(NS, TBS_CERTLIST, {
|
|
|
157
157
|
|
|
158
158
|
/**
|
|
159
159
|
* @primitive pki.schema.crl.parse
|
|
160
|
-
* @signature pki.schema.crl.parse(input) -> crl
|
|
160
|
+
* @signature pki.schema.crl.parse(input, caps?) -> crl
|
|
161
161
|
* @since 0.1.7
|
|
162
162
|
* @status stable
|
|
163
163
|
* @spec RFC 5280
|
|
@@ -180,6 +180,11 @@ var CERTIFICATE_LIST = pkix.signedEnvelope(NS, TBS_CERTLIST, {
|
|
|
180
180
|
* { cert: caCert, key: key });
|
|
181
181
|
* var crl = pki.schema.crl.parse(der);
|
|
182
182
|
* crl.revokedCertificates[0].serialNumberHex; // -> "0a3f"
|
|
183
|
+
* @opts
|
|
184
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
185
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
186
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
187
|
+
* refused with the `/too-large` code of this format.
|
|
183
188
|
*/
|
|
184
189
|
var parse = pkix.makeRecordingParser({ pemLabel: "X509 CRL", PemError: PemError, ErrorClass: CrlError, prefix: "crl", what: "CRL", topSchema: CERTIFICATE_LIST, ns: NS }, "crl");
|
|
185
190
|
|
package/lib/schema-crmf.js
CHANGED
|
@@ -311,7 +311,7 @@ var CERT_REQ_MESSAGES = schema.seqOf(CERT_REQ_MSG, {
|
|
|
311
311
|
|
|
312
312
|
/**
|
|
313
313
|
* @primitive pki.schema.crmf.parse
|
|
314
|
-
* @signature pki.schema.crmf.parse(input) -> certReqMessages
|
|
314
|
+
* @signature pki.schema.crmf.parse(input, caps?) -> certReqMessages
|
|
315
315
|
* @since 0.1.17
|
|
316
316
|
* @status stable
|
|
317
317
|
* @spec RFC 4211
|
|
@@ -348,6 +348,11 @@ var CERT_REQ_MESSAGES = schema.seqOf(CERT_REQ_MSG, {
|
|
|
348
348
|
* { key: await pki.key.export(pair.privateKey) });
|
|
349
349
|
* var m = pki.schema.crmf.parse(der);
|
|
350
350
|
* m.messages[0].certReq.certTemplate.subject.dn; // "CN=req.example"
|
|
351
|
+
* @opts
|
|
352
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
353
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
354
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
355
|
+
* refused with the `/too-large` code of this format.
|
|
351
356
|
*/
|
|
352
357
|
var parse = pkix.makeRecordingParser({
|
|
353
358
|
pemLabel: null, PemError: PemError, ErrorClass: CrmfError, prefix: "crmf",
|
package/lib/schema-csr.js
CHANGED
|
@@ -121,7 +121,7 @@ var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO,
|
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* @primitive pki.schema.csr.parse
|
|
124
|
-
* @signature pki.schema.csr.parse(input) -> csr
|
|
124
|
+
* @signature pki.schema.csr.parse(input, caps?) -> csr
|
|
125
125
|
* @since 0.1.8
|
|
126
126
|
* @status stable
|
|
127
127
|
* @spec RFC 2986
|
|
@@ -147,6 +147,11 @@ var CERTIFICATION_REQUEST = pkix.signedEnvelope(NS, CERTIFICATION_REQUEST_INFO,
|
|
|
147
147
|
* var csr = pki.schema.csr.parse(der);
|
|
148
148
|
* csr.subject.dn; // -> "CN=req.example"
|
|
149
149
|
* csr.attributes[0].type; // -> "1.2.840.113549.1.9.14"
|
|
150
|
+
* @opts
|
|
151
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
152
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
153
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
154
|
+
* refused with the `/too-large` code of this format.
|
|
150
155
|
*/
|
|
151
156
|
var parse = pkix.makeRecordingParser({ pemLabel: "CERTIFICATE REQUEST", PemError: PemError, ErrorClass: CsrError, prefix: "csr", what: "certification request", topSchema: CERTIFICATION_REQUEST, ns: NS }, "csr");
|
|
152
157
|
|
package/lib/schema-csrattrs.js
CHANGED
|
@@ -244,7 +244,7 @@ var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
|
|
|
244
244
|
|
|
245
245
|
/**
|
|
246
246
|
* @primitive pki.schema.csrattrs.parse
|
|
247
|
-
* @signature pki.schema.csrattrs.parse(der) -> { items }
|
|
247
|
+
* @signature pki.schema.csrattrs.parse(der, caps?) -> { items }
|
|
248
248
|
* @since 0.1.24
|
|
249
249
|
* @status stable
|
|
250
250
|
* @spec RFC 8951, RFC 9908, RFC 7030
|
|
@@ -269,6 +269,11 @@ var CSR_ATTRS = schema.seqOf(ATTR_OR_OID, {
|
|
|
269
269
|
* ]);
|
|
270
270
|
* var a = pki.schema.csrattrs.parse(der);
|
|
271
271
|
* a.items[0].kind; // -> "oid" | "attribute"
|
|
272
|
+
* @opts
|
|
273
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
274
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
275
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
276
|
+
* refused with the `/too-large` code of this format.
|
|
272
277
|
*/
|
|
273
278
|
var parse = pkix.makeParser({ pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CsrattrsError, prefix: "csrattrs", what: "CsrAttrs", topSchema: CSR_ATTRS, ns: NS });
|
|
274
279
|
|
package/lib/schema-ocsp.js
CHANGED
|
@@ -431,7 +431,7 @@ var OCSP_REQUEST = schema.seq([
|
|
|
431
431
|
|
|
432
432
|
/**
|
|
433
433
|
* @primitive pki.schema.ocsp.parseRequest
|
|
434
|
-
* @signature pki.schema.ocsp.parseRequest(input) -> ocspRequest
|
|
434
|
+
* @signature pki.schema.ocsp.parseRequest(input, caps?) -> ocspRequest
|
|
435
435
|
* @since 0.1.11
|
|
436
436
|
* @status stable
|
|
437
437
|
* @spec RFC 6960
|
|
@@ -458,12 +458,17 @@ var OCSP_REQUEST = schema.seq([
|
|
|
458
458
|
* var der = await pki.ocsp.buildRequest({ cert: leafDer, issuer: caDer }, {});
|
|
459
459
|
* var req = pki.schema.ocsp.parseRequest(der);
|
|
460
460
|
* req.requestList[0].certID.serialNumberHex; // -> "1332"
|
|
461
|
+
* @opts
|
|
462
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
463
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
464
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
465
|
+
* refused with the `/too-large` code of this format.
|
|
461
466
|
*/
|
|
462
467
|
var parseRequest = pkix.makeParser({ pemLabel: "OCSP REQUEST", PemError: PemError, ErrorClass: OcspError, prefix: "ocsp", what: "OCSP request", topSchema: OCSP_REQUEST, ns: NS });
|
|
463
468
|
|
|
464
469
|
/**
|
|
465
470
|
* @primitive pki.schema.ocsp.parseResponse
|
|
466
|
-
* @signature pki.schema.ocsp.parseResponse(input) -> ocspResponse
|
|
471
|
+
* @signature pki.schema.ocsp.parseResponse(input, caps?) -> ocspResponse
|
|
467
472
|
* @since 0.1.11
|
|
468
473
|
* @status stable
|
|
469
474
|
* @spec RFC 6960
|
|
@@ -495,6 +500,11 @@ var parseRequest = pkix.makeParser({ pemLabel: "OCSP REQUEST", PemError: PemErro
|
|
|
495
500
|
* var res = pki.schema.ocsp.parseResponse(der);
|
|
496
501
|
* res.responseStatus.name; // -> "successful"
|
|
497
502
|
* res.basicResponse.responses[0].certStatus.type; // -> "good" | "revoked" | "unknown"
|
|
503
|
+
* @opts
|
|
504
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
505
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
506
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
507
|
+
* refused with the `/too-large` code of this format.
|
|
498
508
|
*/
|
|
499
509
|
var parseResponse = pkix.makeRecordingParser({ pemLabel: "OCSP RESPONSE", PemError: PemError, ErrorClass: OcspError, prefix: "ocsp", what: "OCSP response", topSchema: OCSP_RESPONSE, ns: NS }, "ocspResponse");
|
|
500
510
|
|
package/lib/schema-pkcs12.js
CHANGED
|
@@ -396,7 +396,7 @@ function _buildBag(rec, state, ctx) {
|
|
|
396
396
|
|
|
397
397
|
/**
|
|
398
398
|
* @primitive pki.schema.pkcs12.parse
|
|
399
|
-
* @signature pki.schema.pkcs12.parse(input) -> pfx
|
|
399
|
+
* @signature pki.schema.pkcs12.parse(input, caps?) -> pfx
|
|
400
400
|
* @since 0.1.18
|
|
401
401
|
* @status stable
|
|
402
402
|
* @spec RFC 7292, RFC 9579
|
|
@@ -441,6 +441,11 @@ function _buildBag(rec, state, ctx) {
|
|
|
441
441
|
* var der = await pki.pkcs12.build({ key: key, cert: cert }, { password: "changeit" });
|
|
442
442
|
* var store = pki.schema.pkcs12.parse(der);
|
|
443
443
|
* store.safeBags.map(function (b) { return b.type; });
|
|
444
|
+
* @opts
|
|
445
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
446
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
447
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
448
|
+
* refused with the `/too-large` code of this format.
|
|
444
449
|
*/
|
|
445
450
|
var parse = pkix.makeRecordingParser({
|
|
446
451
|
pemLabel: "PKCS12", PemError: PemError, ErrorClass: Pkcs12Error,
|
package/lib/schema-pkcs8.js
CHANGED
|
@@ -88,7 +88,7 @@ var ENCRYPTED_PRIVATE_KEY_INFO = schema.seq([
|
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* @primitive pki.schema.pkcs8.parse
|
|
91
|
-
* @signature pki.schema.pkcs8.parse(input) -> privateKey
|
|
91
|
+
* @signature pki.schema.pkcs8.parse(input, caps?) -> privateKey
|
|
92
92
|
* @since 0.1.9
|
|
93
93
|
* @status stable
|
|
94
94
|
* @spec RFC 5208, RFC 5958
|
|
@@ -107,12 +107,17 @@ var ENCRYPTED_PRIVATE_KEY_INFO = schema.seq([
|
|
|
107
107
|
* var key = pki.schema.pkcs8.parse(der);
|
|
108
108
|
* key.privateKeyAlgorithm.oid; // -> "1.3.101.112" (Ed25519)
|
|
109
109
|
* key.privateKey; // -> Buffer (the inner key encoding)
|
|
110
|
+
* @opts
|
|
111
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
112
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
113
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
114
|
+
* refused with the `/too-large` code of this format.
|
|
110
115
|
*/
|
|
111
116
|
var parse = pkix.makeParser({ pemLabel: "PRIVATE KEY", PemError: PemError, ErrorClass: Pkcs8Error, prefix: "pkcs8", what: "private key", topSchema: PRIVATE_KEY_INFO, ns: NS });
|
|
112
117
|
|
|
113
118
|
/**
|
|
114
119
|
* @primitive pki.schema.pkcs8.parseEncrypted
|
|
115
|
-
* @signature pki.schema.pkcs8.parseEncrypted(input) -> encrypted
|
|
120
|
+
* @signature pki.schema.pkcs8.parseEncrypted(input, caps?) -> encrypted
|
|
116
121
|
* @since 0.1.9
|
|
117
122
|
* @status stable
|
|
118
123
|
* @spec RFC 5958, RFC 5208
|
|
@@ -128,6 +133,11 @@ var parse = pkix.makeParser({ pemLabel: "PRIVATE KEY", PemError: PemError, Error
|
|
|
128
133
|
* var der = await pki.key.encrypt(await pki.key.export(pair.privateKey), "s3cr3t");
|
|
129
134
|
* var enc = pki.schema.pkcs8.parseEncrypted(der);
|
|
130
135
|
* enc.encryptionAlgorithm.oid; // -> "1.2.840.113549.1.5.13" (PBES2)
|
|
136
|
+
* @opts
|
|
137
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
138
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
139
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
140
|
+
* refused with the `/too-large` code of this format.
|
|
131
141
|
*/
|
|
132
142
|
var parseEncrypted = pkix.makeParser({ pemLabel: "ENCRYPTED PRIVATE KEY", PemError: PemError, ErrorClass: Pkcs8Error, prefix: "pkcs8", what: "encrypted private key", topSchema: ENCRYPTED_PRIVATE_KEY_INFO, ns: NS });
|
|
133
143
|
|
package/lib/schema-pkix.js
CHANGED
|
@@ -219,15 +219,155 @@ function _isPemArmor(buf) {
|
|
|
219
219
|
return true;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
/** @internal The codec's resource refusals, as distinct from its malformed-input refusals. A
|
|
223
|
+
* caller who tightened a cap has to be able to tell "your bytes are wrong" from "your cap is
|
|
224
|
+
* too small", and only the second is answered by raising the cap. */
|
|
225
|
+
var RESOURCE_REFUSALS = intrinsic.assign(intrinsic.create(null), {
|
|
226
|
+
"asn1/too-large": 1, "asn1/too-deep": 1, "asn1/too-many-items": 1,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
function decodeRoot(der, opts, caps, budget) {
|
|
230
|
+
try { return asn1.decode(der, _decodeOptions(opts, caps)); }
|
|
224
231
|
catch (e) {
|
|
232
|
+
/** @internal `rawDecodeErrors` keeps the codec's own code for a malformed body, which some
|
|
233
|
+
* callers pin. A resource refusal is still translated, that code being new. */
|
|
234
|
+
if (opts.rawDecodeErrors && !(e && RESOURCE_REFUSALS[e.code])) throw e;
|
|
235
|
+
if (e && RESOURCE_REFUSALS[e.code]) {
|
|
236
|
+
if (budget) {
|
|
237
|
+
try {
|
|
238
|
+
budget.trip(opts.what || "the input");
|
|
239
|
+
} catch (_b) {
|
|
240
|
+
/* allow:swallow-unverified the latch is the point here; the refusal below carries the cause */
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
throw new opts.ErrorClass(opts.prefix + "/too-large",
|
|
244
|
+
(opts.what || "the input") + " exceeds the decode budget for this parse: " + (e.message || _String(e)), e);
|
|
245
|
+
}
|
|
225
246
|
throw new opts.ErrorClass(opts.prefix + "/bad-der", (opts.what || "input") + " DER did not decode: " + ((e && e.message) || _String(e)), e);
|
|
226
247
|
}
|
|
227
248
|
}
|
|
228
249
|
|
|
229
|
-
|
|
230
|
-
|
|
250
|
+
/** @internal A fresh options object per decode. The strictness a format declares and the caps
|
|
251
|
+
* a caller asked for are combined here and nowhere else, so neither can be written onto the
|
|
252
|
+
* other's object and outlive this call. */
|
|
253
|
+
function _decodeOptions(opts, caps) {
|
|
254
|
+
if (!caps) return opts.ber ? { ber: true } : undefined;
|
|
255
|
+
var out = { maxBytes: caps.maxBytes, maxDepth: caps.maxDepth, maxItems: caps.maxItems };
|
|
256
|
+
if (opts.ber) out.ber = true;
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** @internal The decode caps a caller may name, each paired with the `C.LIMITS` default that
|
|
261
|
+
* is also its ceiling. A cap may tighten and may not loosen: the defaults are the resource
|
|
262
|
+
* the toolkit is willing to spend, and a caller raising one past them would be granting
|
|
263
|
+
* themselves more than the built-in refusal allows. */
|
|
264
|
+
var PARSE_CAPS = intrinsic.assign(intrinsic.create(null), {
|
|
265
|
+
maxBytes: "DER_MAX_BYTES",
|
|
266
|
+
maxDepth: "DER_MAX_DEPTH",
|
|
267
|
+
maxItems: "DER_MAX_ITEMS",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
/** @internal A format that reads something other than DER declares its own ceilings through
|
|
271
|
+
* `opts.capLimits`, so the bound a caller is held to is the one their parser actually uses. */
|
|
272
|
+
var CBOR_PARSE_CAPS = intrinsic.assign(intrinsic.create(null), {
|
|
273
|
+
maxBytes: "CBOR_MAX_BYTES",
|
|
274
|
+
maxDepth: "CBOR_MAX_DEPTH",
|
|
275
|
+
maxItems: "CBOR_MAX_ITEMS",
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
var CBOR_RESOURCE_REFUSALS = intrinsic.assign(intrinsic.create(null), {
|
|
279
|
+
"cbor/too-large": 1, "cbor/too-deep": 1, "cbor/too-many-items": 1,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
function isCborResourceRefusal(e) {
|
|
283
|
+
return !!(e && typeof e.code === "string" && CBOR_RESOURCE_REFUSALS[e.code] === 1);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function cborParseOpts(ErrorClass, prefix, what) {
|
|
287
|
+
var out = intrinsic.create(null);
|
|
288
|
+
out.ErrorClass = ErrorClass;
|
|
289
|
+
out.prefix = prefix;
|
|
290
|
+
out.what = what;
|
|
291
|
+
out.capLimits = CBOR_PARSE_CAPS;
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** @internal A parser door's options, held on a prototype-less object so a computed lookup on
|
|
296
|
+
* it answers from what the format declared. Every hand-rolled door builds its options here
|
|
297
|
+
* rather than as a literal in its own module. */
|
|
298
|
+
function parseOpts(spec) {
|
|
299
|
+
var out = intrinsic.create(null);
|
|
300
|
+
_forEach(intrinsic.keys(spec), function (k) { out[k] = spec[k]; });
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** @internal Reads the caller's caps into a FRESH object. Nothing is written back onto what
|
|
305
|
+
* the caller passed, and nothing else is ever written onto the returned one, so a resource
|
|
306
|
+
* option cannot become a strictness flag on a shared object. */
|
|
307
|
+
function parseCaps(callerOpts, opts) {
|
|
308
|
+
var E = function (message) { return new opts.ErrorClass(opts.prefix + "/bad-input", message); };
|
|
309
|
+
if (callerOpts === undefined || callerOpts === null) callerOpts = _emptyOptions;
|
|
310
|
+
if (typeof callerOpts !== "object" || intrinsic.isArray(callerOpts) || guard.bytes.isByteSource(callerOpts)) {
|
|
311
|
+
throw E("parse options must be an object of decode caps");
|
|
312
|
+
}
|
|
313
|
+
var capLimits = opts.capLimits || PARSE_CAPS;
|
|
314
|
+
guard.identifier.assertKnownKeys(callerOpts, capLimits,
|
|
315
|
+
function (code, message) { return new opts.ErrorClass(code, message); },
|
|
316
|
+
opts.prefix + "/bad-input", "parse does not take the option ");
|
|
317
|
+
var caps = intrinsic.create(null);
|
|
318
|
+
_forEach(intrinsic.keys(capLimits), function (key) {
|
|
319
|
+
var ceiling = constants.LIMITS[capLimits[key]];
|
|
320
|
+
var asked = callerOpts[key];
|
|
321
|
+
if (asked === undefined) { caps[key] = ceiling; return; }
|
|
322
|
+
if (!intrinsic.isInteger(asked) || asked < 0) {
|
|
323
|
+
throw E(key + " must be a non-negative integer no greater than " + ceiling);
|
|
324
|
+
}
|
|
325
|
+
if (asked > ceiling) {
|
|
326
|
+
throw E(key + " " + asked + " is above the built-in ceiling " + ceiling + "; a cap may only tighten");
|
|
327
|
+
}
|
|
328
|
+
caps[key] = asked;
|
|
329
|
+
});
|
|
330
|
+
return caps;
|
|
331
|
+
}
|
|
332
|
+
var _emptyOptions = intrinsic.freeze(intrinsic.create(null));
|
|
333
|
+
|
|
334
|
+
/** @internal The door every format parser opens, whether it composes the shared factory or
|
|
335
|
+
* hand-rolls its walk. `build(rootNode, ns)` does the format's own work; everything around it
|
|
336
|
+
* is the part that must not be re-implemented per parser, because each re-implementation is
|
|
337
|
+
* another place the caller's caps can go missing or the latch can go unread. */
|
|
338
|
+
function runParseWith(input, opts, callerOpts, build) {
|
|
339
|
+
var caps = parseCaps(callerOpts, opts);
|
|
340
|
+
var budget = guard.limits.budget({ maxBytes: caps.maxBytes });
|
|
341
|
+
var ns = _nsWithBudget(opts.ns, budget);
|
|
342
|
+
var result;
|
|
343
|
+
try {
|
|
344
|
+
result = build(decodeRoot(coerceToDer(input, opts), opts, caps, budget), ns, caps, budget);
|
|
345
|
+
} catch (e) {
|
|
346
|
+
if (guard.limits.isBudgetExceeded(e)) throw _budgetRefusal(opts, e);
|
|
347
|
+
throw e;
|
|
348
|
+
}
|
|
349
|
+
if (budget.exhausted()) throw _budgetRefusal(opts, null);
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function runParse(input, opts, callerOpts) {
|
|
354
|
+
return runParseWith(input, opts, callerOpts, function (root, ns) {
|
|
355
|
+
return schema.walk(opts.topSchema, root, ns).result;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** @internal The re-read at the door is what makes the latch worth having: a catch anywhere
|
|
360
|
+
* under the walk may absorb the exception, and this still refuses. */
|
|
361
|
+
function _budgetRefusal(opts, cause) {
|
|
362
|
+
return new opts.ErrorClass(opts.prefix + "/too-large",
|
|
363
|
+
(opts.what || "the input") + " exceeds the decode budget for this parse", cause || undefined);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function _nsWithBudget(ns, budget) {
|
|
367
|
+
var out = intrinsic.create(null);
|
|
368
|
+
_forEach(intrinsic.keys(ns), function (k) { out[k] = ns[k]; });
|
|
369
|
+
out.budget = budget;
|
|
370
|
+
return out;
|
|
231
371
|
}
|
|
232
372
|
|
|
233
373
|
var DN_SHORT = constants.NAMES.DN_SHORT;
|
|
@@ -1356,7 +1496,7 @@ function rootSequenceChildren(root, minLen, maxLen) {
|
|
|
1356
1496
|
}
|
|
1357
1497
|
|
|
1358
1498
|
function makeParser(opts) {
|
|
1359
|
-
return function (input) { return runParse(input, opts); };
|
|
1499
|
+
return function (input, callerOpts) { return runParse(input, opts, callerOpts); };
|
|
1360
1500
|
}
|
|
1361
1501
|
|
|
1362
1502
|
function makeRecordingParser(opts, kind) {
|
|
@@ -1430,6 +1570,12 @@ module.exports = {
|
|
|
1430
1570
|
isPemArmor: _isPemArmor,
|
|
1431
1571
|
decodeRoot: decodeRoot,
|
|
1432
1572
|
runParse: runParse,
|
|
1573
|
+
runParseWith: runParseWith,
|
|
1574
|
+
parseCaps: parseCaps,
|
|
1575
|
+
CBOR_PARSE_CAPS: CBOR_PARSE_CAPS,
|
|
1576
|
+
isCborResourceRefusal: isCborResourceRefusal,
|
|
1577
|
+
cborParseOpts: cborParseOpts,
|
|
1578
|
+
parseOpts: parseOpts,
|
|
1433
1579
|
makeNS: makeNS,
|
|
1434
1580
|
versionReader: versionReader,
|
|
1435
1581
|
DN_SHORT: DN_SHORT,
|
package/lib/schema-smime.js
CHANGED
|
@@ -187,7 +187,7 @@ var SMIME_CAPABILITIES = schema.seqOf(SMIME_CAPABILITY, {
|
|
|
187
187
|
|
|
188
188
|
/**
|
|
189
189
|
* @primitive pki.schema.smime.parseSigningCertificate
|
|
190
|
-
* @signature pki.schema.smime.parseSigningCertificate(der) -> { certs, policies }
|
|
190
|
+
* @signature pki.schema.smime.parseSigningCertificate(der, caps?) -> { certs, policies }
|
|
191
191
|
* @since 0.1.22
|
|
192
192
|
* @status stable
|
|
193
193
|
* @spec RFC 5035, RFC 2634
|
|
@@ -207,6 +207,11 @@ var SMIME_CAPABILITIES = schema.seqOf(SMIME_CAPABILITY, {
|
|
|
207
207
|
* var av = b.sequence([b.sequence([essCertId])]); // SigningCertificate { certs }
|
|
208
208
|
* var sc = pki.schema.smime.parseSigningCertificate(av);
|
|
209
209
|
* sc.certs[0].hashAlgorithm.name; // "sha1" (implied)
|
|
210
|
+
* @opts
|
|
211
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
212
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
213
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
214
|
+
* refused with the `/too-large` code of this format.
|
|
210
215
|
*/
|
|
211
216
|
var parseSigningCertificate = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: SmimeError, prefix: "smime", what: "SigningCertificate", topSchema: SIGNING_CERTIFICATE, ns: NS });
|
|
212
217
|
|
|
@@ -236,7 +241,7 @@ var parseSigningCertificateV2 = pkix.makeParser({ pemLabel: null, PemError: PemE
|
|
|
236
241
|
|
|
237
242
|
/**
|
|
238
243
|
* @primitive pki.schema.smime.parseSmimeCapabilities
|
|
239
|
-
* @signature pki.schema.smime.parseSmimeCapabilities(der) -> { capabilities }
|
|
244
|
+
* @signature pki.schema.smime.parseSmimeCapabilities(der, caps?) -> { capabilities }
|
|
240
245
|
* @since 0.1.22
|
|
241
246
|
* @status stable
|
|
242
247
|
* @spec RFC 8551
|
|
@@ -253,6 +258,11 @@ var parseSigningCertificateV2 = pkix.makeParser({ pemLabel: null, PemError: PemE
|
|
|
253
258
|
* var cap = b.sequence([b.oid(pki.oid.byName("aes256-CBC"))]);
|
|
254
259
|
* var caps = pki.schema.smime.parseSmimeCapabilities(b.sequence([cap]));
|
|
255
260
|
* caps.capabilities[0].name; // "aes256-CBC"
|
|
261
|
+
* @opts
|
|
262
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
263
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
264
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
265
|
+
* refused with the `/too-large` code of this format.
|
|
256
266
|
*/
|
|
257
267
|
var parseSmimeCapabilities = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: SmimeError, prefix: "smime", what: "SMIMECapabilities", topSchema: SMIME_CAPABILITIES, ns: NS });
|
|
258
268
|
|
package/lib/schema-tsp.js
CHANGED
|
@@ -46,6 +46,8 @@ var PemError = frameworkError.PemError;
|
|
|
46
46
|
|
|
47
47
|
var NS = pkix.makeNS("tsp", TspError, oid);
|
|
48
48
|
|
|
49
|
+
var _TOKEN_PARSE_OPTS = pkix.parseOpts({ ErrorClass: TspError, prefix: "tsp", what: "the timeStampToken" });
|
|
50
|
+
|
|
49
51
|
var ALGORITHM_IDENTIFIER = pkix.algorithmIdentifier(NS);
|
|
50
52
|
var EXTENSION = pkix.extension(NS);
|
|
51
53
|
|
|
@@ -250,7 +252,7 @@ var TIME_STAMP_REQ = schema.seq([
|
|
|
250
252
|
|
|
251
253
|
/**
|
|
252
254
|
* @primitive pki.schema.tsp.parseRequest
|
|
253
|
-
* @signature pki.schema.tsp.parseRequest(input) -> timeStampReq
|
|
255
|
+
* @signature pki.schema.tsp.parseRequest(input, caps?) -> timeStampReq
|
|
254
256
|
* @since 0.2.19
|
|
255
257
|
* @status stable
|
|
256
258
|
* @spec RFC 3161
|
|
@@ -268,12 +270,17 @@ var TIME_STAMP_REQ = schema.seq([
|
|
|
268
270
|
* var req = pki.schema.tsp.parseRequest(der);
|
|
269
271
|
* req.certReq; // -> boolean
|
|
270
272
|
* req.messageImprint.hashedMessage; // -> Buffer (the raw digest)
|
|
273
|
+
* @opts
|
|
274
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
275
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
276
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
277
|
+
* refused with the `/too-large` code of this format.
|
|
271
278
|
*/
|
|
272
279
|
var parseRequest = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: TspError, prefix: "tsp", what: "TimeStampReq", topSchema: TIME_STAMP_REQ, ns: NS });
|
|
273
280
|
|
|
274
281
|
/**
|
|
275
282
|
* @primitive pki.schema.tsp.parseTstInfo
|
|
276
|
-
* @signature pki.schema.tsp.parseTstInfo(input) -> tstInfo
|
|
283
|
+
* @signature pki.schema.tsp.parseTstInfo(input, caps?) -> tstInfo
|
|
277
284
|
* @since 0.1.13
|
|
278
285
|
* @status stable
|
|
279
286
|
* @spec RFC 3161
|
|
@@ -299,12 +306,17 @@ var parseRequest = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorCl
|
|
|
299
306
|
* var tst = pki.schema.tsp.parseTstInfo(der);
|
|
300
307
|
* tst.genTime; // -> Date
|
|
301
308
|
* tst.messageImprint.hashedMessage; // -> Buffer (the raw digest)
|
|
309
|
+
* @opts
|
|
310
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
311
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
312
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
313
|
+
* refused with the `/too-large` code of this format.
|
|
302
314
|
*/
|
|
303
315
|
var parseTstInfo = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: TspError, prefix: "tsp", what: "TSTInfo", topSchema: TST_INFO, ns: NS });
|
|
304
316
|
|
|
305
317
|
/**
|
|
306
318
|
* @primitive pki.schema.tsp.parse
|
|
307
|
-
* @signature pki.schema.tsp.parse(input) -> timeStampResp
|
|
319
|
+
* @signature pki.schema.tsp.parse(input, caps?) -> timeStampResp
|
|
308
320
|
* @since 0.1.13
|
|
309
321
|
* @status stable
|
|
310
322
|
* @spec RFC 3161
|
|
@@ -329,12 +341,17 @@ var parseTstInfo = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorCl
|
|
|
329
341
|
* var res = pki.schema.tsp.parse(der);
|
|
330
342
|
* res.status; // -> 0 (granted)
|
|
331
343
|
* res.timeStampToken.tstInfo.genTime; // -> Date (a granted token is decoded)
|
|
344
|
+
* @opts
|
|
345
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
346
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
347
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
348
|
+
* refused with the `/too-large` code of this format.
|
|
332
349
|
*/
|
|
333
350
|
var parse = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: TspError, prefix: "tsp", what: "TimeStampResp", topSchema: TIME_STAMP_RESP, ns: NS });
|
|
334
351
|
|
|
335
352
|
/**
|
|
336
353
|
* @primitive pki.schema.tsp.parseToken
|
|
337
|
-
* @signature pki.schema.tsp.parseToken(input) -> tstInfo
|
|
354
|
+
* @signature pki.schema.tsp.parseToken(input, caps?) -> tstInfo
|
|
338
355
|
* @since 0.1.13
|
|
339
356
|
* @status stable
|
|
340
357
|
* @spec RFC 3161, RFC 5652
|
|
@@ -364,13 +381,28 @@ var parse = pkix.makeParser({ pemLabel: null, PemError: PemError, ErrorClass: Ts
|
|
|
364
381
|
* var token = pki.schema.tsp.parseToken(tokenDer);
|
|
365
382
|
* token.tstInfo.genTime; // -> Date
|
|
366
383
|
* token.signerInfo.sid; // -> the TSA signer identifier
|
|
384
|
+
* @opts
|
|
385
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
386
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
387
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
388
|
+
* refused with the `/too-large` code of this format.
|
|
367
389
|
*/
|
|
368
|
-
function parseToken(input) {
|
|
390
|
+
function parseToken(input, callerOpts) {
|
|
391
|
+
/** @internal The caller's options are this door's to answer for, so they are read here rather
|
|
392
|
+
* than inside the CMS parser: a complaint about an option must not come back wearing the
|
|
393
|
+
* delegate's verdict about the content. The snapshot travels onward, because handing the
|
|
394
|
+
* caller's own object to the CMS parser would read each cap a second time. */
|
|
395
|
+
var caps = pkix.parseCaps(callerOpts, _TOKEN_PARSE_OPTS);
|
|
369
396
|
var der = pkix.coerceToDer(input, { pemLabel: null, PemError: PemError, ErrorClass: TspError, prefix: "tsp" });
|
|
370
397
|
var signed;
|
|
371
|
-
try { signed = cms.parse(der); }
|
|
398
|
+
try { signed = cms.parse(der, caps); }
|
|
372
399
|
catch (e) {
|
|
373
400
|
if (e instanceof TspError) throw e;
|
|
401
|
+
/** @internal A resource refusal says the cap was too small, not that the token is malformed,
|
|
402
|
+
* so it keeps that meaning rather than becoming a statement about the bytes. */
|
|
403
|
+
if (e && typeof e.code === "string" && e.code.indexOf("/too-large") !== -1) {
|
|
404
|
+
throw new TspError("tsp/too-large", "the timeStampToken exceeds the decode budget for this parse: " + (e.message || ""), e);
|
|
405
|
+
}
|
|
374
406
|
throw new TspError("tsp/bad-token", "the timeStampToken did not decode as a CMS SignedData: " + ((e && e.message) || String(e)), e);
|
|
375
407
|
}
|
|
376
408
|
if (signed.contentTypeName !== "signedData") {
|
package/lib/schema-x509.js
CHANGED
|
@@ -165,7 +165,7 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
|
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
167
|
* @primitive pki.schema.x509.parse
|
|
168
|
-
* @signature pki.schema.x509.parse(input) -> certificate
|
|
168
|
+
* @signature pki.schema.x509.parse(input, caps?) -> certificate
|
|
169
169
|
* @since 0.1.7
|
|
170
170
|
* @status stable
|
|
171
171
|
* @spec RFC 5280, X.509
|
|
@@ -194,6 +194,11 @@ var CERTIFICATE = pkix.signedEnvelope(NS, CERTIFICATE_TBS, {
|
|
|
194
194
|
* cert.subject.dn; // "CN=example.com, O=Example"
|
|
195
195
|
* cert.validity.notAfter; // Date
|
|
196
196
|
* cert.signatureAlgorithm.name; // "Ed25519" (the algorithm the issuer signed with)
|
|
197
|
+
* @opts
|
|
198
|
+
* - `maxBytes` / `maxDepth` / `maxItems` (number) -- decode caps for this parse. Each
|
|
199
|
+
* defaults to the matching `pki.C.LIMITS` figure and may only be set lower; a value
|
|
200
|
+
* above it, or an option outside this set, is refused. A parse that exceeds one is
|
|
201
|
+
* refused with the `/too-large` code of this format.
|
|
197
202
|
*/
|
|
198
203
|
var parse = pkix.makeRecordingParser({ pemLabel: "CERTIFICATE", PemError: PemError, ErrorClass: CertificateError, prefix: "x509", what: "certificate", topSchema: CERTIFICATE, ns: NS }, "certificate");
|
|
199
204
|
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:9e704e55-ccb2-4ecb-9370-04d6f58aa807",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-20T04:03:01.349Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/pki@0.8.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.8.3",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.3",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/pki@0.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.8.3",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/pki@0.8.
|
|
57
|
+
"ref": "@blamejs/pki@0.8.3",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|