@blamejs/pki 0.8.28 → 0.8.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/ocsp.js CHANGED
@@ -197,9 +197,16 @@ function _buildRequest(query, opts) {
197
197
  var issuer = _certOf(q.issuer, "the issuer certificate");
198
198
  return _buildCertID(cert, issuer, hashName).then(function (certID) {
199
199
  var reqChildren = [certID];
200
- if (q.singleRequestExtensions && q.singleRequestExtensions.length) {
201
- if (lightweight) throw _err("ocsp/bad-input", "the lightweight profile permits no singleRequestExtensions (RFC 5019 sec. 2.1.1)");
202
- reqChildren.push(b.explicit(0, b.sequence(q.singleRequestExtensions)));
200
+ if (q.singleRequestExtensions != null) {
201
+ /** @internal Read through the same door the sibling lists in this module use, so a value that is
202
+ * not an array is refused rather than passed over: read as truthy-and-has-length, an object or a
203
+ * number produced a Request carrying none of the extensions the caller asked for, and nothing in
204
+ * the result said so. */
205
+ var singles = pkiBuild.reqDenseArray(q.singleRequestExtensions, "singleRequestExtensions", _err, "ocsp/bad-input");
206
+ if (singles.length) {
207
+ if (lightweight) throw _err("ocsp/bad-input", "the lightweight profile permits no singleRequestExtensions (RFC 5019 sec. 2.1.1)");
208
+ reqChildren.push(b.explicit(0, b.sequence(singles)));
209
+ }
203
210
  }
204
211
  return b.sequence(reqChildren);
205
212
  });
@@ -479,11 +479,44 @@ function coerceToDer(input, opts) {
479
479
  * would otherwise be read end to end on the way to being refused for its size. */
480
480
  guard.limits.byteCap(buf, _COERCE_MAX_BYTES, function (c, m) { return new opts.ErrorClass(c, m); },
481
481
  opts.prefix + "/too-large", "parse input");
482
- return _isPemArmor(buf) ? pemDecode(buf, opts.pemLabel, opts.PemError) : buf;
482
+ if (!_isPemArmor(buf)) return buf;
483
+ /** @internal A DER header short enough for the short form can be entirely text bytes, so the
484
+ * probe alone cannot separate armor from a DER value carrying an armor line in its content: an
485
+ * APPLICATION 3 primitive is identifier 0x43 and any content length from 32 to 126 is a
486
+ * printable length octet. Bytes that do not decode as one complete DER value are armor, which is
487
+ * the resolution `pki convert` takes and keeps every PEM file a caller reads into a Buffer on the
488
+ * PEM path. The decode runs only where the probe already said armor, so DER input reaches its
489
+ * parser without it. */
490
+ if (!_isCompleteDer(buf)) return pemDecode(buf, opts.pemLabel, opts.PemError);
491
+ /** @internal A primitive tag makes any content valid, so bytes can satisfy both readings at once
492
+ * and no rule chooses between them: a caller handed the wrong one would be handed the other
493
+ * reading's bytes, silently. The argument is what is ambiguous, not the file, so the message
494
+ * names the two unambiguous ways to say which was meant. */
495
+ if (_isPemBlock(buf, opts)) {
496
+ throw new opts.ErrorClass(opts.prefix + "/bad-input",
497
+ "parse input is both one complete DER value and a well-formed PEM block, so which was meant " +
498
+ "cannot be read from the bytes: pass PEM as a string, or pass the DER value on its own");
499
+ }
500
+ return buf;
483
501
  }
484
502
  throw new opts.ErrorClass(opts.prefix + "/bad-input", "parse expects a DER BufferSource (Buffer, typed array, DataView, or ArrayBuffer) or a PEM string");
485
503
  }
486
504
 
505
+ /** @internal Whether a buffer also holds a well-formed PEM block, asked only to detect that both
506
+ * readings hold. The decoded bytes are discarded: the caller refuses rather than choosing one. */
507
+ function _isPemBlock(buf, opts) {
508
+ try { pemDecode(buf, opts.pemLabel, opts.PemError); return true; }
509
+ catch (_e) { return false; }
510
+ }
511
+
512
+ /** @internal Whether a buffer is exactly one complete DER value. Trailing bytes disqualify it, so a
513
+ * PEM file whose leading text happened to decode cannot be taken for DER on that prefix alone. */
514
+ function _isCompleteDer(buf) {
515
+ // allow:bare-decode classifies bytes AT the door, before a parse context exists to carry caps; the buffer is byte-capped above and the decode holds the codec's own caps.
516
+ try { asn1.decode(buf); return true; }
517
+ catch (_e) { return false; }
518
+ }
519
+
487
520
  /** @internal Whether a buffer is armored text rather than DER. Read from a fixed window at the
488
521
  * front, the answer is wrong for a file whose explanatory text is longer than the window, and the
489
522
  * caller then hands PEM to the DER decoder and reports the DER as malformed. So the whole buffer is
@@ -493,7 +526,11 @@ function _isPemArmor(buf) {
493
526
  var n = buf.length;
494
527
  for (var i = 0; i < n; i++) {
495
528
  var c = buf[i];
496
- var textByte = (c >= 0x20 && c < 0x7f) || c === 0x09 || c === 0x0a || c === 0x0d ||
529
+ /** @internal ASCII whitespace has six members and a text file carries all six, so the walk
530
+ * passes tab, line feed, vertical tab, form feed, carriage return and space, plus the printable
531
+ * range and the byte-order mark. Every other byte ends the walk: a boundary behind one means the
532
+ * buffer is not text, and DER is binary. A PEM file that does carry one is passed as a string. */
533
+ var textByte = (c >= 0x20 && c < 0x7f) || (c >= 0x09 && c <= 0x0d) ||
497
534
  c === 0xef || c === 0xbb || c === 0xbf;
498
535
  if (!textByte) return false;
499
536
  if (c === 0x2d && _bufToString(_subarray(buf, i, i + 10), "latin1") === "-----BEGIN") return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.8.28",
3
+ "version": "0.8.31",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:3eb9063d-93f7-4a44-bdff-52a992c9a1e7",
5
+ "serialNumber": "urn:uuid:ea5fc812-c57e-4508-9ef7-3dc7126381e6",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-28T21:19:37.849Z",
8
+ "timestamp": "2026-09-29T06:11:34.254Z",
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.28",
22
+ "bom-ref": "@blamejs/pki@0.8.31",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.8.28",
25
+ "version": "0.8.31",
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.28",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.8.31",
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.28",
57
+ "ref": "@blamejs/pki@0.8.31",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]