@blamejs/pki 0.8.61 → 0.9.0

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 CHANGED
@@ -4,6 +4,30 @@ 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.9.0 — 2026-10-08
8
+
9
+ Import any namespace by name from an ESM caller, and give every record the toolkit builds for an omitted argument no prototype.
10
+
11
+ ### Added
12
+
13
+ - Every namespace is an ESM named import. `import { x509, cms, path, schema, lint, webcrypto } from "@blamejs/pki"` resolves, as does any of the other 41; `import pki from "@blamejs/pki"` is unchanged and gives the same object `require` does. The package remains CommonJS, runs on Node LTS as shipped, and adds no build step and no transpilation: every value in the export object is a bare identifier bound above it, which is the shape Node's export reader can follow. A `.d.ts` generated from the source comment blocks is still to come.
14
+
15
+ ### Changed
16
+
17
+ - A record the toolkit defaults for an omitted argument no longer inherits from `Object.prototype`. A caller passing its own object is unaffected: only the record built when the argument is absent changed, and a field read off it that the caller did not supply now reads as absent.
18
+
19
+ ### Fixed
20
+
21
+ - A revocation deadline is measured against the toolkit's own clock. `pki.path.fetchingChecker` builds its deadline with no options record, so the record it defaulted carried `Object.prototype` and the clock came from an inherited `now`: one reporting a time far ahead made the deadline expired before the first fetch, and the fetch that would have retrieved a CRL or an OCSP response was never made. The same record supplies the bound a decoded size is held to, where an inherited `max` of zero refuses every value.
22
+ - `pki.inspect.asn1`, `pki.inspect.certificate` and the other report verbs are held to the caps their caller passed. With the options argument omitted the record they defaulted carried `Object.prototype`, so an inherited `maxBytes` became the cap the render was held to and a report that renders normally came back refused.
23
+ - A signer signs with the identity its caller named. `pki.x509.sign`, `pki.crl.sign` and `pki.attrcert.sign` default an omitted issuer or extension record, so an inherited `cert`, `key`, `name`, `publicKey`, `basicConstraints` or `keyUsage` was read as if supplied. Reaching the read required getting past the spec's unknown-field door and its copy depth cap, both of which refused it, so the effect was a refused signing call rather than a signature under another identity. The record has no prototype now, which is where the answer belongs.
24
+ - A client believes what a server actually sent. `pki.acme`, `pki.cmp`, `pki.ct`, `pki.est`, `pki.scep` and the revocation fetcher each default an omitted response record, where an inherited `status`, `body` or `headers` stands in for what arrived. The content type a CMP transfer and a CT fetch check, and the declared content length the HTTP transport enforces its response cap against, were each read through a header record defaulted the same way.
25
+ - The records every other verb defaults are the same shape and are converted with them: the options records of `pki.asn1.decode`, `pki.cbor.decode`, the schema engine and the shared PKIX sub-schemas, the signer and countersigner records in `pki.cms.sign`, the MAC and bag encryption records in `pki.pkcs12.build`, the message-imprint records in `pki.tsp.sign`, the header records in `pki.est`, the request and defaults records in the HTTP transport, the setup records in `pki.hpke`, the client option records in `pki.ct`, the certificate-transparency policy `pki.path.validate` passes on, the fallback key in `pki.jose`, the algorithm records the WebAuthn verifiers read a name off, and the algorithm record a signature scheme reads off a key.
26
+
27
+ ### Documentation
28
+
29
+ - `THREAT-MODEL.md` states the boundary the toolkit's use of captured operations rests on. The operations a check decides through are copied from the runtime while the modules load, which is what makes a later replacement unable to change a verdict, and that also means code running before the first `require` of the package can replace an operation before the copy is taken. Load the package before running untrusted code in the same realm.
30
+
7
31
  ## v0.8.61 — 2026-10-07
8
32
 
9
33
  Take every cryptographic operation, and every question about which key a key is, through an operation captured when the toolkit loads, so a replacement installed afterwards cannot decide a secret, a tag, a key type or a verdict.
package/README.md CHANGED
@@ -71,6 +71,13 @@ no transpilation.
71
71
  var pki = require("@blamejs/pki");
