@blamejs/pki 0.6.13 → 0.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +1 -1
  3. package/index.js +1 -1
  4. package/lib/acme.js +59 -815
  5. package/lib/asn1-der.js +7 -245
  6. package/lib/attrcert-sign.js +12 -260
  7. package/lib/attrcert-verify.js +1 -7
  8. package/lib/byte-reader.js +0 -8
  9. package/lib/byte-writer.js +0 -11
  10. package/lib/cbor-det.js +0 -54
  11. package/lib/cmc-build.js +15 -357
  12. package/lib/cmc-verify.js +6 -239
  13. package/lib/cmp-build.js +41 -317
  14. package/lib/cmp-session.js +73 -760
  15. package/lib/cmp-verify.js +32 -488
  16. package/lib/cms-compress.js +3 -32
  17. package/lib/cms-decrypt.js +29 -294
  18. package/lib/cms-encrypt.js +14 -234
  19. package/lib/cms-sign.js +29 -324
  20. package/lib/cms-verify.js +9 -500
  21. package/lib/composite-kem.js +2 -102
  22. package/lib/composite-sig.js +1 -77
  23. package/lib/constants.js +0 -249
  24. package/lib/crl-sign.js +9 -237
  25. package/lib/crl-verify.js +1 -10
  26. package/lib/crmf-sign.js +19 -198
  27. package/lib/crmf-verify.js +1 -12
  28. package/lib/csr-sign.js +3 -34
  29. package/lib/csr-verify.js +1 -12
  30. package/lib/ct.js +28 -253
  31. package/lib/edwards-point.js +10 -44
  32. package/lib/est.js +28 -764
  33. package/lib/framework-error.js +4 -182
  34. package/lib/guard-all.js +1 -58
  35. package/lib/guard-async.js +1 -36
  36. package/lib/guard-bytes.js +6 -650
  37. package/lib/guard-compress.js +5 -102
  38. package/lib/guard-crypto.js +1 -40
  39. package/lib/guard-der.js +2 -93
  40. package/lib/guard-encoding.js +2 -60
  41. package/lib/guard-header.js +1 -36
  42. package/lib/guard-identifier.js +7 -531
  43. package/lib/guard-intrinsic.js +1 -150
  44. package/lib/guard-json.js +10 -73
  45. package/lib/guard-limits.js +1 -77
  46. package/lib/guard-list.js +1 -49
  47. package/lib/guard-name.js +3 -209
  48. package/lib/guard-parsed.js +7 -335
  49. package/lib/guard-range.js +1 -71
  50. package/lib/guard-secret.js +1 -102
  51. package/lib/guard-text.js +1 -64
  52. package/lib/guard-time.js +1 -97
  53. package/lib/hpke.js +3 -105
  54. package/lib/http-digest.js +14 -142
  55. package/lib/http-retry-after.js +1 -47
  56. package/lib/http-transport.js +21 -131
  57. package/lib/inspect.js +30 -284
  58. package/lib/ip-utils.js +6 -47
  59. package/lib/jose.js +7 -142
  60. package/lib/key.js +2 -67
  61. package/lib/lint.js +9 -194
  62. package/lib/merkle.js +1 -27
  63. package/lib/mime.js +9 -82
  64. package/lib/ocsp-request-verify.js +1 -14
  65. package/lib/ocsp-verify.js +1 -82
  66. package/lib/ocsp.js +11 -169
  67. package/lib/oid.js +5 -337
  68. package/lib/path-validate.js +103 -1492
  69. package/lib/pbes2.js +2 -89
  70. package/lib/pkcs12-build.js +31 -379
  71. package/lib/pki-build.js +64 -290
  72. package/lib/rc2.js +2 -18
  73. package/lib/rfc3339.js +4 -27
  74. package/lib/scep.js +59 -233
  75. package/lib/schema-all.js +0 -122
  76. package/lib/schema-attrcert.js +4 -146
  77. package/lib/schema-c509.js +153 -802
  78. package/lib/schema-cmc.js +5 -220
  79. package/lib/schema-cmp.js +2 -223
  80. package/lib/schema-cms.js +13 -427
  81. package/lib/schema-crl.js +5 -68
  82. package/lib/schema-crmf.js +6 -167
  83. package/lib/schema-csr.js +1 -54
  84. package/lib/schema-csrattrs.js +2 -87
  85. package/lib/schema-engine.js +0 -152
  86. package/lib/schema-ocsp.js +0 -117
  87. package/lib/schema-pkcs12.js +2 -93
  88. package/lib/schema-pkcs8.js +3 -35
  89. package/lib/schema-pkix.js +24 -655
  90. package/lib/schema-smime.js +0 -54
  91. package/lib/schema-tsp.js +3 -99
  92. package/lib/schema-x509.js +4 -63
  93. package/lib/shbs.js +11 -95
  94. package/lib/sign-scheme.js +2 -97
  95. package/lib/sigstore.js +9 -169
  96. package/lib/sleep.js +2 -8
  97. package/lib/smime.js +15 -408
  98. package/lib/tls-cert-compress.js +0 -62
  99. package/lib/trust.js +19 -185
  100. package/lib/tsp-sign.js +16 -270
  101. package/lib/validator-all.js +1 -30
  102. package/lib/validator-attcert.js +2 -46
  103. package/lib/validator-cose.js +2 -153
  104. package/lib/validator-keydesc.js +1 -37
  105. package/lib/validator-sig.js +1 -46
  106. package/lib/validator-tls.js +1 -88
  107. package/lib/validator-tpm.js +19 -122
  108. package/lib/verify-seam.js +1 -24
  109. package/lib/webauthn-mds.js +3 -400
  110. package/lib/webauthn.js +12 -833
  111. package/lib/webcrypto.js +5 -485
  112. package/lib/x509-sign.js +4 -108
  113. package/package.json +1 -1
  114. package/sbom.cdx.json +6 -6
