@blamejs/pki 0.8.60 → 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.
Files changed (59) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +7 -0
  3. package/index.js +55 -26
  4. package/lib/acme.js +5 -5
  5. package/lib/asn1-der.js +1 -1
  6. package/lib/attrcert-sign.js +2 -2
  7. package/lib/cbor-det.js +4 -1
  8. package/lib/cmc-build.js +15 -10
  9. package/lib/cmp-build.js +5 -5
  10. package/lib/cmp-session.js +6 -3
  11. package/lib/cmp-verify.js +1 -1
  12. package/lib/cms-compress.js +5 -2
  13. package/lib/cms-decrypt.js +17 -17
  14. package/lib/cms-digest.js +2 -3
  15. package/lib/cms-encrypt.js +17 -18
  16. package/lib/cms-sign.js +2 -2
  17. package/lib/composite-kem.js +28 -29
  18. package/lib/crl-sign.js +3 -3
  19. package/lib/crmf-sign.js +12 -18
  20. package/lib/csr-sign.js +1 -1
  21. package/lib/ct.js +25 -22
  22. package/lib/est.js +12 -12
  23. package/lib/framework-error.js +1 -1
  24. package/lib/guard-bytes.js +1 -1
  25. package/lib/guard-crypto.js +506 -14
  26. package/lib/guard-limits.js +3 -2
  27. package/lib/guard-secret.js +3 -2
  28. package/lib/hpke.js +26 -26
  29. package/lib/http-digest.js +5 -7
  30. package/lib/http-retry-after.js +4 -1
  31. package/lib/http-transport.js +6 -6
  32. package/lib/inspect.js +9 -4
  33. package/lib/jose.js +3 -3
  34. package/lib/key.js +41 -29
  35. package/lib/merkle.js +4 -4
  36. package/lib/ocsp.js +3 -4
  37. package/lib/path-validate.js +3 -3
  38. package/lib/pbes2.js +14 -11
  39. package/lib/pkcs12-build.js +10 -11
  40. package/lib/pki-build.js +3 -3
  41. package/lib/scep.js +8 -9
  42. package/lib/schema-engine.js +12 -12
  43. package/lib/schema-pkix.js +12 -12
  44. package/lib/schema-tsp.js +3 -3
  45. package/lib/shbs.js +3 -6
  46. package/lib/sign-scheme.js +4 -4
  47. package/lib/sigstore.js +10 -10
  48. package/lib/smime.js +12 -9
  49. package/lib/tlog.js +5 -4
  50. package/lib/tls-cert-compress.js +3 -3
  51. package/lib/tsp-sign.js +6 -6
  52. package/lib/tuf.js +6 -5
  53. package/lib/validator-cose.js +2 -2
  54. package/lib/webauthn-mds.js +4 -8
  55. package/lib/webauthn.js +5 -12
  56. package/lib/webcrypto.js +61 -46
  57. package/lib/x509-sign.js +3 -3
  58. package/package.json +1 -1
  59. package/sbom.cdx.json +6 -6
