tr-fetch 0.9.0 → 0.9.1

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/README.md CHANGED
@@ -308,6 +308,9 @@ CRL retrieval:
308
308
  - Allows at most five redirects, 16 MiB of decoded response data and ten seconds
309
309
  per download including redirects and body reading. Caller cancellation also
310
310
  cancels CRL retrieval. At most 32 distribution URIs are tried per certificate.
311
+ - Parses at most 1,000,000 ASN.1 nodes per CRL, enough for several hundred
312
+ thousand revoked entries. This bounds the memory that a hostile CRL can use
313
+ (about 0.6 GB); larger CRLs are invalid.
311
314
  - Allows private-network HTTP(S) endpoints, including loopback, for private PKI.
312
315
  It does not perform filesystem or LDAP lookup.
313
316
  - Does not recursively check the CRL download server's CRLs or OCSP status.
@@ -388,7 +391,14 @@ checks. Only `http:` and `https:` URLs are supported; a URL without a scheme
388
391
  defaults to `http://`.
389
392
 
390
393
  ```sh
391
- npx tr-curl -v https://example.com/
394
+ npx -p tr-fetch tr-curl -v https://example.com/
395
+ ```
396
+
397
+ The command is in the `tr-fetch` package, so `npx` needs `-p tr-fetch`.
398
+ After `npm install -g tr-fetch`, or inside a project that depends on it,
399
+ `tr-curl` can be run directly:
400
+
401
+ ```sh
392
402
  tr-curl -fsSL -o page.html https://example.com/
393
403
  tr-curl --json '{"a":1}' -u user:password https://api.example.com/items
394
404
  tr-curl --cacert private-ca.pem --crlfile current.crl https://internal.example/
package/crl.js CHANGED
@@ -5,6 +5,10 @@ const pki = require('pkijs');
5
5
  const { cryptoEngine, parseDer, extensionsById, extensionValue, parseCertificate } = require('./pkiutils');
6
6
 
7
7
  const MAX_CRL_BYTES = 16 * 1024 * 1024;
8
+ // A revoked entry takes three to seven ASN.1 nodes, so this allows CRLs of
9
+ // several hundred thousand entries. Unlike the byte limit, it also bounds the
10
+ // memory used by hostile input made of minimal nodes (about 0.6 GB).
11
+ const MAX_CRL_NODES = 1000000;
8
12
 
9
13
  function distributionPoints(certificate) {
10
14
  const extension = extensionsById(certificate.extensions).get('2.5.29.31');
@@ -39,7 +43,7 @@ function parseCrl(bytes) {
39
43
  throw new Error('Malformed base64 in PEM CRL');
40
44
  }
41
45
  }
42
- return parseDer(bytes, pki.CertificateRevocationList);
46
+ return parseDer(bytes, pki.CertificateRevocationList, { maxNodes: MAX_CRL_NODES, maxContentLength: MAX_CRL_BYTES });
43
47
  }
44
48
 
45
49
  function checkValidity(crl, now = Date.now()) {
@@ -161,4 +165,4 @@ async function validateCrl(crl, certificate, issuer, urls, now = Date.now()) {
161
165
  return { revoked, nextUpdate };
162
166
  }
163
167
 
164
- module.exports = { MAX_CRL_BYTES, parseCertificate, distributionPoints, parseCrl, validateCrl };
168
+ module.exports = { MAX_CRL_BYTES, MAX_CRL_NODES, parseCertificate, distributionPoints, parseCrl, validateCrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-fetch",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Node.js fetch with CRL and OCSP certificate revocation checking, plus tr-curl, a curl-like test tool",
5
5
  "main": "index.js",
6
6
  "exports": {
package/pkiutils.js CHANGED
@@ -6,10 +6,14 @@ const { webcrypto } = require('node:crypto');
6
6
 
7
7
  const cryptoEngine = new pki.CryptoEngine({ name: 'tr-fetch', crypto: webcrypto });
8
8
 
9
- function parseDer(bytes, Type) {
10
- const decoded = asn1.fromBER(bytes);
11
- if ((decoded.offset !== bytes.length) || decoded.result.error) {
12
- throw new Error('Malformed ASN.1 data or trailing bytes');
9
+ // Limits default to asn1js's own; see its fromBER() resource limits.
10
+ function parseDer(bytes, Type, limits) {
11
+ const decoded = asn1.fromBER(bytes, limits);
12
+ if (decoded.result.error) {
13
+ throw new Error(`Malformed ASN.1 data: ${decoded.result.error}`);
14
+ }
15
+ if (decoded.offset !== bytes.length) {
16
+ throw new Error('Malformed ASN.1 data: trailing bytes');
13
17
  }
14
18
  return new Type({ schema: decoded.result });
15
19
  }