@@ -1,78 +1,25 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- no operator-facing namespace. The documented surface is every guard that composes
6
- // this one, which is every guard that performs its work with a captured intrinsic: guard-bytes
7
- // (the byte-source door), guard-time (the evaluation instant), guard-name (distinguished-name
8
- // identity), guard-text (the byte-to-string decode), guard-secret (the wipe).
9
- //
10
- // guard-intrinsic -- invoke a captured method against a receiver without reading any property of
11
- // the captured function.
12
- //
13
- // Capturing a method at module load closes half of the hole. `var _fill =
14
- // Uint8Array.prototype.fill` freezes which function the guard will run, so a later
15
- // `Uint8Array.prototype.fill = noop` changes nothing. Then `_fill.call(view, 0)` reads `call` off
16
- // that function object, and the object is the one still sitting on the prototype where any caller
17
- // can reach it. Assigning `Uint8Array.prototype.fill.call = function () {}` installs an own
18
- // property that shadows `Function.prototype.call`, and the guard runs the caller's function with
19
- // the same result the un-captured code had. The wipe clears nothing. A distinguished name compares
20
- // equal to an unrelated one. A decode returns a string the caller chose. Every check around it
21
- // still runs and still passes.
22
- //
23
- // The uncurried form performs no property read at the call site. `_fill(view, 0)` invokes a
24
- // function object no caller holds a reference to, so nothing on it is left to poison. The binding
25
- // happens here, at load, while `Function.prototype.call` and `.bind` are still the language's own.
26
- //
27
- // The scope of the defense is replacement that happens after this module loads. Code running
28
- // before it is already inside the trust boundary and can reach further than any single method, so
29
- // there is no defense here to add for that case. What capture-then-uncurry buys is that a caller
30
- // who receives control later, through an option accessor or while a verb is suspended on an await,
31
- // cannot change what a guard does.
4
+ // @internal
32
5
 
33
6
  var _utilTypes = require("util").types;
34
7
 
35
8
  var _call = Function.prototype.call;
36
9
  var _bind = Function.prototype.bind;
37
- // The invocation primitive `uncurry` itself is built out of. Binding as `_bind.call(_call, fn)`
38
- // would read `call` off the captured bind function, which is the very shape this module exists to
39
- // remove -- and `uncurry` is exported, so it can run long after load, while another guard
40
- // initializes. `Reflect.apply` is invoked directly, so no property of it is consulted either.
41
10
  var _reflectApply = Reflect.apply;
42
11
 
43
- // isArray -- the array test, snapshotted for the same reason as the predicates below. It decides
44
- // whether a value is walked as a list at all, so one answering `false` makes an index scan report
45
- // nothing and every rule keyed on what that scan found silently applies to nothing.
46
12
  var _isArray = Array.isArray;
47
13
 
48
- // The Buffer constructors, snapshotted for the same reason. `Buffer.from` is a writable property
49
- // of the `Buffer` global and it is how this toolkit turns a backing store into something it can
50
- // read or clear; one returning a buffer over DIFFERENT memory hands every later step a decoy, so a
51
- // wipe zeroes the decoy while the plaintext it was aimed at stays readable.
52
14
  var _bufferFrom = Buffer.from;
53
15
  var _bufferAlloc = Buffer.alloc;
54
16
  var _bufferConcat = Buffer.concat;
55
17
  var _bufferIsBuffer = Buffer.isBuffer;
56
18
  var _bufferByteLength = Buffer.byteLength;
57
19
  var _bufferCompare = Buffer.compare;
58
- // `Buffer.prototype.equals` is the byte-identity test a binding decides on: an OCSP CertID says the
59
- // response is about this issuer, a responder ID says this key signed it. Dispatched live, one
60
- // answering true makes a response about a DIFFERENT certificate match the one being asked about.
61
20
  var _bufferEquals = uncurry(Buffer.prototype.equals);
62
- // Buffer#toString, uncurried at load. Used to build dedup keys (a hex string) from bytes the toolkit
63
- // owns; dispatched live, a replaced toString could make two distinct values key alike or one value key
64
- // differently on two reads, so a dedup over untrusted-adjacent bytes would merge or split wrongly.
65
21
  var _bufferToString = uncurry(Buffer.prototype.toString);
66
22
 
67
- // The rest of what a guard reads from the runtime while it is deciding something. These are
68
- // grouped here rather than captured file by file so the set is enumerable in one place and a guard
69
- // added later inherits it: a reader asking "what can a caller still reach" has one list to read.
70
- //
71
- // The reflective operations are the load-bearing ones. `getOwnPropertyDescriptor` is how the
72
- // identifier guard learns whether a field is an accessor, `getPrototypeOf` and `ownKeys` are how it
73
- // walks a chain honestly, and `isView` is how the byte guard recognizes the shape whose backing
74
- // store it must refuse when shared. A replacement for any of them answers the question the guard
75
- // asked on the caller's behalf.
76
23
  var _isView = ArrayBuffer.isView;