package/CHANGELOG.md CHANGED
@@ -4,6 +4,54 @@ 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
+
31
+ ## v0.8.61 — 2026-10-07
32
+
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.
34
+
35
+ ### Added
36
+
37
+ - The internal crypto guard gained the operations the library needed to stop reading `node:crypto` at call time: randomness, the password-based and extract-and-expand derivations, the RSA transforms, the elliptic-curve point derivation and conversion, the AEAD transform methods, the hash handle for a caller that cannot hold its whole input, and the four key-identity accessors. The digest primitive takes input and output encodings. None of this is on the public surface.
38
+
39
+ ### Changed
40
+
41
+ - `pki.webcrypto.subtle.exportKey` and `pki.key.export` read a key's type at most twice per call, once to admit the key and once for every decision that follows. Nothing in the public surface changed shape, and no error code was added or removed.
42
+
43
+ ### Fixed
44
+
45
+ - An imported key is bound to the algorithm the caller named it under. `pki.webcrypto.subtle.importKey` settles that by asking the key which algorithm family it belongs to, and that answer came from an accessor on a node prototype, read at the moment of the check. An accessor answering `rsa` for an Ed25519 key therefore made the import accept it as RSA-PSS, and every later operation ran under an algorithm the key does not belong to. The accessor is captured when the engine loads. The same read also decided a curve, a modulus length and whether a key pair corresponds, across `pki.key`, `pki.tuf`, `pki.tlog`, `pki.sigstore`, `pki.cmc`, `pki.crmf`, `pki.ct` and the signature-scheme check that matches a signer to a certificate.
46
+ - A plain object carrying an `asymmetricKeyType` field is no longer accepted as a key. The sites that asked whether a caller had handed them a key object tested for that one field, which any object can carry, so a forged object passed the test and was then used as a key. The question is asked of the object's prototype now, and the answer settles both whether it is a key and which kind.
47
+ - A shared secret is derived through the agreement the toolkit captured, not one replaced afterwards. `crypto.diffieHellman` returns the traditional half of a hybrid secret outright, so a replacement supplies that half: driving `pki.hpke.decap` with one returning a fixed buffer derived a secret from the value the replacement chose. The post-quantum half, through `encapsulate` and `decapsulate`, had the same shape, as did the key generation that decides the ephemeral key an encapsulation is made under. `pki.hpke`, `pki.kem`, `pki.key`, `pki.cms` and `pki.webcrypto` all take these through operations captured at load.
48
+ - A content-encryption key, a MAC key, an IV, a nonce and a salt are drawn through the randomness the toolkit captured. Twenty-seven sites read it off the module handle when they needed it, so a replacement returning a value it already knows handed it every message those protect, and nothing downstream can tell a chosen key from a random one.
49
+ - An AEAD message is authenticated against the tag it carries. The tag is set and read through methods on the cipher object, which were reached through that object: a replacement decides which tag a ciphertext is checked against, so the verdict stops being a function of the message. The additional authenticated data, the padding mode, and the bytes a transform produces are reached the same way and are now taken through operations captured at load. The streaming paths in `pki.webcrypto` already did this; the one-shot encrypt and decrypt did not.
50
+ - A key-transport ciphertext is produced, and the secret inside one recovered, through the RSA transforms captured at load. A password-derived key-encryption key, an HKDF expansion, and the elliptic-curve point a scalar generates are the same shape: each returns a value rather than a claim about one, so a replacement returning a fixed value makes every password open the message or puts a point of its own choosing where a public key was expected.
51
+ - `pki.key.export` emits a PEM label that agrees with the bytes in the block. It asked the key its type once to choose the label and again to choose the encoding, and on a `CryptoKey` from node's own WebCrypto that is an accessor, so an accessor answering differently across those reads picked the two separately and a public key came back inside a `PRIVATE KEY` block. The type is read once and every decision in an export comes from that one answer.
52
+ - A digest is computed through the hash operation the toolkit captured, across every path that takes one: the certificate and CRL digests, the CMS message digests and countersignature imprints, the transparency-log identifiers, the PKCS#12 key derivation, the hash-based signature trees, the WebAuthn attestation comparisons and the HTTP Digest credential. `pki.scep`'s check that a named digest is available goes through the same operation, so the name it accepts is the name it would use.
53
+ - The RFC 7616 HTTP Digest credential is computed over the octets of the latin1 encoding the specification names, through one operation rather than a copy of the hash construction kept in the module. Three modules held their own copy of what the digest primitive already does; all three route through it now, and the input and output encodings are named at the call rather than defaulted.
54
+
7
55
  ## v0.8.60 — 2026-10-07
8
56
 
9
57
  Build every list a parse or an encode reads from by defining its indexes, so an accessor inherited from the array prototype cannot take an element as it is added.
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
@@ -470,8 +470,8 @@ function identityProofV2(secret, reqSequenceBytes, identity) {
470
470
  _ownSecret(Buffer.from(identity, "utf8"), owned),
471
471
  ]), owned);