72
72
  ```
73
73
 
74
+ An ESM caller can import the whole namespace object or any namespace by name:
75
+
76
+ ```js
77
+ import pki from "@blamejs/pki";
78
+ import { x509, cms, path, schema } from "@blamejs/pki";
79
+ ```
80
+
74
81
  ## Quickstart
75
82
 
76
83
  ### Parse an X.509 certificate
package/index.js CHANGED
@@ -73,8 +73,53 @@ var inspect = require("./lib/inspect");
73
73
  var lint = require("./lib/lint");
74
74
  var webauthn = require("./lib/webauthn");
75
75
 
76
+ /* Every value in the export object below is a bare identifier, and the ten `var`s here are what make
77
+ * that true. Node detects a CommonJS module's named exports with `cjs-module-lexer`, which follows
78
+ * `name: ident` and a shorthand and stops at anything else: a member expression, a nested object
79
+ * literal, a call. `version: constants.version` was the first entry, so it stopped the lexer before
80
+ * any namespace was seen and `import { x509 } from "@blamejs/pki"` failed for all 47 of them, with
81
+ * only `default`, `module.exports` and `version` reaching an ESM caller. Hoisting is the whole fix;
82
+ * it needs no build step and changes nothing a `require` caller sees. A new namespace added below
83
+ * must be a bare identifier, which a vector in `esm-named-exports.test.js` holds it to. */
84
+ var _version = constants.version;
85
+ var _identityNs = { match: identity.match };
86
+ var _cmsNs = {
87
+ verify: cms.verify, sign: cms.sign, countersign: cms.countersign, encrypt: cms.encrypt,
88
+ authenticate: cms.authenticate, decrypt: cms.decrypt, compress: cms.compress, decompress: cms.decompress,
89
+ digest: cms.digest, verifyDigest: cms.verifyDigest,
90
+ certsOnly: cms.certsOnly, parseCertsOnly: cms.parseCertsOnly, isCertsOnly: cms.isCertsOnly,
91
+ timestampImprint: cms.timestampImprint, attachTimestamp: cms.attachTimestamp,
92
+ };
93
+ var _cmpNs = {
94
+ build: cmp.build, transfer: cmp.transfer, wellKnownUrl: cmp.wellKnownUrl, verify: cmp.verify,
95
+ openKeyPackage: cmp.openKeyPackage, session: cmp.session,
96
+ };
97
+ var _keyNs = {
98
+ encrypt: key.encrypt, decrypt: key.decrypt, export: key.export, import: key.import,
99
+ generate: key.generate, publicFromPrivate: key.publicFromPrivate,
100
+ };
101
+ var _kemNs = { encapsulate: compositeKem.encapsulate, decapsulate: compositeKem.decapsulate };
102
+ var _scepNs = {
103
+ build: scep.build, parse: scep.parse, getCACaps: scep.getCACaps, getCACert: scep.getCACert,
104
+ getNextCACert: scep.getNextCACert, enroll: scep.enroll, renew: scep.renew, getCert: scep.getCert,
105
+ getCrl: scep.getCrl, parseCapabilities: scep.parseCapabilities,
106
+ };
107
+ var _transportNs = { https: transport.https, peerChain: transport.peerChain };
108
+ var _lintNs = {
109
+ certificate: lint.certificate,
110
+ csr: lint.csr,
111
+ crl: lint.crl,
112
+ ocsp: lint.ocsp,
113
+ cms: lint.cms,
114
+ tsp: lint.tsp,
115
+ attrcert: lint.attrcert,
116
+ rules: lint.rules,
117
+ profiles: lint.profiles,
118
+ };
119
+ var _webcryptoNs = _webcryptoNamespace();
120
+
76
121
  module.exports = {
77
- version: constants.version,
122
+ version: _version,
78
123
  // `C` is the terse call-site alias; `constants` the discoverable name.
79
124
  C: constants,
80
125
  constants: constants,
@@ -97,7 +142,7 @@ module.exports = {
97
142
  // `identity` is RFC 9525 service identity -- pki.identity.match says whether a certificate
98
143
  // presents a name the client was trying to reach. A separate answer from path validation,
99
144
  // which pki.path.validate gives; sec. 1.2 has an application need both.
100
- identity: { match: identity.match },
145
+ identity: _identityNs,
101
146
  // `ct` is RFC 6962 Certificate Transparency -- pki.ct.parseSctList decodes the
102
147
  // SCT-list extension a certificate / OCSP response carries; the signature is
103
148
  // surfaced raw for external verification (pki.ct.reconstructSignedData).
@@ -113,11 +158,7 @@ module.exports = {
113
158
  // Curated, the way pki.cmp is: cms-verify also exports `setEngine`, the seam path-validate injects
114
159
  // its path builder through. That is plumbing between two internal modules, not an operator verb,
115
160
  // and exporting the module wholesale would put it on the public surface.
116
- cms: { verify: cms.verify, sign: cms.sign, countersign: cms.countersign, encrypt: cms.encrypt,
117
- authenticate: cms.authenticate, decrypt: cms.decrypt, compress: cms.compress, decompress: cms.decompress,
118
- digest: cms.digest, verifyDigest: cms.verifyDigest,
119
- certsOnly: cms.certsOnly, parseCertsOnly: cms.parseCertsOnly, isCertsOnly: cms.isCertsOnly,
120
- timestampImprint: cms.timestampImprint, attachTimestamp: cms.attachTimestamp },
161
+ cms: _cmsNs,
121
162
  smime: smime,
122
163
  // `cmc` interprets an RFC 5272 Full PKI Response into one terminal verdict;
123
164
  // `pki.schema.cmc` is the decoder underneath it.
@@ -147,8 +188,7 @@ module.exports = {
147
188
  // and pki.cmp.verify checks the protection on an incoming one. pki.cmp.openKeyPackage opens a
148
189
  // centrally generated private key a CA delivered. Parsing lives at pki.schema.cmp.parse.
149
190
  // setEngine is the @internal path-validate seam -- kept off the public surface.
150
- cmp: { build: cmp.build, transfer: cmp.transfer, wellKnownUrl: cmp.wellKnownUrl, verify: cmp.verify,
151
- openKeyPackage: cmp.openKeyPackage, session: cmp.session },
191
+ cmp: _cmpNs,
152
192
  // `crl` is the RFC 5280 sec. 5 CRL producing side -- pki.crl.sign builds and signs a CertificateList
153
193
  // over any registry algorithm, pki.crl.verify checks a CRL signature through the one path-validation
154
194
  // signature engine, and pki.crl.isRevoked looks a serial up. Parsing lives at pki.schema.crl.parse.
@@ -158,8 +198,7 @@ module.exports = {
158
198
  // pki.key.generate / publicFromPrivate over every WebCrypto algorithm. Parsing lives at pki.schema.pkcs8.
159
199
  // Curated: correspondsTo is the @internal check pki.cmp.session holds a delivered key and its
160
200
  // certificate to each other with, and stays off the public surface.
161
- key: { encrypt: key.encrypt, decrypt: key.decrypt, export: key.export, import: key.import,
162
- generate: key.generate, publicFromPrivate: key.publicFromPrivate },
201
+ key: _keyNs,
163
202
  // `pkcs12` is the RFC 7292 / RFC 9579 PKCS#12 (.p12/.pfx) producing side -- pki.pkcs12.build assembles a
164
203
  // password-integrity store (key/cert/crl/secret bags in an AuthenticatedSafe, shrouded keys + cert safes
165
204
  // under PBES2, a classic HMAC or PBMAC1 MAC), and pki.pkcs12.verifyMac checks a store's MAC. Parsing lives
@@ -193,7 +232,7 @@ module.exports = {
193
232
  // `kem` is composite ML-KEM key establishment (draft-ietf-lamps-pq-composite-kem):
194
233
  // pki.kem.encapsulate / decapsulate over a post-quantum ML-KEM hybridized with a
195
234
  // traditional RSA-OAEP / ECDH / X25519 / X448, mixed through the SHA3-256 combiner.
196
- kem: { encapsulate: compositeKem.encapsulate, decapsulate: compositeKem.decapsulate },
235
+ kem: _kemNs,
197
236
  // `sigstore` verifies a Sigstore bundle (the npm --provenance artifact): a
198
237
  // keyless Fulcio signature over a DSSE-wrapped in-toto SLSA attestation with a
199
238
  // Rekor inclusion proof -- offline, zero-dep, against caller-pinned trust.
@@ -204,14 +243,14 @@ module.exports = {
204
243
  // splitter, certs-only + serverkeygen validators over CMS, the enroll-attribute
205
244
  // builders, the HTTP response classifier). est opens no socket; fail-closed.
206
245
  est: est,
207
- scep: { build: scep.build, parse: scep.parse, getCACaps: scep.getCACaps, getCACert: scep.getCACert, getNextCACert: scep.getNextCACert, enroll: scep.enroll, renew: scep.renew, getCert: scep.getCert, getCrl: scep.getCrl, parseCapabilities: scep.parseCapabilities },
246
+ scep: _scepNs,
208
247
  // `transport` is the shared fail-closed node:https transport the enrollment clients
209
248
  // drive -- pki.transport.https(defaults) returns a transport(request) -> {status,
210
249
  // headers, body}. The toolkit's sole socket choke point: explicit trust anchors,
211
250
  // rejectUnauthorized always on, a TLS floor, a streaming response cap, and a timeout.
212
251
  // Curated to the public `https` factory; the module's `isBlockedIp` classifier is an
213
252
  // internal helper pki.path.build reuses (require the module), not a public surface.
214
- transport: { https: transport.https, peerChain: transport.peerChain },
253
+ transport: _transportNs,
215
254
  // `jose` is the RFC 7515 Flattened JWS + RFC 7638 JWK-thumbprint layer: a strict
216
255
  // base64url codec, a bounded duplicate-key-rejecting JSON reader, profiled
217
256
  // sign/verify (ACME-outer / EAB-inner / keyChange-inner), and an alg registry
@@ -241,17 +280,7 @@ module.exports = {
241
280
  // `lint` is named member by member rather than passed through, because the module also exports the
242
281
  // build-time gate the authoring verbs call and the two readers its conformance vectors use. Those
243
282
  // are internal plumbing, so they stay off the public namespace.
244
- lint: {
245
- certificate: lint.certificate,
246
- csr: lint.csr,
247
- crl: lint.crl,
248
- ocsp: lint.ocsp,
249
- cms: lint.cms,
250
- tsp: lint.tsp,
251
- attrcert: lint.attrcert,
252
- rules: lint.rules,
253
- profiles: lint.profiles,
254
- },
283
+ lint: _lintNs,
255
284
  // `webauthn` verifies a W3C WebAuthn / passkey attestation -- pki.webauthn.verify
256
285
  // checks the attestation-statement signature + each format's structural bindings
257
286
  // (packed / tpm / android-key / apple / fido-u2f / none) and surfaces the x5c chain
@@ -263,7 +292,7 @@ module.exports = {
263
292
  // A ready W3C Crypto instance (globalThis.crypto shape) with the classes for
264
293
  // constructing more attached under the same namespace (pki.webcrypto.CryptoKey,
265
294
  // .SubtleCrypto, .Crypto, .WebCryptoError). PQC-first, classical-capable, zero-dep.
266
- webcrypto: _webcryptoNamespace(),
295
+ webcrypto: _webcryptoNs,
267
296
  };
268
297
 
269
298
  function _webcryptoNamespace() {
package/lib/acme.js CHANGED
@@ -1796,7 +1796,7 @@ function _parseLinkValue(raw) {
1796
1796
  return { uri: uri, rel: rel, anchor: anchor, relSeen: relSeen };
1797
1797
  }
1798
1798
  function _parseLinkRelation(headers, base, relName, opts) {
1799
- opts = opts || {};
1799
+ opts = opts || intrinsic.create(null);
1800
1800
  var raw = null;
1801
1801
  var hNames = guard.identifier.optionNames(headers);
1802
1802
  for (var hi = 0; hi < hNames.length; hi++) {
@@ -2047,11 +2047,11 @@ function client(directoryUrl, opts) {
2047
2047
 
2048
2048
  function _send(method, url, headers, body) { return _sendFollowing(method, url, headers, body, 0); }
2049
2049
  function _sendFollowing(method, url, headers, body, redirects) {
2050
- var reqHeaders = Object.assign({ "user-agent": CLIENT_USER_AGENT }, headers || {});
2050
+ var reqHeaders = Object.assign({ "user-agent": CLIENT_USER_AGENT }, headers || intrinsic.create(null));
2051
2051
  return guard.async.deferred(function () {
2052
2052
  return guard.async.invoked(transport, [{ method: method, url: url, headers: reqHeaders, body: body, tls: _tlsFor(url), proxy: budgets.proxy, timeout: budgets.timeout, maxResponseBytes: budgets.maxResponseBytes }], E, "acme/bad-input", "opts.transport");
2053
2053
  }).then(function (res) {
2054
- res = res || {};
2054
+ res = res || intrinsic.create(null);
2055
2055
  /** @internal The transport is a caller-supplied option, so its response is a caller object: the body
2056
2056
  * and the status are read ONCE here and every check and the returned value read those locals. Read
2057
2057
  * per use, the body whose length was capped need not be the body handed back, which is how a
@@ -2145,7 +2145,7 @@ function client(directoryUrl, opts) {
2145
2145
 
2146
2146
  function _newAccount(payloadOpts) {
2147
2147
  return _resource("newAccount").then(function (url) {
2148
- return _post(url, newAccount, payloadOpts || {}, "jwk", undefined, [200, 201]).then(function (res) {
2148
+ return _post(url, newAccount, payloadOpts || intrinsic.create(null), "jwk", undefined, [200, 201]).then(function (res) {
2149
2149
  var loc = res.headers["location"];
2150
2150
  if (!_isString(loc)) throw E("acme/no-account-url", "newAccount did not return an account URL in a Location header (RFC 8555 sec. 7.3)");
2151
2151
  var account = validate("account", _json(res));
@@ -2156,7 +2156,7 @@ function client(directoryUrl, opts) {
2156
2156
  }
2157
2157
  function _newOrder(payloadOpts) {
2158
2158
  return _resource("newOrder").then(function (url) {
2159
- return _post(url, newOrder, payloadOpts || {}, "kid", undefined, [201]).then(function (res) {
2159
+ return _post(url, newOrder, payloadOpts || intrinsic.create(null), "kid", undefined, [201]).then(function (res) {
2160
2160
  var loc = res.headers["location"];
2161
2161
  if (!_isString(loc)) throw E("acme/no-order-url", "newOrder did not return an order URL in a Location header (RFC 8555 sec. 7.4)");
2162
2162
  return { order: validate("order", _json(res)), url: _resolveLocation(loc, url) };
package/lib/asn1-der.js CHANGED
@@ -210,7 +210,7 @@ function _asBuffer(input, who) {
210
210
  * node.tagNumber === pki.asn1.TAGS.SEQUENCE;
211
211
  */
212
212
  function decode(input, opts) {
213
- opts = opts || {};
213
+ opts = opts || intrinsic.create(null);
214
214
  var buf = _asBuffer(input, "decode");
215
215
  var maxBytes = guard.limits.cap(opts.maxBytes, "maxBytes", constants.LIMITS.DER_MAX_BYTES);
216
216
  var maxDepth = guard.limits.depthCap(opts.maxDepth, "maxDepth", constants.LIMITS.DER_MAX_DEPTH);
@@ -448,7 +448,7 @@ function _emitNamedExtension(out, seen, k, val, ctx) {
448
448
  _push(out,_b.ext(eOid, meta.critical, valueDer));
449
449
  }
450
450
  function _buildExtensions(extSpec, ctx) {
451
- if (extSpec == null) extSpec = {};
451
+ if (extSpec == null) extSpec = intrinsic.create(null);
452
452
  if (Array.isArray(extSpec)) {
453
453
  if (!extSpec.length) return null;
454
454
  var seenA = intrinsic.create(null);
@@ -567,7 +567,7 @@ function _sign(spec, issuer, opts) {
567
567
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "attrcert/bad-input", "unknown pki.attrcert.sign option (accepted: pem, pss, digestAlgorithm): ");
568
568
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("attrcert/bad-input", "the attribute-certificate spec must be an object");
569
569
  guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "attrcert/bad-input", "unknown spec field ");
570
- issuer = issuer || {};
570
+ issuer = issuer || intrinsic.create(null);
571
571
  if (issuer.key == null) throw _err("attrcert/bad-input", "a signing key (issuer.key, the AA's WebCrypto CryptoKey or PKCS#8 private key DER/PEM) is required");
572
572
 
573
573
  var issuerDnSpec, aaSpki, aaSki = null;
package/lib/cbor-det.js CHANGED
@@ -36,6 +36,9 @@
36
36
  * leaf readers over its node tree.
37
37
  */
38
38
 
39
+ /** @internal The record constructor, captured at load, for the reason the same capture in
40
+ * `lib/inspect.js` gives: arming this module counts 66 live runtime reads. */
41
+ var _create = Object.create;
39
42
  var constants = require("./constants");
40
43
  var frameworkError = require("./framework-error");
41
44
  var asn1 = require("./asn1-der");
@@ -241,7 +244,7 @@ function _decodeItem(buf, start, limit, depth, maxD, rules, state) {
241
244
  * pki.cbor.read.uint(node.children[0]); // 1n
242
245
  */
243
246
  function decode(input, opts) {
244
- opts = opts || {};
247
+ opts = opts || _create(null);
245
248
  var buf = _asBuffer(input, "decode");
246
249
  var maxBytes = guard.limits.cap(opts.maxBytes, "maxBytes", constants.LIMITS.CBOR_MAX_BYTES);
247
250
  var maxDepth = guard.limits.depthCap(opts.maxDepth, "maxDepth", constants.LIMITS.CBOR_MAX_DEPTH);
package/lib/cmc-build.js CHANGED
@@ -712,7 +712,7 @@ function build(spec, signer, opts) {
712
712
  }
713
713
 
714
714
  async function _build(spec, signer, opts) {
715
- opts = opts || {};
715
+ opts = opts || intrinsic.create(null);
716
716
  if (!spec || typeof spec !== "object" || Array.isArray(spec) || Buffer.isBuffer(spec)) {
717
717
  throw E("cmc/bad-input", "the CMC request spec must be an object");
718
718
  }
package/lib/cmp-build.js CHANGED
@@ -856,7 +856,7 @@ function build(message, opts) {
856
856
  }
857
857
 
858
858
  async function _build(message, opts) {
859
- opts = opts || {};
859
+ opts = opts || intrinsic.create(null);
860
860
  if (!message || typeof message !== "object" || Buffer.isBuffer(message)) throw _err("cmp/bad-input", "the PKIMessage spec must be an object { header, body }");
861
861
  guard.identifier.assertKnownKeys(message, KNOWN_MESSAGE_KEYS, _err, "cmp/bad-input", function (k) {
862
862
  return "unknown message field " + JSON.stringify(k) + " (a message carries only header + body)";
@@ -1020,7 +1020,7 @@ function _tlsForTransfer(opts) {
1020
1020
  * `Symbol.split` is part of that operation. The token decides which parser a response body is
1021
1021
  * handed to. */
1022
1022
  function _ctypeToken(headers) {
1023
- var raw = intrinsic.String((headers || {})["content-type"] || "");
1023
+ var raw = intrinsic.String((headers || intrinsic.create(null))["content-type"] || "");
1024
1024
  var parts = intrinsic.splitChar(raw, 59);
1025
1025
  return intrinsic.toLowerCase(_strTrim(parts.length ? parts[0] : ""));
1026
1026
  }
@@ -1067,7 +1067,7 @@ function _assertTransport(opts) {
1067
1067
  }
1068
1068
 
1069
1069
  function _transfer(url, message, opts) {
1070
- opts = opts || {};
1070
+ opts = opts || intrinsic.create(null);
1071
1071
  guard.identifier.assertKnownKeys(opts, KNOWN_TRANSFER_OPTS, _err, "cmp/bad-input", "unknown opts field ");
1072
1072
  /** @internal Read once, at the door, and carried from here. Asking again would let an option that
1073
1073
  * answers differently on each read hand back something other than the value that was checked. */
@@ -1095,7 +1095,7 @@ function _transfer(url, message, opts) {
1095
1095
  headers["content-type"] = PKIXCMP;
1096
1096
  var tls = _tlsForTransfer(opts);
1097
1097
  return guard.async.invoked(transport, [{ method: "POST", url: parsedUrl.href, headers: headers, body: der, tls: tls, proxy: proxy, timeout: timeout, maxResponseBytes: maxResponseBytes }], _err, "cmp/bad-input", "opts.transport").then(function (res) {
1098
- res = res || {};
1098
+ res = res || intrinsic.create(null);
1099
1099
  var h = guard.header.lowerCased(res.headers);
1100
1100
  var body = guard.bytes.isByteSource(res.body)
1101
1101
  ? guard.bytes.source(res.body, CmpError, "cmp/bad-response", "the CMP response body")
@@ -1136,7 +1136,7 @@ function _beforeQueryOrFragment(s) {
1136
1136
  }
1137
1137
 
1138
1138
  function wellKnownUrl(base, opts) {
1139
- opts = opts || {};
1139
+ opts = opts || intrinsic.create(null);
1140
1140
  guard.identifier.assertKnownKeys(opts, KNOWN_WELLKNOWN_OPTS, _err, "cmp/bad-input", function (k) {
1141
1141
  return "unknown wellKnownUrl option " + JSON.stringify(k) + " (expected label / operation)";
1142
1142
  });
@@ -4,6 +4,9 @@
4
4
  // @internal
5
5
  // lib/cmp-build.js; this file adds the @primitive pki.cmp.session block and re-exports the cmp message
6
6
 
7
+ /** @internal The record constructor, captured at load, for the reason the same capture in
8
+ * `lib/inspect.js` gives: arming this module counts 174 live runtime reads. */
9
+ var _create = Object.create;
7
10
  var cmp = require("./cmp-verify");
8
11
  var asn1 = require("./asn1-der");
9
12
  var oid = require("./oid");
@@ -430,7 +433,7 @@ function _certConfHash(certDer) {
430
433
  * if (answer.outcome === "answered" && answer.present) { var caCerts = answer.value; }
431
434
  */
432
435
  function session(opts) {
433
- if (opts == null) opts = {};
436
+ if (opts == null) opts = _create(null);
434
437
  guard.identifier.assertPlainRecord(opts, _err, "cmp/bad-input", "opts");
435
438
  guard.identifier.optionsObject(opts, _err, "cmp/bad-input", "opts");
436
439
  guard.identifier.assertKnownKeys(opts, KNOWN_SESSION_OPTS, _err, "cmp/bad-input", "unknown session opts field ");
@@ -668,7 +671,7 @@ function session(opts) {
668
671
  }
669
672
 
670
673
  function _classify(verdict) {
671
- var body = verdict.body || {};
674
+ var body = verdict.body || _create(null);
672
675
  var arm = body.arm;
673
676
  if (arm === expectedRespArm && txnKind === "revoke") return _classifyRevRep(body);
674
677
  if (arm === expectedRespArm && txnKind === "info") return _classifyGenRep(body);
@@ -734,7 +737,7 @@ function session(opts) {
734
737
  }
735
738
 
736
739
  function _classifyRevRep(body) {
737
- var d = body.decoded || {};
740
+ var d = body.decoded || _create(null);
738
741
  var list = d.status || [];
739
742
  if (list.length !== 1) {
740
743
  return { state: "unexpected", reason: "an rp answering a revocation must carry exactly one status (RFC 9483 sec. 4.2); got " + list.length };
package/lib/cmp-verify.js CHANGED
@@ -811,7 +811,7 @@ function _fixTime(v) {
811
811
  return new _Date(guard.time.instantOf(v));
812
812
  }
813
813
  function _fixVerifyOptions(opts, made) {
814
- if (opts == null) opts = {};
814
+ if (opts == null) opts = _create(null);
815
815
  opts = guard.identifier.optionsObject(opts, _err, "cmp/bad-input", "pki.cmp.verify options");
816
816
  guard.identifier.assertKnownKeys(opts, KNOWN_VERIFY_OPTS, _err, "cmp/bad-input", "unknown opts field ");
817
817
  var f = {
@@ -4,6 +4,9 @@
4
4
  // @internal
5
5
  // @module pki.cms + the @primitive blocks live in cms-verify.js, which re-exports these (the
6
6
 
7
+ /** @internal The record constructor, captured at load, for the reason the same capture in
8
+ * `lib/inspect.js` gives: arming this module counts 5 live runtime reads. */
9
+ var _create = Object.create;
7
10
  var zlib = require("zlib");
8
11
  var oid = require("./oid");
9
12
  var schemaCms = require("./schema-cms");
@@ -21,7 +24,7 @@ var OID_ZLIB = O("id-alg-zlibCompress");
21
24
  var NULL_PARAMS_DER = Buffer.from([0x05, 0x00]);
22
25
 
23
26
  async function compress(content, opts) {
24
- opts = opts || {};
27
+ opts = opts || _create(null);
25
28
  var raw = guard.bytes.source(content, CmsError, "cms/bad-input", "content");
26
29
  var level = opts.level;
27
30
  if (level !== undefined && (typeof level !== "number" || !isFinite(level) || Math.floor(level) !== level)) throw _err("cms/bad-input", "opts.level must be an integer");
@@ -41,7 +44,7 @@ async function compress(content, opts) {
41
44
  }
42
45
 
43
46
  async function decompress(input, opts) {
44
- opts = opts || {};
47
+ opts = opts || _create(null);
45
48
  var cap = C.LIMITS.COMPRESS_MAX_BYTES;
46
49
  if (opts.maxOutputBytes !== undefined) {
47
50
  var mo = opts.maxOutputBytes;
@@ -34,7 +34,7 @@ var CONTENT_KEYBITS = pbes2.CONTENT_KEYBITS;
34
34
  var CONTENT_MODE = pbes2.CONTENT_MODE;
35
35
 
36
36
  async function decrypt(input, keyMaterial, opts) {
37
- opts = opts || {};
37
+ opts = opts || intrinsic.create(null);
38
38
  if (keyMaterial == null || typeof keyMaterial !== "object") throw _err("cms/bad-input", "decrypt requires a key-material object");
39
39
  /** @internal Read on every route, not only the one that applies it, and read before the message
40
40
  * is derived: deriving one runs accessors on a parsed input, which is the caller's own code and
@@ -66,7 +66,7 @@ function _originFields(res, authenticatedBy, originatorInfo) {
66
66
  }
67
67
 
68
68
  async function decryptEnvelopedData(parsed, keyMaterial, opts, contentTypeName) {
69
- opts = opts || {};
69
+ opts = opts || intrinsic.create(null);
70
70
  if (keyMaterial == null || typeof keyMaterial !== "object") throw _err("cms/bad-input", "decrypt requires a key-material object");
71
71
  var ct = contentTypeName || "envelopedData";
72
72
  var recips = parsed.recipientInfos || [];
@@ -426,7 +426,7 @@ function encrypt(content, recipients, opts) {
426
426
  }
427
427
 
428
428
  async function _encryptImpl(content, recipients, opts) {
429
- opts = opts || {};
429
+ opts = opts || intrinsic.create(null);
430
430
  var algName = opts.contentEncryptionAlgorithm || "aes-256-gcm";
431
431
  var ca = CONTENT_ALGS[guard.text.keyOf(algName)];
432
432
  if (!ca) throw _err("cms/bad-input", "unsupported contentEncryptionAlgorithm " + guard.text.showValue(algName));
@@ -648,7 +648,7 @@ function authenticate(content, recipients, opts) {
648
648
  }
649
649
 
650
650
  async function _authenticateImpl(content, recipients, opts) {
651
- opts = opts || {};
651
+ opts = opts || intrinsic.create(null);
652
652
  var withAttrs = opts.authenticatedAttributes !== false;
653
653
  guard.identifier.assertKnownKeys(opts, withAttrs ? _AUTHENTICATE_OPTS_ATTRS : _AUTHENTICATE_OPTS_BARE,
654
654
  _err, "cms/bad-input", function (k) {
package/lib/cms-sign.js CHANGED
@@ -203,7 +203,7 @@ function _assertAlgorithmProtectionPairs(pairs, digestAlgId, armAlgId, armTag) {
203
203
  }
204
204
 
205
205
  function _resolveSignerContext(signer, opts) {
206
- var so = signer || {};
206
+ var so = signer || intrinsic.create(null);
207
207
  var keyOnly = so.cert == null && so.spki != null;
208
208
  var soKey = so.key;
209
209
  var soSpki = keyOnly ? guard.bytes.snapshotSource(so.spki, CmsError, "cms/bad-input", "a key-only signer's spki") : null;
@@ -533,7 +533,7 @@ function _resolveSignerIndices(spec, n) {
533
533
  }
534
534
 
535
535
  function _buildCountersignature(targetSigOctets, countersigner, opts) {
536
- var so = countersigner || {};
536
+ var so = countersigner || intrinsic.create(null);
537
537
  var certDer = _normCertDer(so.cert);
538
538
  var cert = x509.parse(certDer);
539
539
  var scheme = signScheme.resolveSignScheme(cert, so, opts.signedAttributes === false, _signE);
package/lib/crl-sign.js CHANGED
@@ -240,7 +240,7 @@ function _buildCrlExtensions(spec, ctx) {
240
240
  var crlNumberVal = null;
241
241
  if (spec.crlNumber != null) { var cn = _boundedInteger(spec.crlNumber, "cRLNumber"); crlNumberVal = cn.value; push("cRLNumber", false, cn.tlv); }
242
242
  var ext = spec.extensions;
243
- if (ext == null) ext = {};
243
+ if (ext == null) ext = intrinsic.create(null);
244
244
  if (Array.isArray(ext)) {
245
245
  var arrBase = null, arrCrlNum = null;
246
246
  /** @internal The walk goes through `guard.list.copyMap`, never the caller's own `forEach`. Reached
@@ -391,9 +391,9 @@ function _assertIssuerCanSignCrl(issuerCert) {
391
391
  }
392
392
 
393
393
  function _sign(spec, issuer, opts) {
394
- opts = opts || {};
394
+ opts = opts || intrinsic.create(null);
395
395
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("crl/bad-input", "the CRL spec must be an object");
396
- issuer = issuer || {};
396
+ issuer = issuer || intrinsic.create(null);
397
397
  var byCert = issuer.cert != null, byName = issuer.name != null;
398
398
  guard.identifier.assertKnownKeys(spec, byCert || byName ? KNOWN_SPEC_KEYS_ISSUER_NAMED : KNOWN_SPEC_KEYS,
399
399
  _err, "crl/bad-input", function (k) {
package/lib/crmf-sign.js CHANGED
@@ -1215,7 +1215,7 @@ function _buildCertReqMsg(spec, key, opts) {
1215
1215
  }
1216
1216
 
1217
1217
  function _build(spec, key, opts) {
1218
- opts = opts || {};
1218
+ opts = opts || intrinsic.create(null);
1219
1219
  if (!spec || typeof spec !== "object" || _isBuffer(spec)) throw _err("crmf/bad-input", "the certificate-request-message spec must be an object");
1220
1220
  var specs;
1221
1221
  if (spec.messages != null) {
package/lib/csr-sign.js CHANGED
@@ -209,7 +209,7 @@ function sign(spec, key, opts) {
209
209
  }
210
210
 
211
211
  function _sign(spec, key, opts) {
212
- opts = opts || {};
212
+ opts = opts || intrinsic.create(null);
213
213
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("csr/bad-input", "the certification-request spec must be an object");
214
214
  guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "csr/bad-input", "unknown spec field ");
215
215
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "csr/bad-input", "pki.csr.sign has an unknown option ");
package/lib/ct.js CHANGED
@@ -40,6 +40,7 @@
40
40
  */
41
41
 
42
42
  var asn1 = require("./asn1-der.js");
43
+ var _create = require("./guard-intrinsic").create;
43
44
  var constants = require("./constants.js");
44
45
  var frameworkError = require("./framework-error.js");
45
46
  var guard = require("./guard-all.js");
@@ -357,7 +358,7 @@ function _u24Bytes(n) {
357
358
  var _X509_ENTRY_KEYS = intrinsic.assign(intrinsic.create(null), { entryType: 1, leafCert: 1 });
358
359
  var _PRECERT_ENTRY_KEYS = intrinsic.assign(intrinsic.create(null), { entryType: 1, tbsCertificate: 1, issuerKeyHash: 1 });
359
360
  function reconstructSignedData(entry, sct) {
360
- entry = entry || {};
361
+ entry = entry || _create(null);
361
362
  if (typeof entry !== "object") throw new CtError("ct/bad-input", "the log entry must be an object { entryType, ... } (RFC 6962 sec. 3.1)");
362
363
  var entryType = entry.entryType;
363
364
  if (entryType !== 0 && entryType !== 1) {
@@ -493,7 +494,7 @@ async function verifySct(entry, sct, logPublicKey) {
493
494
  throw new CtError("ct/log-id-mismatch", "the SCT logId does not match SHA-256 of the provided log key (RFC 6962 sec. 3.2)");
494
495
  }
495
496
  }
496
- var sigInfo = rec.signatureAlgorithm || {};
497
+ var sigInfo = rec.signatureAlgorithm || _create(null);
497
498
  var hashName = CT_HASH[sigInfo.hashName];
498
499
  if (!hashName) throw new CtError("ct/unsupported-algorithm", "unsupported SCT hash algorithm " + JSON.stringify(sigInfo.hashName) + " (RFC 6962 sec. 2.1.4 mandates sha256)");
499
500
  var alg = _spkiAlg(spki);
@@ -899,7 +900,7 @@ function _classifyLog(sct, logList, entry, opts) {
899
900
  }
900
901
 
901
902
  async function verifySctWithLogList(entry, sct, logList, opts) {
902
- opts = opts || {};
903
+ opts = opts || _create(null);
903
904
  var c = _classifyLog(sct, logList, entry, opts);
904
905
  if (c.status !== "ok") throw _ctErr(c.code, c.message);
905
906
  /** @internal Read before the verify, so the timestamp the verdict states is the one the signature covered.
@@ -1249,7 +1250,7 @@ function _assertTransport(opts) {
1249
1250
  * `Symbol.split` is part of that operation. The token decides which parser a log's response body is
1250
1251
  * handed to. */
1251
1252
  function _fetchCtypeToken(headers) {
1252
- var raw = intrinsic.String((headers || {})["content-type"] || "");
1253
+ var raw = intrinsic.String((headers || _create(null))["content-type"] || "");
1253
1254
  var parts = intrinsic.splitChar(raw, 59);
1254
1255
  return _toLowerCase(_ctTrim(parts.length ? parts[0] : ""));
1255
1256
  }
@@ -1279,7 +1280,7 @@ function _fetchBody(transport, url, req, label) {
1279
1280
  if (req.body !== undefined) request.body = req.body;
1280
1281
  return transport(request);
1281
1282
  }).then(function (res) {
1282
- res = res || {};
1283
+ res = res || _create(null);
1283
1284
  var h = intrinsic.create(null);
1284
1285
  guard.identifier.optionNames(res.headers).forEach(function (k) { h[k.toLowerCase()] = res.headers[k]; });
1285
1286
  var body = guard.bytes.isByteSource(res.body)
@@ -1581,7 +1582,7 @@ function _uintField(obj, name, code, label) {
1581
1582
  var _STH_KEYS = intrinsic.assign(intrinsic.create(null),
1582
1583
  { timestamp: 1, treeSize: 1, rootHash: 1, signature: 1, raw: 1, then: 1 });
1583
1584
  function sthSignedData(sth) {
1584
- sth = sth || {};
1585
+ sth = sth || _create(null);
1585
1586
  guard.identifier.assertKnownKeys(sth, _STH_KEYS, _ctErr, "ct/bad-input", "unknown sth field ");
1586
1587
  var ts = guard.range.uint64(sth.timestamp, _ctErr, "ct/bad-input", "sth.timestamp");
1587
1588
  var size = guard.range.uint64(sth.treeSize, _ctErr, "ct/bad-input", "sth.treeSize");
@@ -1627,7 +1628,7 @@ function sthSignedData(sth) {
1627
1628
  * // -> true
1628
1629
  */
1629
1630
  async function verifySth(sth, logKey) {
1630
- sth = sth || {};
1631
+ sth = sth || _create(null);
1631
1632
  var signature = _toBuffer(sth.signature, "sth.signature");
1632
1633
  var signedData = sthSignedData({ timestamp: sth.timestamp, treeSize: sth.treeSize, rootHash: sth.rootHash });
1633
1634
  return await _verifyDigitallySigned(signedData, signature, logKey, "the signed tree head");
@@ -1668,7 +1669,7 @@ async function verifySth(sth, logKey) {
1668
1669
  * sth.treeSize; // -> 3n
1669
1670
  */
1670
1671
  async function getSth(opts) {
1671
- var door = _clientDoor(opts || {}, "logKey");
1672
+ var door = _clientDoor(opts || _create(null), "logKey");
1672
1673
  opts = door.o;
1673
1674
  /** @internal ONE read of the option, and the presence check and the copy both decide from it. Reading
1674
1675
  * it twice let an accessor answer the two separately: a non-null value for the check and an
@@ -1727,7 +1728,7 @@ async function getSth(opts) {
1727
1728
  * p.verified; // -> true
1728
1729
  */
1729
1730
  async function getProofByHash(opts) {
1730
- var door = _clientDoor(opts || {}, null);
1731
+ var door = _clientDoor(opts || _create(null), null);
1731
1732
  opts = door.o;
1732
1733
  var sth = _assertSth(opts.sth, "opts.sth");
1733
1734
  /** @internal Copied for the reason the tree head is: it is sent on the wire and then folded against the
@@ -1783,7 +1784,7 @@ async function getProofByHash(opts) {
1783
1784
  * c.verified; // -> true
1784
1785
  */
1785
1786
  async function getSthConsistency(opts) {
1786
- var door = _clientDoor(opts || {}, null);
1787
+ var door = _clientDoor(opts || _create(null), null);
1787
1788
  opts = door.o;
1788
1789
  var oldSth = _assertSth(opts.oldSth, "opts.oldSth");
1789
1790
  var newSth = _assertSth(opts.newSth, "opts.newSth");
@@ -1841,7 +1842,7 @@ async function getSthConsistency(opts) {
1841
1842
  * e.entries[0].leafInput; // -> <Buffer ...>
1842
1843
  */
1843
1844
  async function getEntries(opts) {
1844
- var door = _clientDoor(opts || {}, null);
1845
+ var door = _clientDoor(opts || _create(null), null);
1845
1846
  opts = door.o;
1846
1847
  var start = guard.range.uint64(opts.start, _ctErr, "ct/bad-input", "opts.start");
1847
1848
  var end = guard.range.uint64(opts.end, _ctErr, "ct/bad-input", "opts.end");
@@ -1899,7 +1900,7 @@ async function getEntries(opts) {
1899
1900
  */
1900
1901
  async function getRoots(opts) {
1901
1902
  /** @internal This message carries no options of its own, so the door's record is all that is used. */
1902
- var door = _clientDoor(opts || {}, null);
1903
+ var door = _clientDoor(opts || _create(null), null);
1903
1904
  var doc = await _clientJson(door, "get-roots", "roots");
1904
1905
  return guard.verdict.of({ certificates: _b64Array(doc, "certificates", "ct/bad-roots", "roots", undefined, C.LIMITS.CT_MAX_ROOTS) });
1905
1906
  }
@@ -1982,7 +1983,7 @@ async function addPreChain(opts) {
1982
1983
  * The chain encoding, the response shape, and the refusal when the receipt does not verify are one
1983
1984
  * rule stated once. */
1984
1985
  async function _addChain(opts, message, entryType) {
1985
- var door = _clientDoor(opts || {}, "logKey");
1986
+ var door = _clientDoor(opts || _create(null), "logKey");
1986
1987
  opts = door.o;
1987
1988
  /** @internal ONE read of the option, used by the presence check here and by the copy below. Reading it
1988
1989
  * twice let an accessor answer the two separately, presenting a non-null value to the check and an