77
24
  var _isInteger = Number.isInteger;
78
25
  var _isSafeInteger = Number.isSafeInteger;
@@ -93,24 +40,11 @@ var _mathFloor = Math.floor;
93
40
  var _mathCeil = Math.ceil;
94
41
  var _mathMin = Math.min;
95
42
  var _mathMax = Math.max;
96
- // A numeric parse a bound is then compared against: one answering a larger value widens the bound
97
- // the comparison was written to enforce.
98
43
  var _parseInt = parseInt;
99
44
  var _promiseResolve = Promise.resolve;
100
45
  var _promiseReject = Promise.reject;
101
- // The well-known async-iteration symbol, captured at load. `for await` uses this symbol at the
102
- // language level regardless of the global `Symbol` object, so a classifier that reads
103
- // `Symbol.asyncIterator` live would disagree with the loop the moment a co-resident replaced the
104
- // writable `Symbol` global: a real async iterable would be looked up under the wrong key, judged not
105
- // iterable, and refused where the engine would have consumed it. Reading the captured symbol keeps
106
- // the door's answer and the loop's behavior the same.
107
46
  var _asyncIterator = Symbol.asyncIterator;
108
47
 
109
- // The array operations, uncurried at load. These run on arrays the TOOLKIT owns -- an `ownKeys`
110
- // result, a local accumulator -- so the receiver is never a caller's object; what is caller-
111
- // reachable is `Array.prototype` itself. A `forEach` replaced with a no-op makes a scan over
112
- // perfectly real keys report nothing, and a check keyed on what that scan found then passes
113
- // vacuously, which is the same fail-open shape as an index test that answers `false`.
114
48
  var _arrForEach = uncurry(Array.prototype.forEach);
115
49
  var _arrMap = uncurry(Array.prototype.map);
116
50
  var _arrFilter = uncurry(Array.prototype.filter);
@@ -123,10 +57,6 @@ var _arrSlice = uncurry(Array.prototype.slice);
123
57
  var _arrJoin = uncurry(Array.prototype.join);
124
58
  var _arrPush = uncurry(Array.prototype.push);
125
59
 
126
- // The string and byte-view operations a decision is then made on. A `toUpperCase` or `toLowerCase`
127
- // replaced after load changes which registry row an algorithm name resolves to; a `subarray`
128
- // returning a different window hands the next step bytes from somewhere else in the same buffer;
129
- // and a radix conversion is how a key's own numbers are read back before they are compared.
130
60
  var _strToUpperCase = uncurry(String.prototype.toUpperCase);
131
61
  var _strToLowerCase = uncurry(String.prototype.toLowerCase);
132
62
  var _strIndexOf = uncurry(String.prototype.indexOf);
@@ -135,11 +65,6 @@ var _abSlice = uncurry(ArrayBuffer.prototype.slice);
135
65
  var _numToString = uncurry(Number.prototype.toString);
136
66
  var _bigIntToString = uncurry(BigInt.prototype.toString);
137
67
 
138
- // The collection operations, uncurried. A guard's cycle-safe chain walk is a `Set` it owns, and
139
- // `has` is what stops it: one answering `true` ends the walk at the first prototype, so a scan that
140
- // should have found an accessor two levels up reports nothing and the rule keyed on it passes. The
141
- // registry lookups are the same shape from the other side -- a `get` that answers for a key never
142
- // stored hands a guard a member list for an object it has never seen.
143
68
  var _setAdd = uncurry(Set.prototype.add);
144
69
  var _setHas = uncurry(Set.prototype.has);
145
70
  var _mapGet = uncurry(Map.prototype.get);
@@ -149,32 +74,17 @@ var _weakGet = uncurry(WeakMap.prototype.get);
149
74
  var _weakSet = uncurry(WeakMap.prototype.set);
150
75
  var _weakHas = uncurry(WeakMap.prototype.has);
151
76
  var _taSet = uncurry(Uint8Array.prototype.set);
152
- // Own-membership, which is how this toolkit asks whether a key is really in a table rather than
153
- // inherited from a prototype somebody extended. Spelled `Object.prototype.hasOwnProperty.call(t, k)`
154
- // it reads two replaceable properties to answer one question, and either of them answering yes puts
155
- // a name into an allowlist that never contained it.
156
77
  var _hasOwn = uncurry(Object.prototype.hasOwnProperty);
157
- // The conversions, which are globals and so ordinary writable properties of globalThis. They read
158
- // like language rather than like code, which is why they were the last of these to be noticed: an
159
- // index test is `String(Number(k)) === k`, a narrow is `Number(v)`, and a header value is
160
- // `String(value)` before it is scanned for injection. A replacement decides all three.
161
78
  var _String = String;
162
79
  var _Number = Number;
163
80
  var _Boolean = Boolean;
164
81
  var _BigInt = BigInt;
165
82
  var _Date = Date;
166
83
  var _isFinite = globalThis.isFinite;
167
- // The byte-view constructors, for the same reason: a private copy is only private if the store and
168
- // the view over it are the ones this code asked for. A replaced constructor hands back a view over
169
- // storage of its own choosing, while the cleanup still tracks the store that was allocated.
170
84
  var _ArrayBuffer = ArrayBuffer;