472
472
  }
473
- key = nodeCrypto.createHash("sha256").update(material).digest();
474
- var witness = nodeCrypto.createHmac("sha256", key).update(reqSequenceBytes).digest();
473
+ key = guard.crypto.digest("sha256", material);
474
+ var witness = guard.crypto.hmac("sha256", key, reqSequenceBytes);
475
475
  return b.sequence([algId(OID_SHA256), algId(OID_HMAC_SHA256), b.octetString(witness)]);
476
476
  } finally {
477
477
  if (key) guard.secret.zeroize(key, CmcError, "cmc/bad-input", "the Identity Proof MAC key");
@@ -541,7 +541,7 @@ function _provesRequestKey(opening, outgoing) {
541
541
  /** @internal Keys of different types are never the same key, and comparing them through the
542
542
  * runtime's equality leaves a fault queued in the crypto library that surfaces on the next
543
543
  * unrelated key import in the process, so the type decides that case first. */
544
- if (requested.asymmetricKeyType !== opening.key.asymmetricKeyType) return false;
544
+ if (guard.crypto.keyType(requested) !== guard.crypto.keyType(opening.key)) return false;
545
545
  return intrinsic.keyEquals(requested, opening.key);
546
546
  }
547
547
  /** @internal A key the runtime engine cannot read has no KeyObject to compare, and a composite
@@ -607,7 +607,7 @@ async function _recoverProofValue(decoded, recipient, witnessHash) {
607
607
  continue; // allow:swallow-unverified this recipient is not addressed to the supplied key; the witness decides
608
608
  }
609
609
  var candidate = opened.content;
610
- var computed = nodeCrypto.createHash(witnessHash).update(candidate).digest();
610
+ var computed = guard.crypto.digest(witnessHash, candidate);
611
611
  var matches = computed.length === decoded.witness.length &&
612
612
  guard.crypto.constantTimeEqual(computed, decoded.witness);
613
613
  guard.secret.zeroize(computed, CmcError, "cmc/bad-input", "the computed witness");
@@ -674,7 +674,7 @@ async function answerPopChallenge(popChallenge, ids) {
674
674
  * in the challenge at all: neither side re-encodes it. */
675
675
  macKey = _bufferFrom(proofValue.length > POP_MAC_KEY_MAX_BYTES
676
676
  ? _subarray(proofValue, 0, POP_MAC_KEY_MAX_BYTES) : proofValue);
677
- var thePOP = nodeCrypto.createHmac(macHash, macKey).update(decoded.requestBytes).digest();
677
+ var thePOP = guard.crypto.hmac(macHash, macKey, decoded.requestBytes);
678
678
  return { algBytes: decoded.thePOPAlgID.bytes, thePOP: thePOP, ids: ids,
679
679
  recipientSpki: await _openingPublicKey(recipient, recovered.recipientType),
680
680
  challengedRequest: _requestIdentity(decoded.request) };
@@ -688,13 +688,18 @@ async function answerPopChallenge(popChallenge, ids) {
688
688
 
689
689
  function popLinkWitnessV2(secret, R) {
690
690
  _assertSecret(secret, "a POP Link Witness V2 control");
691
- var key = nodeCrypto.createHash("sha256").update(secret, "utf8").digest();
691
+ /** @internal The secret's octets, held so the finally can wipe them. Handing the string and an
692
+ * encoding to a digest instead leaves the copy inside the provider, where nothing clears it. */
693
+ var material = _bufferFrom(secret, "utf8");
694
+ var key = null;
692
695
  try {
696
+ key = guard.crypto.digest("sha256", material);
693
697
  /** @internal Inside the try, so a MAC that faults on its message still wipes the key above it. */
694
- var witness = nodeCrypto.createHmac("sha256", key).update(R).digest();
698
+ var witness = guard.crypto.hmac("sha256", key, R);
695
699
  return b.sequence([algId(OID_SHA256), algId(OID_HMAC_SHA256), b.octetString(witness)]);
696
700
  } finally {
697
- guard.secret.zeroize(key, CmcError, "cmc/bad-input", "the POP Link MAC key");
701
+ guard.secret.zeroize(material, CmcError, "cmc/bad-input", "the POP Link secret");
702
+ if (key !== null) guard.secret.zeroize(key, CmcError, "cmc/bad-input", "the POP Link MAC key");
698
703
  }
699
704
  }
700
705
 
@@ -707,7 +712,7 @@ function build(spec, signer, opts) {
707
712
  }
708
713
 
709
714
  async function _build(spec, signer, opts) {
710
- opts = opts || {};
715
+ opts = opts || intrinsic.create(null);
711
716
  if (!spec || typeof spec !== "object" || Array.isArray(spec) || Buffer.isBuffer(spec)) {
712
717
  throw E("cmc/bad-input", "the CMC request spec must be an object");
713
718
  }
@@ -935,7 +940,7 @@ async function _build(spec, signer, opts) {
935
940
  if (typeof rBytes !== "number" || !Number.isInteger(rBytes) || rBytes < 1) {
936
941
  throw E("cmc/bad-input", "popLinkRandomBytes must be a positive integer");
937
942
  }
938
- var R = nodeCrypto.randomBytes(rBytes);
943
+ var R = guard.crypto.randomBytes(rBytes);
939
944
  _push(controls,encodeControl(OID_POP_LINK_RANDOM, [b.octetString(R)], ids));
940
945
  _push(controls,encodeControl(O("id-cmc-popLinkWitnessV2"),
941
946
  [popLinkWitnessV2(spec.popLink.secret, R)], ids));
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;
@@ -4,7 +4,6 @@
4
4
  // @internal
5
5
  // @primitive pki.cms.decrypt block live in cms-verify.js, which re-exports this function.
6
6
 
7
- var nodeCrypto = require("crypto");
8
7
  var asn1 = require("./asn1-der");
9
8
  var oid = require("./oid");
10
9
  var x509 = require("./schema-x509");
@@ -35,7 +34,7 @@ var CONTENT_KEYBITS = pbes2.CONTENT_KEYBITS;
35
34
  var CONTENT_MODE = pbes2.CONTENT_MODE;
36
35
 
37
36
  async function decrypt(input, keyMaterial, opts) {
38
- opts = opts || {};
37
+ opts = opts || intrinsic.create(null);
39
38
  if (keyMaterial == null || typeof keyMaterial !== "object") throw _err("cms/bad-input", "decrypt requires a key-material object");
40
39
  /** @internal Read on every route, not only the one that applies it, and read before the message
41
40
  * is derived: deriving one runs accessors on a parsed input, which is the caller's own code and
@@ -67,7 +66,7 @@ function _originFields(res, authenticatedBy, originatorInfo) {
67
66
  }
68
67
 
69
68
  async function decryptEnvelopedData(parsed, keyMaterial, opts, contentTypeName) {
70
- opts = opts || {};
69
+ opts = opts || intrinsic.create(null);
71
70
  if (keyMaterial == null || typeof keyMaterial !== "object") throw _err("cms/bad-input", "decrypt requires a key-material object");
72
71
  var ct = contentTypeName || "envelopedData";
73
72
  var recips = parsed.recipientInfos || [];
@@ -235,8 +234,8 @@ async function _ktriCek(ri, km) {
235
234
  return Buffer.from(await subtle.decrypt({ name: "RSA-OAEP" }, pub, ri.encryptedKey));
236
235
  }
237
236
  if (kea.oid === O("rsaEncryption")) {
238
- var keyObj = nodeCrypto.createPrivateKey({ key: k.der, format: "der", type: "pkcs8" });
239
- try { return nodeCrypto.privateDecrypt({ key: keyObj, padding: guard.crypto.padding.RSA_PKCS1 }, ri.encryptedKey); }
237
+ var keyObj = guard.crypto.privateKey({ key: k.der, format: "der", type: "pkcs8" });
238
+ try { return guard.crypto.privateDecrypt({ key: keyObj, padding: guard.crypto.padding.RSA_PKCS1 }, ri.encryptedKey); }
240
239
  catch (_e) {
241
240
  return null;
242
241
  }
@@ -339,7 +338,7 @@ async function _pwriCek(ri, km, opts) {
339
338
  var iv = asn1.read.octetString(inner.children[1]);
340
339
  var pw = pbes2.passwordBytesOwned(km.password, _err, "cms");
341
340
  var kek;
342
- try { kek = nodeCrypto.pbkdf2Sync(pw.bytes, pb.salt, pb.iterations, innerBits / 8, pb.prfNode); }
341
+ try { kek = guard.crypto.pbkdf2(pw.bytes, pb.salt, pb.iterations, innerBits / 8, pb.prfNode); }
343
342
  finally { if (pw.owned) guard.secret.zeroize(pw.bytes, CmsError, "cms/bad-input", "the password encoding"); }
344
343
  try {
345
344
  return _pwriUnwrap(kek, ri.encryptedKey, iv, innerBits);
@@ -421,7 +420,7 @@ async function _openContent(parsed, eci, cek, ct, streamMode) {
421
420
  }
422
421
  if (eci.encryptedContent == null) throw _err("cms/no-encrypted-content", "the message has no encryptedContent (detached; supply it out of band)");
423
422
  var substitute = null;
424
- if (cek == null || cek.length !== keyBits / 8) { substitute = nodeCrypto.randomBytes(keyBits / 8); cek = substitute; }
423
+ if (cek == null || cek.length !== keyBits / 8) { substitute = guard.crypto.randomBytes(keyBits / 8); cek = substitute; }
425
424
  try {
426
425
  if (ct === "authEnvelopedData") {
427
426
  var aad = parsed.authAttrsBytes != null ? _explicitSetOf(parsed.authAttrsBytes) : Buffer.alloc(0);
@@ -461,9 +460,9 @@ async function _openContent(parsed, eci, cek, ct, streamMode) {
461
460
  }
462
461
  function _gcmOpen(cek, nonce, ct, tag, aad, keyBits, icvLen) {
463
462
  if (!tag || tag.length !== icvLen) throw _fail();
464
- var d = nodeCrypto.createDecipheriv("aes-" + keyBits + "-gcm", cek, nonce, { authTagLength: icvLen });
465
- d.setAuthTag(tag);
466
- if (aad && aad.length) d.setAAD(aad);
463
+ var d = guard.crypto.decipher("aes-" + keyBits + "-gcm", cek, nonce, { authTagLength: icvLen });
464
+ guard.crypto.decipherSetAuthTag(d, tag);
465
+ if (aad && aad.length) guard.crypto.transformSetAAD(d, aad);
467
466
  return guard.secret.cipherFinish(d, ct, CmsError, "cms/decrypt-failed", "the recovered content");
468
467
  }
469
468
 
@@ -543,7 +542,7 @@ async function _decryptPbes2(parsed, eci, km, opts) {
543
542
  if (!keyBits) throw _err("cms/unsupported-algorithm", "unsupported PBES2 content cipher " + encOid);
544
543
  var pwE = pbes2.passwordBytesOwned(km.password, _err, "cms");
545
544
  var key;
546
- try { key = nodeCrypto.pbkdf2Sync(pwE.bytes, pb.salt, pb.iterations, keyBits / 8, pb.prfNode); }
545
+ try { key = guard.crypto.pbkdf2(pwE.bytes, pb.salt, pb.iterations, keyBits / 8, pb.prfNode); }
547
546
  finally { if (pwE.owned) guard.secret.zeroize(pwE.bytes, CmsError, "cms/bad-input", "the password encoding"); }
548
547
  try { return _originFields({ content: opts.stream === true ? _cbcStream(key, iv, eci.encryptedContent, keyBits) : pbes2.cbcDecrypt(key, iv, eci.encryptedContent, keyBits, CmsError, "cms/decrypt-failed"), contentType: eci.contentType, contentTypeName: oid.name(eci.contentType) || eci.contentType, recipientType: "password", recipientIndex: -1, contentEncryptionAlgorithm: oid.name(encOid) || encOid, authenticated: false }, null, null); }
549
548
  catch (_e) { throw _fail(); }
@@ -588,13 +587,13 @@ function _pwriUnwrap(kek, wrapped, iv, keyBits) {
588
587
  var n = wrapped.length;
589
588
  var lastDec = null, pass1 = null, body = null;
590
589
  try {
591
- var ecb = nodeCrypto.createDecipheriv("aes-" + keyBits + "-ecb", kek, Buffer.alloc(0)); ecb.setAutoPadding(false);
590
+ var ecb = guard.crypto.decipher("aes-" + keyBits + "-ecb", kek, Buffer.alloc(0)); guard.crypto.transformNoPadding(ecb);
592
591
  lastDec = guard.secret.cipherFinish(ecb, wrapped.subarray(n - blk), CmsError, "cms/decrypt-failed", "the recovered CBC last block");
593
592
  var iv2 = Buffer.alloc(blk);
594
593
  for (var i = 0; i < blk; i++) iv2[i] = lastDec[i] ^ wrapped[n - 2 * blk + i];
595
- var d1 = nodeCrypto.createDecipheriv(alg, kek, iv2); d1.setAutoPadding(false);
594
+ var d1 = guard.crypto.decipher(alg, kek, iv2); guard.crypto.transformNoPadding(d1);
596
595
  pass1 = guard.secret.cipherFinish(d1, wrapped, CmsError, "cms/decrypt-failed", "the PWRI first-pass plaintext");
597
- var d2 = nodeCrypto.createDecipheriv(alg, kek, iv); d2.setAutoPadding(false);
596
+ var d2 = guard.crypto.decipher(alg, kek, iv); guard.crypto.transformNoPadding(d2);
598
597
  body = guard.secret.cipherFinish(d2, pass1, CmsError, "cms/decrypt-failed", "the PWRI plaintext block");
599
598
  var count = body[0];
600
599
  if (count < 1 || count + 4 > body.length) throw _fail();
@@ -670,8 +669,9 @@ function _ecCurveFromCert(cert) {
670
669
  function _ecCurveFromPrivateKey(keyDer) {
671
670
  var spki;
672
671
  try {
673
- spki = nodeCrypto.createPublicKey({ key: keyDer, format: "der", type: "pkcs8" })
674
- .export({ format: "der", type: "spki" });
672
+ spki = guard.crypto.exportKey(
673
+ guard.crypto.publicKey({ key: keyDer, format: "der", type: "pkcs8" }),
674
+ { format: "der", type: "spki" });
675
675
  } catch (_e) { return null; } // allow:swallow-unverified a key this runtime cannot read names no curve
676
676
  var alg = asn1.decode(spki).children[0];
677
677
  if (asn1.read.oid(alg.children[0]) !== O("ecPublicKey") || alg.children.length < 2) return null;
@@ -756,7 +756,7 @@ async function _verifyAuthenticatedData(parsed, km, opts, requireProtection) {
756
756
  _assertSupported(candidates[ci].ri, km);
757
757
  var macKey = await _acquireCek(candidates[ci].ri, km, opts);
758
758
  var macSubstitute = null;
759
- if (macKey == null || macKey.length < MAC_KEY_MIN_OCTETS) macSubstitute = nodeCrypto.randomBytes(MAC_KEY_MIN_OCTETS);
759
+ if (macKey == null || macKey.length < MAC_KEY_MIN_OCTETS) macSubstitute = guard.crypto.randomBytes(MAC_KEY_MIN_OCTETS);
760
760
  try {
761
761
  var key = await subtle.importKey("raw", macSubstitute || macKey, { name: "HMAC", hash: hash }, false, ["verify"]);
762
762
  if (!(await _subtleVerify(subtle, { name: "HMAC" }, key, Buffer.from(parsed.mac), preimage))) throw _fail();