171
85
  var _Uint8Array = Uint8Array;
172
86
  var _DataView = DataView;
173
- // Boxing a primitive, which decides what a reflection scan then sees.
174
87
  var _ObjectFn = Object;
175
- // The prototype OBJECTS, used as identity sentinels: "is this a plain object", "is this a Buffer",
176
- // "has the chain walk reached the top". Each is reached as a property of a replaceable global, so
177
- // after a replacement the sentinel is a different object and every comparison against it is false.
178
88
  var _ObjectProto = Object.prototype;
179
89
  var _BufferProto = Buffer.prototype;
180
90
  var _ArrayProto = Array.prototype;
@@ -182,15 +92,6 @@ var _Set = Set;
182
92
  var _Map = Map;
183
93
  var _WeakMap = WeakMap;
184
94
 
185
- // types -- the slot predicates, snapshotted at load.
186
- //
187
- // `util.types` is an ordinary object on an ordinary module export, so `util.types.isDate = () =>
188
- // true` reaches every guard that asks it at call time. These predicates are how this toolkit
189
- // answers "what IS this value", in preference to a prototype test a caller can satisfy, so a
190
- // caller who gets to answer them instead has replaced the one question a lookalike cannot lie
191
- // about. Every own function property is carried across rather than a written-out list, because a
192
- // list is a thing to get wrong and a predicate added by a later runtime would silently be missing
193
- // from it.
194
95
  var _types = Object.create(null);
195
96
  var _typeNames = Object.getOwnPropertyNames(_utilTypes);
196
97
  for (var _i = 0; _i < _typeNames.length; _i++) {
@@ -200,15 +101,6 @@ for (var _i = 0; _i < _typeNames.length; _i++) {
200
101
  }
201
102
  Object.freeze(_types);
202
103
 
203
- // uncurry(fn) -> function (receiver, ...args) { return fn.call(receiver, ...args); }
204
- // fn : the intrinsic captured from a prototype, or an intrinsic getter function.
205
- //
206
- // The returned function is private to whichever module called `uncurry`, so no property of it is
207
- // reachable from outside.
208
- //
209
- // A `.call` on a captured intrinsic is the shape this replaces. It reads as safe while being as
210
- // reachable as the un-captured method was, so it is flagged anywhere in lib/, including a guard
211
- // not yet written. The safe spelling is also the tripwire for the next one.
212
104
  // @enforced-by guard-shape-reinlined
213
105
  // @guard-shape \b_[A-Za-z][A-Za-z0-9_$]*\.(?:call|apply)\s*\(
214
106
  function uncurry(fn) {
@@ -218,21 +110,7 @@ function uncurry(fn) {
218
110
  return _reflectApply(_bind, _call, [fn]);
219
111
  }
220
112
 
221
- // getter(proto, name, who) -> the prototype's own accessor, uncurried.
222
- // proto : the intrinsic prototype the accessor lives on.
223
- // name : the accessor's property name.
224
- // who : how the prototype is named in the refusal, for a runtime that has no such accessor.
225
- //
226
- // A view's size, offset and backing store are accessors on a prototype, which means they are
227
- // replaceable, which means every rule keyed on one is answerable by whoever replaced it. Taking the
228
- // descriptor's `get` at load and uncurrying it reads the value's own slot and consults nothing.
229
- // A runtime without the accessor is refused rather than fallen back from: a fallback here would be
230
- // the value's own `length`, which is the property this exists to stop reading.
231
113
  // @enforced-by behavioral -- reading a descriptor's `get` is not distinguishable from testing one
232
- // for presence (`!!d.get`, which four guards do legitimately), so a lexical detector would
233
- // false-fire on every accessor-shape check in the tree; the vectors that replace an accessor and
234
- // drive the composing guard are the guard. The `.call` half of the shape is covered by uncurry's
235
- // guard-shape-reinlined detector.
236
114
  function getter(proto, name, who) {
237
115
  var d = _getOwnPropertyDescriptor(proto, name);
238
116
  if (!d || typeof d.get !== "function") {
@@ -245,24 +123,7 @@ function getter(proto, name, who) {
245
123
  var _taByteLength = getter(_getPrototypeOf(Uint8Array.prototype), "byteLength", "%TypedArray%.prototype");
246
124
  var _dvByteLength = getter(DataView.prototype, "byteLength", "DataView.prototype");
247
125
 
248
- // sizeOf(value) -> how large the value is: a string's character count, a view's byte count.
249
- //
250
- // The size of an input decides a cap, a bound, an emptiness gate and a loop end all over this
251
- // toolkit, and `value.length` asks the prototype for it. On a view that property is a replaceable
252
- // accessor: one reporting a small number for a large buffer disables every size cap at once, and
253
- // one reporting a positive number for an empty buffer passes an empty secret, an empty DER element
254
- // and an empty name through the gates that exist to refuse them. So a view is measured from its
255
- // slot, and a DataView carries its own accessor rather than the typed-array one.
256
- //
257
- // A primitive string's `length` is a data property the language maintains and no code can redefine,
258
- // so the string arm reads it directly. The two arms are one function because a size comparison
259
- // should have one spelling: a second way to measure is a second thing to get wrong, and the arm
260
- // that gets skipped is the one that was replaceable. Anything that is neither is refused rather
261
- // than measured, since its `length` would be whatever its author wrote.
262
126
  // @enforced-by behavioral -- `x.length` on a byte view is the same three tokens as on a string or
263
- // an array, where the read is safe and ubiquitous, and the receiver's kind is not knowable
264
- // statically in this codebase's style; a detector would flag every array bound in the tree. The
265
- // over-cap and control-byte vectors under a replaced accessor are the guard.
266
127
  function sizeOf(value) {
267
128
  if (typeof value === "string") return value.length;
268
129
  if (_types.isDataView(value)) return _dvByteLength(value);
@@ -271,11 +132,6 @@ function sizeOf(value) {
271
132
  (value === null ? "null" : typeof value));
272
133
  }
273
134
 
274
- // Frozen, and that is what makes the capture worth taking. A consumer binds these at load, but it
275
- // also reads several of them as `intrinsic.<name>(...)` at the call itself, and the module registry
276
- // hands every caller this same object: assigning one property would redirect that call in every
277
- // module at once, which is the substitution the captures exist to refuse. Freezing costs nothing
278
- // here because nothing writes to it after load.
279
135
  module.exports = Object.freeze({
280
136
  uncurry: uncurry,
281
137
  getter: getter,
@@ -333,12 +189,7 @@ module.exports = Object.freeze({
333
189
  arraySlice: _arrSlice,
334
190
  join: _arrJoin,
335
191
  hasOwn: _hasOwn,
336
- // Invocation itself. `fn.apply(...)` reads `apply` off Function.prototype, so a replacement
337
- // decides whether a verb's body runs at all and what it appears to return; `Reflect.apply` is
338
- // invoked directly and consults no property of the function.
339
192
  apply: _reflectApply,
340
- // And the cleanup half of a promise chain: `.finally` is where a copied secret is released, so a
341
- // replacement that drops its callback leaves the plaintext copy alive for the process's lifetime.
342
193
  promiseFinally: uncurry(Promise.prototype["finally"]),
343
194
  String: _String,
344
195
  Number: _Number,
package/lib/guard-json.js CHANGED
@@ -1,72 +1,27 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- no operator-facing namespace. The documented surface is the
6
- // consumers whose JSON integrity composes this guard (pki.jose message parsing,
7
- // pki.acme resource objects, pki.webcrypto JWK unwrap).
8
- //
9
- // guard-json -- strict, bounded parse of an untrusted JSON document. JSON.parse
10
- // silently takes the last value of a duplicate member, so a signed or wrapped
11
- // object carrying two members of the same name resolves differently for a
12
- // verifier than for a consumer. That is the JSON smuggling / parser-differential
13
- // class (CWE-20 / CWE-436). It also caps neither size nor nesting (CWE-770 /
14
- // CWE-400), and over a Buffer substitutes U+FFFD for invalid UTF-8 instead of failing.
15
- //
16
- // This is a single hand-written recursive-descent reader that composes
17
- // guard.text.decode (the byte cap runs before the strict/fatal UTF-8 decode, so
18
- // an oversized document is rejected before it is materialized), then rejects a
19
- // duplicate member at every nesting depth, caps nesting, assigns each member as
20
- // an own data property (a "__proto__" key becomes a normal member: it cannot
21
- // mutate the prototype nor, being a non-own assignment for a primitive, silently
22
- // defeat the duplicate-member gate), and enforces the RFC 8259 number/string
23
- // grammar (no leading zero, a fraction/exponent needs a digit, no bare "-").
24
- //
4
+ // @internal
25
5
  var text = require("./guard-text");
26
- // Taken at load. `defineProperty` is how a decoded member lands on the result without consulting a
27
- // setter, and `fromCharCode` is how an escape becomes the character it names; a replacement for
28
- // either decides what this parser produces. See guard-intrinsic for the whole captured set.
29
6
  var _defineProperty = require("./guard-intrinsic").defineProperty;
30
7
  var _freeze = require("./guard-intrinsic").freeze;
31
8
  var _fromCharCode = require("./guard-intrinsic").fromCharCode;
32
- // The character-code read the whole scanner is built on: whitespace, escapes and the control-byte
33
- // reject all consult it, so one that lies decides what this parser sees in the input.
34
9
  var _charCodeAt = require("./guard-intrinsic").uncurry(String.prototype.charCodeAt);
35
- // The scanner has already found where a number literal starts and ends; this is the step that cuts
36
- // it out. A replacement hands `Number` a different span than the one the parser validated, so the
37
- // value the document is understood to carry is not the value its bytes spell.
38
10
  var _strSlice = require("./guard-intrinsic").uncurry(String.prototype.slice);
39
- // The duplicate-member gate below asks whether a key is already present. Spelled
40
- // `Object.prototype.hasOwnProperty.call(...)` it reads two replaceable properties to answer that,
41
- // and either of them answering wrongly lets a document carry the same member twice.
42
11
  var _hasOwn = require("./guard-intrinsic").hasOwn;
43
- // The conversion that turns a validated number literal into the value the document is understood to
44
- // carry. A replacement returns something else for text this parser has already checked.
45
12
  var _Number = require("./guard-intrinsic").Number;
46
- // The gate that refuses a numeric token that overflowed to Infinity. A replacement answering true
47
- // admits it, and the document is understood to carry a value its bytes cannot spell.
48
13
  var _isFinite = require("./guard-intrinsic").isFinite;
49
14
  var _stringify = require("./guard-intrinsic").stringify;
50
- // Appended by index rather than through `push`, so the growth reads no prototype method at all.
51
15
  function _append(arr, v) { _defineProperty(arr, arr.length, { value: v, writable: true, enumerable: true, configurable: true }); }
52
16
  var limits = require("./guard-limits");
53
17
 
54
- // One hex digit's value, or -1. Written out because the three ranges ARE the rule.
55
18
  function _hexVal(c) {
56
- if (c >= 0x30 && c <= 0x39) return c - 0x30; // 0-9
57
- if (c >= 0x61 && c <= 0x66) return c - 0x61 + 10; // a-f
58
- if (c >= 0x41 && c <= 0x46) return c - 0x41 + 10; // A-F
19
+ if (c >= 0x30 && c <= 0x39) return c - 0x30;
20
+ if (c >= 0x61 && c <= 0x66) return c - 0x61 + 10;
21
+ if (c >= 0x41 && c <= 0x46) return c - 0x41 + 10;
59
22
  return -1;
60
23
  }
61
24
 
62
- // parse(input, ErrorClass, spec) -> value. `input` is a Buffer or a string.
63
- // spec = { maxBytes, maxDepth, badJson, tooDeep, duplicateMember, tooLarge,
64
- // badInput, label }, the caller's caps and frozen domain/reason codes.
65
- // Both caps are required authoring inputs: an omitted, NaN or fractional cap
66
- // would silently disable the bound it configures (a depth-uncapped recursive
67
- // descent escapes as a raw stack-overflow RangeError), so they are validated
68
- // through the shared cap guards at entry, maxDepth additionally against the
69
- // stack-safe recursion ceiling, so no caller cap can exceed frame safety.
70
25
  // @enforced-by json-parse-not-via-guard
71
26
  function parse(input, ErrorClass, spec) {
72
27
  function E(code, message, cause) { return new ErrorClass(code, message, cause); }
@@ -75,8 +30,6 @@ function parse(input, ErrorClass, spec) {
75
30
  }
76
31
  var maxBytes = limits.cap(spec.maxBytes, "guard.json.parse spec.maxBytes", undefined);
77
32
  var maxDepth = limits.depthCap(spec.maxDepth, "guard.json.parse spec.maxDepth", undefined);
78
- // Byte cap before the fatal UTF-8 decode (an oversized/ill-encoded document is
79
- // rejected before it is turned into a string).
80
33
  var str = text.decode(input, maxBytes, ErrorClass, {
81
34
  charset: "utf-8", fatal: true, tooLarge: spec.tooLarge, badDecode: spec.badJson, badInput: spec.badInput, label: spec.label,
82
35
  });
@@ -92,8 +45,6 @@ function parse(input, ErrorClass, spec) {
92
45
  if (c === "[") return array(depth);
93
46
  if (c === "\"") return string();
94
47
  if (c === "-" || (c >= "0" && c <= "9")) return number();
95
- // Through the captured slice, not `substr`: these three comparisons ARE the literal grammar, so
96
- // one returning something else accepts a token the document does not spell.
97
48
  if (_strSlice(str, i, i + 4) === "true") { i += 4; return true; }
98
49
  if (_strSlice(str, i, i + 5) === "false") { i += 5; return false; }
99
50
  if (_strSlice(str, i, i + 4) === "null") { i += 4; return null; }
@@ -101,7 +52,7 @@ function parse(input, ErrorClass, spec) {
101
52
  return undefined;
102
53
  }
103
54
  function object(depth) {
104
- i++; // {
55
+ i++;
105
56
  var out = {};
106
57
  ws();
107
58
  if (str[i] === "}") { i++; return out; }
@@ -113,8 +64,6 @@ function parse(input, ErrorClass, spec) {
113
64
  ws();
114
65
  if (str[i] !== ":") fail("expected ':'");
115
66
  i++;
116
- // Own data property (not out[key]=...): a "__proto__" key becomes a normal
117
- // member, never a prototype mutation nor a silent duplicate-gate bypass.
118
67
  _defineProperty(out, key, { value: value(depth + 1), writable: true, enumerable: true, configurable: true });
119
68
  ws();
120
69
  if (str[i] === ",") { i++; continue; }
@@ -123,7 +72,7 @@ function parse(input, ErrorClass, spec) {
123
72
  }
124
73
  }
125
74
  function array(depth) {
126
- i++; // [
75
+ i++;
127
76
  var out = [];
128
77
  ws();
129
78
  if (str[i] === "]") { i++; return out; }
@@ -136,7 +85,7 @@ function parse(input, ErrorClass, spec) {
136
85
  }
137
86
  }
138
87
  function string() {
139
- i++; // opening quote
88
+ i++;
140
89
  var s = "";
141
90
  for (;;) {
142
91
  if (i >= n) fail("unterminated string");
@@ -154,9 +103,6 @@ function parse(input, ErrorClass, spec) {
154
103
  else if (e === "r") s += "\r";
155
104
  else if (e === "t") s += "\t";
156
105
  else if (e === "u") {
157
- // Four hex digits, read as digits instead of matched as a pattern: the
158
- // scanner is already walking this string one character at a time, and a
159
- // parser handed hostile input should not hand any of it to a second engine.
160
106
  var cp = 0;
161
107
  if (i + 4 > n) fail("bad \\u escape");
162
108
  for (var h = 0; h < 4; h++) {
@@ -172,13 +118,6 @@ function parse(input, ErrorClass, spec) {
172
118
  } else s += c;
173
119
  }
174
120
  }
175
- // RFC 8259 sec. 6, enforced by the walk itself and not by re-matching the token
176
- // afterwards. The scan already knows where each part starts and ends, so the
177
- // grammar's three rules (an integer part that is "0" or has no leading zero, a
178
- // fraction with at least one digit, an exponent with at least one digit) are
179
- // checked as it goes. Re-matching what the scanner just read meant maintaining
180
- // the same grammar twice, in two notations, and the pattern was the copy whose
181
- // cost on a rejecting token could not be bounded from outside.
182
121
  function number() {
183
122
  var start = i;
184
123
  if (str[i] === "-") i++;
@@ -186,19 +125,19 @@ function parse(input, ErrorClass, spec) {
186
125
  while (i < n && str[i] >= "0" && str[i] <= "9") i++;
187
126
  var intLen = i - intStart;
188
127
  if (intLen === 0) fail("malformed number");
189
- if (intLen > 1 && str[intStart] === "0") fail("malformed number"); // no leading zero
128
+ if (intLen > 1 && str[intStart] === "0") fail("malformed number");
190
129
  if (str[i] === ".") {
191
130
  i++;
192
131
  var fracStart = i;
193
132
  while (i < n && str[i] >= "0" && str[i] <= "9") i++;
194
- if (i === fracStart) fail("malformed number"); // "1." has no fraction
133
+ if (i === fracStart) fail("malformed number");
195
134
  }
196
135
  if (str[i] === "e" || str[i] === "E") {
197
136
  i++;
198
137
  if (str[i] === "+" || str[i] === "-") i++;
199
138
  var expStart = i;
200
139
  while (i < n && str[i] >= "0" && str[i] <= "9") i++;
201
- if (i === expStart) fail("malformed number"); // "1e" has no exponent
140
+ if (i === expStart) fail("malformed number");
202
141
  }
203
142
  var v = _Number(_strSlice(str, start, i));
204
143
  if (!_isFinite(v)) fail("bad number");
@@ -210,6 +149,4 @@ function parse(input, ErrorClass, spec) {
210
149
  return result;
211
150
  }
212
151
 
213
- // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
214
- // call, so a writable export would let a caller replace the check rather than pass it.
215
152
  module.exports = _freeze({ parse: parse });
@@ -1,63 +1,18 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
- //
5
- // @internal -- no operator-facing namespace. The documented surface is the
6
- // decoders whose option validation composes these guards (pki.asn1.decode,
7
- // pki.cbor.decode).
8
- //
9
- // guard-limits -- fail-closed validation of operator-supplied decode limits at
10
- // config time (the tier that throws on a bad argument so the operator catches
11
- // the typo at boot). Enforced choke point: a codebase-patterns detector requires
12
- // the stack-safe recursion ceiling to live only here, so a new decoder cannot be
13
- // configured past it.
14
- //
15
- // Defends the parser-DoS / resource-exhaustion class (CWE-834 excessive
16
- // recursion, CWE-770 allocation without limits; MITRE T1499.001; D3FEND
17
- // Recursion-Bounding + Input-Size-Restriction). A recursive-descent decoder
18
- // bounded only by a caller-tunable maxDepth overflows the native call stack (a
19
- // raw RangeError, not a typed verdict) once the cap is raised past the frame
20
- // limit; depthCap refuses a maxDepth above the stack-safe ceiling. A bad limit
21
- // is an authoring bug, so this tier throws a TypeError (not a PkiError). NIST
22
- // 800-53 SI-10 / SC-5 do not require these bounds (framework lag). The control
23
- // that actually holds is the bound at the parser.
4
+ // @internal
24
5
 
25
6
  var constants = require("./constants");
26
- // The integer test, taken at load. Every bound below is only a bound while this answers honestly:
27
- // one returning true admits a NaN or fractional cap, which makes the comparison it guards always
28
- // false. See guard-intrinsic for the whole captured set.
29
7
  var _isInteger = require("./guard-intrinsic").isInteger;
30
8
  var _freeze = require("./guard-intrinsic").freeze;
31
- // And the size measurement, for the same reason one step further in: a cap compares against a
32
- // length, and on a byte view `length` is a replaceable accessor. One reporting a small number for a
33
- // large buffer leaves every byteCap below always-false, which is the size defense silently dead.
34
9
  var _sizeOf = require("./guard-intrinsic").sizeOf;
35
10
 
36
- // cap(value, key, dflt, opts) -> a validated bounded integer, or dflt when value
37
- // is undefined. A non-integer / non-finite / negative value fails closed
38
- // (Number.isInteger already rejects non-numbers, NaN, and Infinity).
39
- //
40
- // With no opts it is the config-time codec default: a bare TypeError with the
41
- // "decode:" prefix and a >= 0 floor (the asn1-der / cbor-det callers are
42
- // untouched). opts lets a caller in another currency reuse the same integer
43
- // floor with its own typed verdict and bounds, so a fractional/negative/NaN
44
- // bound cannot be spelled a fifth way with a dropped Number.isInteger:
45
- // E - a (code, message) -> Error factory; when given, an out-of-range
46
- // value throws E(code, ...) instead of the bare TypeError.
47
- // code - the domain/reason code passed to E.
48
- // label - names the argument in the message (defaults to key).
49
- // min - inclusive lower bound (default 0).
50
- // max - inclusive upper bound (optional).
51
11
  // @enforced-by behavioral -- a config-time cap validator has no rename-proof code
52
- // shape; the decode-rejects-a-bad-cap RED vectors (asn1/cbor/path) are the guard.
53
12
  function cap(value, key, dflt, opts) {
54
13
  if (value === undefined) return dflt;
55
14
  opts = opts || {};
56
15
  var min = opts.min === undefined ? 0 : opts.min;
57
- // The bounds themselves are authoring inputs: a NaN / fractional min or max
58
- // compares false against every value, silently disabling the check (a NaN min
59
- // even REPLACES the default >= 0 floor). Always a config-time TypeError --
60
- // the bound wiring is broken regardless of the value currency opts.E selects.
61
16
  if (!_isInteger(min) || (opts.max !== undefined && !_isInteger(opts.max))) {
62
17
  throw new TypeError("guard.limits.cap: the min/max bounds for " + key + " must be integers");
63
18
  }
@@ -70,9 +25,6 @@ function cap(value, key, dflt, opts) {
70
25
  return value;
71
26
  }
72
27
 
73
- // depthCap(value, key, dflt) -> a validated recursion-depth cap: cap() plus the
74
- // stack-safe ceiling, so a raised maxDepth cannot drive recursive descent into a
75
- // raw RangeError past the native frame limit.
76
28
  // @enforced-by guard-shape-reinlined
77
29
  // @guard-scope file
78
30
  // @guard-shape \bopts\.maxDepth\b
@@ -86,20 +38,8 @@ function depthCap(value, key, dflt) {
86
38
  return n;
87
39
  }
88
40
 
89
- // counter(max, E, code, label) -> { tick }. A parse-time item counter: the
90
- // recursive decoder calls tick() once per decoded element so a small input
91
- // cannot fan out into a massive eager node/element tree (CWE-770 / CWE-400 memory
92
- // amplification -- the class pki.cbor closed with CBOR_MAX_ITEMS). Unlike cap
93
- // (config-time TypeError), this is Tier-2 parse validation: an over-count throws
94
- // the caller's typed PkiError via the E(code, message) factory. `max` is the
95
- // caller's already-validated ceiling (an opts.maxItems run through cap()).
96
41
  // @enforced-by behavioral -- a monotone counter has no rename-proof code shape
97
- // distinct from any `n++ > max` loop bound; the memory-fanout RED vectors (a
98
- // dense TLV run rejects at the cap) driving the composing decoders are the guard.
99
42
  function counter(max, E, code, label) {
100
- // The ceiling is an authoring input: an undefined / NaN / fractional max
101
- // builds a counter whose `n > max` never fires, leaving a silently dead fanout
102
- // defense. Reject at construction (config-time TypeError).
103
43
  if (!_isInteger(max) || max < 0) {
104
44
  throw new TypeError("guard.limits.counter: max must be a non-negative integer");
105
45
  }
@@ -112,22 +52,8 @@ function counter(max, E, code, label) {
112
52
  };
113
53
  }
114
54
 
115
- // byteCap(buf, max, E, code, label) -> the same buffer, once proven within `max`
116
- // bytes. Bounds a caller-supplied buffer before an expensive hash / verify / parse
117
- // materializes over it (CWE-400 uncontrolled resource consumption / CWE-770
118
- // allocation without limits -- the class guard.text.decode closes for a decoded
119
- // string and counter closes for element fanout, here for a raw byte input). Tier-2:
120
- // an over-size input is hostile / malformed content, so it throws the caller's typed
121
- // PkiError via the E(code, message) factory. `max` is the caller's ceiling (a
122
- // C.LIMITS.* constant, or an operator max already run through cap()).
123
55
  // @enforced-by behavioral -- a `buf.length > cap` size gate has no rename-proof code
124
- // shape distinct from an arity / field-width check (children.length > 2,
125
- // ext.length > 0xffff), so a codebase-patterns detector would false-fire; the
126
- // over-size RED vectors driving the composing verifiers are the guard.
127
56
  function byteCap(buf, max, E, code, label) {
128
- // The ceiling is an authoring input: an undefined / NaN / fractional / negative
129
- // max makes `length > max` never fire, and the size defense is then silently
130
- // dead. Reject at config time (TypeError), regardless of the value currency E selects.
131
57
  if (!_isInteger(max) || max < 0) {
132
58
  throw new TypeError("guard.limits.byteCap: max must be a non-negative integer");
133
59
  }
@@ -138,6 +64,4 @@ function byteCap(buf, max, E, code, label) {
138
64
  return buf;
139
65
  }
140
66
 
141
- // Frozen for the reason the family header gives: a boundary reads its guard off this object at the
142
- // call, so a writable export would let a caller replace the check rather than pass it.
143
67
  module.exports = _freeze({ cap: cap, depthCap: depthCap, counter: counter, byteCap: byteCap });