@blamejs/core 0.18.41 → 0.18.42
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 +10 -0
- package/NOTICE +1 -1
- package/README.md +1 -1
- package/lib/middleware/bot-guard.js +33 -10
- package/lib/vendor/MANIFEST.json +12 -12
- package/lib/vendor/blamejs-pki.cjs +104 -73
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,16 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.18.x
|
|
10
10
|
|
|
11
|
+
- v0.18.42 (2026-08-20) — **`b.middleware.botGuard` no longer refuses a request for omitting Accept-Language, which was returning 403 to every search-engine crawler.** `b.middleware.botGuard` treated a missing `Accept-Language` header as grounds for a 403 in its default blocking mode. Google documents that Googlebot sends requests without setting that header, and bingbot behaves the same, so every content page of a site running the default middleware chain answered 403 to a crawler while a browser was served normally. The header's absence is now an advisory signal, matching how the same middleware already treats a missing `Sec-Fetch-Mode`. **Changed:** *Vendored `@blamejs/pki` 0.5.16 to 0.5.17* — A failed integrity check now destroys the plaintext it had recovered rather than returning it, `AuthEnvelopedData` validates the attributes it is asked to authenticate, and the refusal for a content cipher in the wrong container cites the rule it actually applies — RFC 5083 §2 defines `AuthEnvelopedData` in terms of authenticated encryption and never names GCM, so the previous message sent operators to argue with a specification that says the opposite. **Fixed:** *A missing `Accept-Language` tags a request instead of refusing it* — The check was `if (!headers["accept-language"]) return "missing-accept-language"`, and `mode` defaults to `"block"`, so the request was answered 403. Whole client families omit the header — every major search-engine crawler, and with them uptime monitors, link previewers and feed readers — which made a site unreachable to all of them. On a deployment fronted by a cache this is easy to miss from the outside: the cached home page still answers 200, so the site looks partly indexed while every other URL is refused.
|
|
12
|
+
|
|
13
|
+
It now sets `req.suspectedBot` in `mode: "tag"` and never blocks, which is exactly how the middleware already treats a missing `Sec-Fetch-Mode` — absent for Safari before 16.4 and for every plain-HTTP non-localhost origin — and how `b.middleware.fetchMetadata` already treats a missing `Sec-Fetch-Site` through its `allowMissing` default. A header a whole client family omits is not evidence of automation.
|
|
14
|
+
|
|
15
|
+
Requests are still refused on positive evidence: the `User-Agent` deny-list (curl, wget, python-requests, axios, Go-http-client and the rest) is unchanged, and operators can extend it with `blockedAgents`. Separating a crawler from an abuser is a rate-limiting question rather than a header one, and `b.rateLimit` answers it.
|
|
16
|
+
|
|
17
|
+
If you were relying on the old behaviour, `mode: "tag"` surfaces the same signal on `req.suspectedBot` for you to act on. **Detectors:** *No single absent header may block, asserted against the middleware* — `bot-guard.test.js` now starts from a complete browser request and removes one header at a time, asserting that no single omission refuses the request. It covers the headers the middleware inspects — `User-Agent`, `Accept`, `Accept-Language`, `Accept-Encoding` and the three `Sec-Fetch-*` — so the rule holds for whichever one a future change reaches for, not only the one that was wrong.
|
|
18
|
+
|
|
19
|
+
It is a behavioural check rather than a source-pattern one deliberately. Written as a pattern check first, it was wrong six different ways: anchored to the first expression in the condition, bounded at the first `)`, bounded to a single line, defeated by a statement before the return, by a guard that was OR'd rather than AND'd, and by a `)` inside a string literal. Each fix was a step further into parsing JavaScript with text matching. Running the middleware decides all six, because it asks what the code does rather than how it is written. **References:** [How Google crawls locale-adaptive pages — Googlebot and Accept-Language](https://developers.google.com/search/docs/specialty/international/locale-adaptive-pages)
|
|
20
|
+
|
|
11
21
|
- v0.18.41 (2026-08-20) — **Logout can now clear the session cookie on a plain-HTTP origin, and every Set-Cookie the framework writes goes through one validating writer.** `b.session.logout` built its expiry cookie by string concatenation with `Secure` hardcoded. A browser refuses a `Secure` cookie that arrives over plain HTTP, so on a cleartext deployment the header was discarded and the session cookie the logout existed to clear stayed in the jar. `b.middleware.csrfProtect` had its own cookie formatter with the same shape and a different consequence: it interpolated the configured `cookie.path` into the response header with no CRLF scrub. Both now compose `b.cookies`, which is the framework's single Set-Cookie writer. **Added:** *`b.cookies.assertAppendable(res)`* — Throws unless a response can carry an appended `Set-Cookie` — the same check `appendSetCookie` performs, exposed so a caller can run it before doing something it cannot undo. A response has to be readable as well as writable to be appended to: without `appendHeader` the merge happens in the framework and needs to see what is already queued, and a response carrying only `setHeader` would have its existing cookies silently replaced. `b.session.logout` calls it up front, because it revokes the session row before queueing the expiry cookie — a refusal at queue time would leave the session destroyed, the browser still holding its cookie, and the request failing. · *`b.cookies.appendSetCookie(res, header)`* — Queues one `Set-Cookie` header without discarding the ones already queued. `res.setHeader("Set-Cookie", value)` replaces the header, so a route that issues a session cookie and then a CSRF cookie sends only the second; `Set-Cookie` is the one response header that is legitimately repeated. The appender uses `res.appendHeader` where the runtime offers it and array-merges where it does not.
|
|
12
22
|
|
|
13
23
|
It pairs with `b.cookies.serialize`, which validates and builds the header string. `b.cookies.create().write()` and `.clear()` compose both; reach for the two separately when you need to build the header at one point in a flow and queue it at another — validating early, emitting only once the side effect it accompanies has succeeded, which is what `b.session.logout` does with the session row. **Changed:** *`b.session.logout` queues its expiry cookie rather than overwriting the header* — It called `res.setHeader("Set-Cookie", ...)`, which discarded any cookie the route had already queued — a rotated CSRF token, a locale. It now appends. Code reading `res.getHeader("Set-Cookie")` after a logout sees an array of header strings rather than a single string; Node accepts either form on the way out.
|
package/NOTICE
CHANGED
|
@@ -68,7 +68,7 @@ Used for: FIPS 203 ML-KEM (ml_kem_512 / ml_kem_768 / ml_kem_1024),
|
|
|
68
68
|
reference implementation.
|
|
69
69
|
--------------------------------------------------------------------------------
|
|
70
70
|
Component: @blamejs/pki
|
|
71
|
-
Version: 0.5.
|
|
71
|
+
Version: 0.5.17
|
|
72
72
|
Source: https://github.com/blamejs/pki
|
|
73
73
|
License: Apache-2.0
|
|
74
74
|
Copyright: Copyright (c) blamejs contributors
|
package/README.md
CHANGED
|
@@ -322,7 +322,7 @@ All runtime dependencies are committed to the repo — no transitive npm install
|
|
|
322
322
|
| [`@noble/hashes`](https://github.com/paulmillr/noble-hashes) | 2.3.0 | [Paul Miller](https://github.com/paulmillr) | Browser (ESM) build only — SHAKE256 / SHA-3 / SHA-2 / HMAC / HKDF for the client half of a hybrid exchange. The server side reaches all of these through `node:crypto`, so there is no server bundle |
|
|
323
323
|
| [`@noble/curves`](https://github.com/paulmillr/noble-curves) | 2.3.0 (bundles @noble/hashes 2.3.0) | [Paul Miller](https://github.com/paulmillr) | RFC 9497 Oblivious Pseudo-Random Function (OPRF / VOPRF / POPRF) over ristretto255 / P-256 / P-384 / P-521, behind `b.crypto.oprf` |
|
|
324
324
|
| [`@noble/post-quantum`](https://github.com/paulmillr/noble-post-quantum) | 0.7.0 (bundles @noble/hashes, @noble/curves, @noble/ciphers 2.3.0) | [Paul Miller](https://github.com/paulmillr) | Pure-JS FIPS 203 ML-KEM (`ml_kem_512` / `ml_kem_768` / `ml_kem_1024`), FIPS 204 ML-DSA (`ml_dsa_44/65/87`), FIPS 205 SLH-DSA (`slh_dsa_*`). First-class on both server-side and client-side via `b.pqcSoftware` — security-first defaults pin to the highest cat-5 levels (ML-KEM-1024, ML-DSA-87, SLH-DSA-SHAKE-256f); interoperable with Node's built-in WebCrypto ML-KEM that `b.crypto.encrypt` / `b.middleware.apiEncrypt` use. A browser (ESM) build ships beside it carrying the KEM suites only — a client half encapsulates and does not sign |
|
|
325
|
-
| [`@blamejs/pki`](https://github.com/blamejs/pki) | 0.5.
|
|
325
|
+
| [`@blamejs/pki`](https://github.com/blamejs/pki) | 0.5.17 | [blamejs](https://github.com/blamejs) | Zero-dependency pure-JS X.509 / CRL / PKCS#12 / CSR / CMS toolkit backing `b.mtlsCa` — ML-DSA-87 (FIPS 204) post-quantum + ECDSA-P384 cert signing, PBMAC1 PKCS#12 packaging, chain validation (no openssl CLI) — and the WebAuthn attestation / assertion verification behind `b.auth.passkey` |
|
|
326
326
|
| [`SecLists` 10k-most-common.txt](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) | master snapshot | [Daniel Miessler / SecLists contributors](https://github.com/danielmiessler/SecLists) (CC-BY-3.0) | Top-10000 common-password dictionary read by `b.auth.password.policy()` for the NIST 800-63B §5.1.1.2 "previously breached" check |
|
|
327
327
|
| [`prismjs`](https://prismjs.com/) | 1.30.0 | [Lea Verou + contributors](https://github.com/PrismJS/prism) | Syntax highlighting in the example wiki's code blocks (browser-side) |
|
|
328
328
|
|
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* authentication, but catches drive-by scrapers and most low-effort bots.
|
|
8
8
|
*
|
|
9
9
|
* Heuristics (all combined):
|
|
10
|
-
* - Missing Accept-Language header
|
|
10
|
+
* - Missing Accept-Language header — ADVISORY ONLY (never blocks). Tagged
|
|
11
|
+
* in mode:"tag". It cannot block because the header is absent for entire
|
|
12
|
+
* client families: every major search-engine crawler omits it (Google
|
|
13
|
+
* documents that Googlebot "sends HTTP requests without setting
|
|
14
|
+
* Accept-Language"), as do uptime monitors, link previewers and feed
|
|
15
|
+
* readers — a 403 on it alone made a site's every page unreachable to
|
|
16
|
+
* Googlebot while a browser sailed through.
|
|
11
17
|
* - Missing Sec-Fetch-Mode header — ADVISORY ONLY (never blocks). Tagged
|
|
12
18
|
* in mode:"tag" on secure-context HTML GETs where a modern browser
|
|
13
19
|
* would have sent it. It cannot block because the header is absent for
|
|
@@ -90,13 +96,15 @@ function _coerceAgentPattern(r, where) {
|
|
|
90
96
|
* Cheap fingerprint-based detection of obviously-non-browser requests.
|
|
91
97
|
* Constructed via `b.middleware.botGuard(opts)`; the resulting
|
|
92
98
|
* middleware has the `(req, res, next)` shape shown above.
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
99
|
+
* One blocking heuristic — a User-Agent regex match against a default
|
|
100
|
+
* list (curl / wget / python-requests / axios / etc.) — plus two
|
|
101
|
+
* advisory signals that set `req.suspectedBot` in `mode: "tag"` and
|
|
102
|
+
* NEVER block: a missing `Accept-Language` (absent from every major
|
|
103
|
+
* search-engine crawler, so blocking on it makes a site unreachable to
|
|
104
|
+
* them) and a missing `Sec-Fetch-Mode` on a secure-context HTML GET
|
|
105
|
+
* (absent for Safari < 16.4 and every plain-HTTP non-localhost origin).
|
|
106
|
+
* A header a whole client family omits is not evidence of automation.
|
|
107
|
+
* Not
|
|
100
108
|
* a substitute for proper authentication — catches drive-by scrapers
|
|
101
109
|
* and low-effort bots. In `mode: "block"` (default) the request is
|
|
102
110
|
* refused; in `mode: "tag"` `req.suspectedBot = true` is set and the
|
|
@@ -206,14 +214,29 @@ function create(opts) {
|
|
|
206
214
|
// Skip browser-fingerprint checks for API routes
|
|
207
215
|
return null;
|
|
208
216
|
}
|
|
209
|
-
|
|
217
|
+
// Missing Accept-Language NEVER blocks, for the reason the Sec-Fetch-Mode
|
|
218
|
+
// check below does not either: the header is absent for entire CLIENT
|
|
219
|
+
// families, so a 403 on it alone refuses them wholesale. Every major
|
|
220
|
+
// search-engine crawler omits it — Google documents that Googlebot "sends
|
|
221
|
+
// HTTP requests without setting Accept-Language in the request header",
|
|
222
|
+
// and bingbot behaves the same — so blocking on it made every content page
|
|
223
|
+
// of a blamejs site answer 403 to a crawler while a browser sailed
|
|
224
|
+
// through. Measured on a live deployment: a 337-URL sitemap of which only
|
|
225
|
+
// the cached homepage was reachable. Uptime monitors, link previewers and
|
|
226
|
+
// feed readers are refused the same way.
|
|
227
|
+
//
|
|
228
|
+
// It survives as an advisory TAG, so an operator can still rate-limit or
|
|
229
|
+
// log on it. Automation libraries remain blocked by the User-Agent
|
|
230
|
+
// deny-list, which is what actually distinguishes them; separating a
|
|
231
|
+
// crawler from an abuser is a rate-limiting question, not a header one.
|
|
232
|
+
if (mode === "tag" && !headers["accept-language"]) return "missing-accept-language";
|
|
210
233
|
// Missing Sec-Fetch-Mode NEVER blocks: the header is absent for entire
|
|
211
234
|
// browser families (Safari < 16.4 omits Fetch Metadata even over HTTPS)
|
|
212
235
|
// and for every plain-HTTP non-localhost origin (Umbrel, LAN / *.local
|
|
213
236
|
// reverse proxies), so a 403 on it alone refuses real users. It survives
|
|
214
237
|
// only as an advisory TAG in mode:"tag", and even then only in a secure
|
|
215
238
|
// context where a modern browser would have sent it. Drive-by bots are
|
|
216
|
-
// still blocked by
|
|
239
|
+
// still blocked by the User-Agent deny-list.
|
|
217
240
|
if (mode === "tag" && req.method === "GET" && _isSecureContext(req) && !headers["sec-fetch-mode"]) return "missing-sec-fetch-mode";
|
|
218
241
|
return null;
|
|
219
242
|
}
|
package/lib/vendor/MANIFEST.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"server": "sha256:f3325f480cb8eb814fcb0baaa19336cbbf2b993f48624c6aa9600ffd69d0be5e",
|
|
22
22
|
"browser": "sha256:0ffd91540bcb586a29b56e52ee1c29df69097b50776beb4036a07558f7a4e12e"
|
|
23
23
|
},
|
|
24
|
-
"refreshedAt": "2026-08-
|
|
24
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
25
25
|
},
|
|
26
26
|
"@noble/hashes": {
|
|
27
27
|
"version": "2.3.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"hashes": {
|
|
49
49
|
"browser": "sha256:dfe4b7ae3c9880e388c8da4b68f44742b229b53afacd1e674179527e33da62b0"
|
|
50
50
|
},
|
|
51
|
-
"refreshedAt": "2026-08-
|
|
51
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
52
52
|
},
|
|
53
53
|
"@noble/curves": {
|
|
54
54
|
"version": "2.3.0",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"hashes": {
|
|
71
71
|
"server": "sha256:b5fe88d1ea780d0581dee6145d666f89d46fc9531b5db35db2e5b16627840890"
|
|
72
72
|
},
|
|
73
|
-
"refreshedAt": "2026-08-
|
|
73
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z",
|
|
74
74
|
"components": {
|
|
75
75
|
"@noble/hashes": {
|
|
76
76
|
"url": "https://github.com/paulmillr/noble-hashes",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"server": "sha256:fab7ebe5737793862c473444f4ee5912f79dd1edec86683acbb4eecbca0f5892",
|
|
115
115
|
"browser": "sha256:cae1d5bbdc7184b202b6ca68df6e1db7b0d0f668c77809ded189ca7f271accc9"
|
|
116
116
|
},
|
|
117
|
-
"refreshedAt": "2026-08-
|
|
117
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z",
|
|
118
118
|
"components": {
|
|
119
119
|
"@noble/hashes": {
|
|
120
120
|
"url": "https://github.com/paulmillr/noble-hashes",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
},
|
|
149
149
|
"runtime_artifact": "lib/vendor/common-passwords-top-10000.data.js",
|
|
150
150
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
151
|
-
"refreshedAt": "2026-08-
|
|
151
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
152
152
|
},
|
|
153
153
|
"bimi-trust-anchors": {
|
|
154
154
|
"version": "operator-managed",
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
},
|
|
174
174
|
"runtime_artifact": "lib/vendor/bimi-trust-anchors.data.js",
|
|
175
175
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
176
|
-
"refreshedAt": "2026-08-
|
|
176
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
177
177
|
},
|
|
178
178
|
"publicsuffix-list": {
|
|
179
179
|
"version": "master",
|
|
@@ -193,10 +193,10 @@
|
|
|
193
193
|
},
|
|
194
194
|
"runtime_artifact": "lib/vendor/public-suffix-list.data.js",
|
|
195
195
|
"integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
|
|
196
|
-
"refreshedAt": "2026-08-
|
|
196
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
197
197
|
},
|
|
198
198
|
"@blamejs/pki": {
|
|
199
|
-
"version": "0.5.
|
|
199
|
+
"version": "0.5.17",
|
|
200
200
|
"license": "Apache-2.0",
|
|
201
201
|
"author": "blamejs",
|
|
202
202
|
"source": "https://github.com/blamejs/pki",
|
|
@@ -216,12 +216,12 @@
|
|
|
216
216
|
"server": "lib/vendor/blamejs-pki.cjs"
|
|
217
217
|
},
|
|
218
218
|
"bundler": "esbuild --format=cjs --platform=node --external:crypto --external:node:crypto",
|
|
219
|
-
"bundledAt": "2026-08-
|
|
220
|
-
"cpe": "cpe:2.3:a:blamejs:pki:0.5.
|
|
219
|
+
"bundledAt": "2026-08-20T00:00:00Z",
|
|
220
|
+
"cpe": "cpe:2.3:a:blamejs:pki:0.5.17:*:*:*:*:node.js:*:*",
|
|
221
221
|
"hashes": {
|
|
222
|
-
"server": "sha256:
|
|
222
|
+
"server": "sha256:dbedb80e1725747a24fdbd3dec9fcab31b507ac048b923462382b6ac117937a0"
|
|
223
223
|
},
|
|
224
|
-
"refreshedAt": "2026-08-
|
|
224
|
+
"refreshedAt": "2026-08-20T15:14:48.311Z"
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @blamejs/pki v0.5.
|
|
1
|
+
// @blamejs/pki v0.5.17 — vendored (Apache-2.0). Zero-dep pure CJS.
|
|
2
2
|
// https://github.com/blamejs/pki Exports: x509, crl, pkcs12, key, webcrypto, schema, csr, cms, ...
|
|
3
3
|
// Backs lib/mtls-engine-default.js (PQC-capable CA + PKCS#12 engine).
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -141,7 +141,7 @@ var require_package = __commonJS({
|
|
|
141
141
|
"node_modules/@blamejs/pki/package.json"(exports2, module2) {
|
|
142
142
|
module2.exports = {
|
|
143
143
|
name: "@blamejs/pki",
|
|
144
|
-
version: "0.5.
|
|
144
|
+
version: "0.5.17",
|
|
145
145
|
description: "Pure-JavaScript PKI toolkit that owns its stack \u2014 X.509, ASN.1/DER, CMS, PQC-first.",
|
|
146
146
|
license: "Apache-2.0",
|
|
147
147
|
author: "blamejs contributors",
|
|
@@ -2512,7 +2512,7 @@ var require_webcrypto = __commonJS({
|
|
|
2512
2512
|
return _withSecretBytes(key, function(kb) {
|
|
2513
2513
|
var cipher = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: (alg.tagLength || 128) / 8 });
|
|
2514
2514
|
if (aad) cipher.setAAD(aad);
|
|
2515
|
-
var ct =
|
|
2515
|
+
var ct = guard.secret.cipherFinish(cipher, buf, WebCryptoError, "webcrypto/operation", "an AES-GCM encrypt intermediate");
|
|
2516
2516
|
return Buffer.concat([ct, cipher.getAuthTag()]);
|
|
2517
2517
|
});
|
|
2518
2518
|
}, "encrypt"));
|
|
@@ -2522,7 +2522,7 @@ var require_webcrypto = __commonJS({
|
|
|
2522
2522
|
return _toArrayBuffer(_runCipher(function() {
|
|
2523
2523
|
return _withSecretBytes(key, function(kb) {
|
|
2524
2524
|
var c2 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv);
|
|
2525
|
-
return
|
|
2525
|
+
return guard.secret.cipherFinish(c2, buf, WebCryptoError, "webcrypto/operation", "an AES-CBC encrypt intermediate");
|
|
2526
2526
|
});
|
|
2527
2527
|
}, "encrypt"));
|
|
2528
2528
|
}
|
|
@@ -2532,7 +2532,7 @@ var require_webcrypto = __commonJS({
|
|
|
2532
2532
|
return _toArrayBuffer(_runCipher(function() {
|
|
2533
2533
|
return _withSecretBytes(key, function(kb) {
|
|
2534
2534
|
var c3 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter);
|
|
2535
|
-
return
|
|
2535
|
+
return guard.secret.cipherFinish(c3, buf, WebCryptoError, "webcrypto/operation", "an AES-CTR encrypt intermediate");
|
|
2536
2536
|
});
|
|
2537
2537
|
}, "encrypt"));
|
|
2538
2538
|
}
|
|
@@ -2570,7 +2570,7 @@ var require_webcrypto = __commonJS({
|
|
|
2570
2570
|
var d = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: tagLen });
|
|
2571
2571
|
if (gcmAad) d.setAAD(gcmAad);
|
|
2572
2572
|
d.setAuthTag(tag);
|
|
2573
|
-
return
|
|
2573
|
+
return guard.secret.cipherFinish(d, ct, WebCryptoError, "webcrypto/operation", "the recovered AES-GCM plaintext");
|
|
2574
2574
|
});
|
|
2575
2575
|
}, "decrypt"));
|
|
2576
2576
|
}
|
|
@@ -2579,7 +2579,7 @@ var require_webcrypto = __commonJS({
|
|
|
2579
2579
|
return _toArrayBuffer(_runCipher(function() {
|
|
2580
2580
|
return _withSecretBytes(key, function(kb) {
|
|
2581
2581
|
var d2 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv2);
|
|
2582
|
-
return
|
|
2582
|
+
return guard.secret.cipherFinish(d2, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CBC plaintext");
|
|
2583
2583
|
});
|
|
2584
2584
|
}, "decrypt"));
|
|
2585
2585
|
}
|
|
@@ -2589,7 +2589,7 @@ var require_webcrypto = __commonJS({
|
|
|
2589
2589
|
return _toArrayBuffer(_runCipher(function() {
|
|
2590
2590
|
return _withSecretBytes(key, function(kb) {
|
|
2591
2591
|
var d3 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter2);
|
|
2592
|
-
return
|
|
2592
|
+
return guard.secret.cipherFinish(d3, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CTR plaintext");
|
|
2593
2593
|
});
|
|
2594
2594
|
}, "decrypt"));
|
|
2595
2595
|
}
|
|
@@ -2809,7 +2809,7 @@ var require_webcrypto = __commonJS({
|
|
|
2809
2809
|
try {
|
|
2810
2810
|
return _withSecretBytes(wrappingKey, function(wkBytes) {
|
|
2811
2811
|
var c = nodeCrypto.createCipheriv("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
|
|
2812
|
-
return _toArrayBuffer(
|
|
2812
|
+
return _toArrayBuffer(guard.secret.cipherFinish(c, bytes, WebCryptoError, "webcrypto/operation", "an AES-KW wrap intermediate"));
|
|
2813
2813
|
});
|
|
2814
2814
|
} catch (e) {
|
|
2815
2815
|
throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW key wrap failed", e);
|
|
@@ -2835,7 +2835,7 @@ var require_webcrypto = __commonJS({
|
|
|
2835
2835
|
try {
|
|
2836
2836
|
bytes = _withSecretBytes(unwrappingKey, function(kwBytes) {
|
|
2837
2837
|
var d = nodeCrypto.createDecipheriv("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
|
|
2838
|
-
return
|
|
2838
|
+
return guard.secret.cipherFinish(d, wrapped, WebCryptoError, "webcrypto/operation", "the unwrapped key material");
|
|
2839
2839
|
});
|
|
2840
2840
|
} catch (e) {
|
|
2841
2841
|
throw new WebCryptoError("webcrypto/operation", "unwrapKey: AES-KW key unwrap failed (integrity or length)", e);
|
|
@@ -3419,6 +3419,7 @@ var require_guard_secret = __commonJS({
|
|
|
3419
3419
|
var bytes = require_guard_bytes();
|
|
3420
3420
|
var intrinsic = require_guard_intrinsic();
|
|
3421
3421
|
var _fill = intrinsic.uncurry(Uint8Array.prototype.fill);
|
|
3422
|
+
var _concat = intrinsic.bufferConcat;
|
|
3422
3423
|
function zeroize(value, ErrorClass, code, label) {
|
|
3423
3424
|
if (value === null || value === void 0) return value;
|
|
3424
3425
|
var view = bytes.view(value, ErrorClass, code, label);
|
|
@@ -3430,7 +3431,18 @@ var require_guard_secret = __commonJS({
|
|
|
3430
3431
|
for (var i = 0; i < list.length; i++) zeroize(list[i], ErrorClass, code, label);
|
|
3431
3432
|
return list;
|
|
3432
3433
|
}
|
|
3433
|
-
|
|
3434
|
+
function cipherFinish(transform, input, ErrorClass, code, label) {
|
|
3435
|
+
var head = null, tail = null;
|
|
3436
|
+
try {
|
|
3437
|
+
head = transform.update(input);
|
|
3438
|
+
tail = transform.final();
|
|
3439
|
+
return _concat([head, tail]);
|
|
3440
|
+
} finally {
|
|
3441
|
+
zeroize(head, ErrorClass, code, label);
|
|
3442
|
+
zeroize(tail, ErrorClass, code, label);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
module2.exports = { zeroize, zeroizeAll, cipherFinish };
|
|
3434
3446
|
}
|
|
3435
3447
|
});
|
|
3436
3448
|
|
|
@@ -18943,13 +18955,13 @@ var require_pbes2 = __commonJS({
|
|
|
18943
18955
|
}
|
|
18944
18956
|
return { salt, iterations, prfNode };
|
|
18945
18957
|
}
|
|
18946
|
-
function cbcEncrypt(key, iv, plaintext, keyBits) {
|
|
18958
|
+
function cbcEncrypt(key, iv, plaintext, keyBits, E, code) {
|
|
18947
18959
|
var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
18948
|
-
return
|
|
18960
|
+
return guard.secret.cipherFinish(c, plaintext, E, code, "a content-encryption intermediate");
|
|
18949
18961
|
}
|
|
18950
|
-
function cbcDecrypt(key, iv, ct, keyBits) {
|
|
18962
|
+
function cbcDecrypt(key, iv, ct, keyBits, E, code) {
|
|
18951
18963
|
var d = nodeCrypto.createDecipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
18952
|
-
return
|
|
18964
|
+
return guard.secret.cipherFinish(d, ct, E, code, "the partially recovered plaintext");
|
|
18953
18965
|
}
|
|
18954
18966
|
function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
|
|
18955
18967
|
opts = opts || {};
|
|
@@ -18963,7 +18975,7 @@ var require_pbes2 = __commonJS({
|
|
|
18963
18975
|
var iv = opts.iv != null ? opts.iv : nodeCrypto.randomBytes(16);
|
|
18964
18976
|
var key = nodeCrypto.pbkdf2Sync(pwBytes, salt, iterations, keyBits / 8, prfNode);
|
|
18965
18977
|
try {
|
|
18966
|
-
return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits) };
|
|
18978
|
+
return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits, E, prefix + "/bad-input") };
|
|
18967
18979
|
} finally {
|
|
18968
18980
|
guard.secret.zeroize(key, E, prefix + "/bad-input", "the password-derived encryption key");
|
|
18969
18981
|
}
|
|
@@ -18994,7 +19006,7 @@ var require_pbes2 = __commonJS({
|
|
|
18994
19006
|
}
|
|
18995
19007
|
var dk = nodeCrypto.pbkdf2Sync(pwBytes, pb.salt, pb.iterations, keyBits / 8, pb.prfNode);
|
|
18996
19008
|
try {
|
|
18997
|
-
return cbcDecrypt(dk, iv, ciphertext, keyBits);
|
|
19009
|
+
return cbcDecrypt(dk, iv, ciphertext, keyBits, E, prefix + "/decrypt-failed");
|
|
18998
19010
|
} catch (_e) {
|
|
18999
19011
|
throw E(prefix + "/decrypt-failed", "decryption failed");
|
|
19000
19012
|
} finally {
|
|
@@ -20495,7 +20507,7 @@ var require_cms_sign = __commonJS({
|
|
|
20495
20507
|
function _buildSignedAttrs(pairs) {
|
|
20496
20508
|
var seenTypes = {};
|
|
20497
20509
|
var attrs = pairs.map(function(p) {
|
|
20498
|
-
if (seenTypes
|
|
20510
|
+
if (guard.intrinsic.hasOwn(seenTypes, p.type)) throw _err("cms/bad-input", "signedAttrs must not repeat an attribute type (RFC 5652 sec. 5.3): " + p.type);
|
|
20499
20511
|
seenTypes[p.type] = 1;
|
|
20500
20512
|
return b.sequence([b.oid(p.type), b.set(p.values)]);
|
|
20501
20513
|
});
|
|
@@ -20524,8 +20536,8 @@ var require_cms_sign = __commonJS({
|
|
|
20524
20536
|
var pairs = _resolveAttrPairs(list, "an unsigned attribute value");
|
|
20525
20537
|
var seen = {};
|
|
20526
20538
|
pairs.forEach(function(p) {
|
|
20527
|
-
if (UNSIGNED_FORBIDDEN
|
|
20528
|
-
if (seen
|
|
20539
|
+
if (guard.intrinsic.hasOwn(UNSIGNED_FORBIDDEN, p.type)) throw _err("cms/bad-input", "the " + UNSIGNED_FORBIDDEN[p.type] + " attribute must not appear as an unsigned attribute (RFC 5652 sec. 11)");
|
|
20540
|
+
if (guard.intrinsic.hasOwn(seen, p.type)) throw _err("cms/bad-input", "unsignedAttrs must not repeat an attribute type (RFC 5652 sec. 5.3): " + p.type);
|
|
20529
20541
|
seen[p.type] = 1;
|
|
20530
20542
|
});
|
|
20531
20543
|
var setOf = b.set(pairs.map(function(p) {
|
|
@@ -21187,11 +21199,11 @@ var require_cms_encrypt = __commonJS({
|
|
|
21187
21199
|
try {
|
|
21188
21200
|
var c1 = nodeCrypto.createCipheriv("aes-256-cbc", kek, iv);
|
|
21189
21201
|
c1.setAutoPadding(false);
|
|
21190
|
-
var pass1 =
|
|
21202
|
+
var pass1 = guard.secret.cipherFinish(c1, wk, CmsError, "cms/bad-input", "the PWRI first-pass ciphertext");
|
|
21191
21203
|
var iv2 = pass1.subarray(pass1.length - 16);
|
|
21192
21204
|
var c2 = nodeCrypto.createCipheriv("aes-256-cbc", kek, iv2);
|
|
21193
21205
|
c2.setAutoPadding(false);
|
|
21194
|
-
return
|
|
21206
|
+
return guard.secret.cipherFinish(c2, pass1, CmsError, "cms/bad-input", "the PWRI wrapped key");
|
|
21195
21207
|
} finally {
|
|
21196
21208
|
guard.secret.zeroize(wk, CmsError, "cms/bad-input", "the PWRI plaintext block");
|
|
21197
21209
|
}
|
|
@@ -21258,10 +21270,37 @@ var require_cms_encrypt = __commonJS({
|
|
|
21258
21270
|
}
|
|
21259
21271
|
function _envelopedData(contentBytes, cek, ca, contentType, riNodes, recips) {
|
|
21260
21272
|
var iv = nodeCrypto.randomBytes(16);
|
|
21261
|
-
var enc = pbes2.cbcEncrypt(cek, iv, contentBytes, ca.keyBits);
|
|
21273
|
+
var enc = pbes2.cbcEncrypt(cek, iv, contentBytes, ca.keyBits, CmsError, "cms/bad-input");
|
|
21262
21274
|
var eci = b.sequence([b.oid(O(contentType)), b.sequence([b.oid(O(ca.oid)), b.octetString(iv)]), b.contextPrimitive(0, enc)]);
|
|
21263
21275
|
return b.sequence([b.integer(BigInt(_envelopedVersion(recips, false))), b.setOf(riNodes), eci]);
|
|
21264
21276
|
}
|
|
21277
|
+
function _assertAuthAttrs(pairs, forbidden) {
|
|
21278
|
+
var seenTypes = {};
|
|
21279
|
+
pairs.forEach(function(p) {
|
|
21280
|
+
var node;
|
|
21281
|
+
try {
|
|
21282
|
+
node = asn1.decode(p);
|
|
21283
|
+
} catch (e) {
|
|
21284
|
+
throw _err("cms/bad-input", "an authenticated attribute is not well-formed DER", e);
|
|
21285
|
+
}
|
|
21286
|
+
if (node.tagClass !== "universal" || node.tagNumber !== asn1.TAGS.SEQUENCE || !node.children || node.children.length !== 2 || node.children[1].tagClass !== "universal" || node.children[1].tagNumber !== asn1.TAGS.SET || !node.children[1].children || node.children[1].children.length < 1) {
|
|
21287
|
+
throw _err("cms/bad-input", "an authenticated attribute must be an Attribute SEQUENCE { type, non-empty SET OF value } (RFC 5652)");
|
|
21288
|
+
}
|
|
21289
|
+
var t;
|
|
21290
|
+
try {
|
|
21291
|
+
t = asn1.read.oid(node.children[0]);
|
|
21292
|
+
} catch (e) {
|
|
21293
|
+
throw _err("cms/bad-input", "an authenticated attribute type is not an OBJECT IDENTIFIER", e);
|
|
21294
|
+
}
|
|
21295
|
+
if (guard.intrinsic.hasOwn(seenTypes, t)) throw _err("cms/bad-input", "authenticated attributes must not repeat an attribute type (RFC 5652): " + t);
|
|
21296
|
+
seenTypes[t] = 1;
|
|
21297
|
+
if (forbidden && t === forbidden.oid) throw _err("cms/bad-input", forbidden.why);
|
|
21298
|
+
});
|
|
21299
|
+
}
|
|
21300
|
+
var AUTH_ENVELOPED_FORBIDDEN = {
|
|
21301
|
+
oid: O("messageDigest"),
|
|
21302
|
+
why: "authAttrs must not carry the message-digest attribute in an AuthEnvelopedData: its value is the unencrypted hash of the plaintext, which enables content tracking and confirmation of a guessed plaintext (RFC 5083 sec. 2.1, sec. 5)"
|
|
21303
|
+
};
|
|
21265
21304
|
function _authEnvelopedData(contentBytes, cek, ca, contentType, opts, riNodes, recips) {
|
|
21266
21305
|
var nonce = nodeCrypto.randomBytes(12);
|
|
21267
21306
|
var authAttrsDer = null, aad = Buffer.alloc(0);
|
|
@@ -21269,6 +21308,7 @@ var require_cms_encrypt = __commonJS({
|
|
|
21269
21308
|
throw _err("cms/bad-input", "AuthEnvelopedData with a non-data contentType requires authAttrs (RFC 5083 sec. 2.1)");
|
|
21270
21309
|
}
|
|
21271
21310
|
if (opts.authAttrs && opts.authAttrs.length) {
|
|
21311
|
+
_assertAuthAttrs(opts.authAttrs, AUTH_ENVELOPED_FORBIDDEN);
|
|
21272
21312
|
var setOf = b.setOf(opts.authAttrs);
|
|
21273
21313
|
aad = setOf;
|
|
21274
21314
|
authAttrsDer = b.contextConstructed(1, setOf.subarray(_tlvHeaderLen(setOf)));
|
|
@@ -21294,7 +21334,7 @@ var require_cms_encrypt = __commonJS({
|
|
|
21294
21334
|
} else {
|
|
21295
21335
|
throw _err("cms/bad-input", "EncryptedData needs a single { cek } or { password } descriptor");
|
|
21296
21336
|
}
|
|
21297
|
-
var enc = pbes2.cbcEncrypt(encKey, iv, contentBytes, ca.keyBits);
|
|
21337
|
+
var enc = pbes2.cbcEncrypt(encKey, iv, contentBytes, ca.keyBits, CmsError, "cms/bad-input");
|
|
21298
21338
|
var eci = b.sequence([b.oid(O(contentType)), contentAlgNode, b.contextPrimitive(0, enc)]);
|
|
21299
21339
|
var inner = b.sequence([b.integer(0n), eci]);
|
|
21300
21340
|
return _emit(inner, "encryptedData", opts);
|
|
@@ -21308,7 +21348,7 @@ var require_cms_encrypt = __commonJS({
|
|
|
21308
21348
|
var key = nodeCrypto.pbkdf2Sync(password, salt, iterations, ca.keyBits / 8, pbes2.prfNodeByName(prf, _err, "cms"));
|
|
21309
21349
|
if (pwOwn2.owned) guard.secret.zeroize(password, CmsError, "cms/bad-input", "the password encoding");
|
|
21310
21350
|
try {
|
|
21311
|
-
var enc = pbes2.cbcEncrypt(key, iv, contentBytes, ca.keyBits);
|
|
21351
|
+
var enc = pbes2.cbcEncrypt(key, iv, contentBytes, ca.keyBits, CmsError, "cms/bad-input");
|
|
21312
21352
|
var contentAlg = pbes2.pbes2AlgId(salt, iterations, prf, ca.oid, iv);
|
|
21313
21353
|
var eci = b.sequence([b.oid(O(contentType)), contentAlg, b.contextPrimitive(0, enc)]);
|
|
21314
21354
|
var inner = b.sequence([b.integer(0n), eci]);
|
|
@@ -21320,7 +21360,7 @@ var require_cms_encrypt = __commonJS({
|
|
|
21320
21360
|
function _gcmEncrypt(key, nonce, plaintext, aad, keyBits, tagLen) {
|
|
21321
21361
|
var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-gcm", key, nonce, { authTagLength: tagLen });
|
|
21322
21362
|
if (aad && aad.length) c.setAAD(aad);
|
|
21323
|
-
var ct =
|
|
21363
|
+
var ct = guard.secret.cipherFinish(c, plaintext, CmsError, "cms/bad-input", "a content-encryption intermediate");
|
|
21324
21364
|
return { ct, tag: c.getAuthTag() };
|
|
21325
21365
|
}
|
|
21326
21366
|
function _tlvHeaderLen(der) {
|
|
@@ -21360,26 +21400,7 @@ var require_cms_encrypt = __commonJS({
|
|
|
21360
21400
|
b.sequence([b.oid(O("messageDigest")), b.setOf([b.octetString(mdDigest)])])
|
|
21361
21401
|
];
|
|
21362
21402
|
if (opts.authAttrs && opts.authAttrs.length) pairs = pairs.concat(opts.authAttrs);
|
|
21363
|
-
|
|
21364
|
-
pairs.forEach(function(p) {
|
|
21365
|
-
var node;
|
|
21366
|
-
try {
|
|
21367
|
-
node = asn1.decode(p);
|
|
21368
|
-
} catch (e) {
|
|
21369
|
-
throw _err("cms/bad-input", "an authenticated attribute is not well-formed DER", e);
|
|
21370
|
-
}
|
|
21371
|
-
if (node.tagClass !== "universal" || node.tagNumber !== asn1.TAGS.SEQUENCE || !node.children || node.children.length !== 2 || node.children[1].tagClass !== "universal" || node.children[1].tagNumber !== asn1.TAGS.SET || !node.children[1].children || node.children[1].children.length < 1) {
|
|
21372
|
-
throw _err("cms/bad-input", "an authenticated attribute must be an Attribute SEQUENCE { type, non-empty SET OF value } (RFC 5652)");
|
|
21373
|
-
}
|
|
21374
|
-
var t;
|
|
21375
|
-
try {
|
|
21376
|
-
t = asn1.read.oid(node.children[0]);
|
|
21377
|
-
} catch (e) {
|
|
21378
|
-
throw _err("cms/bad-input", "an authenticated attribute type is not an OBJECT IDENTIFIER", e);
|
|
21379
|
-
}
|
|
21380
|
-
if (seenTypes[t]) throw _err("cms/bad-input", "authenticated attributes must not repeat an attribute type (RFC 5652): " + t);
|
|
21381
|
-
seenTypes[t] = 1;
|
|
21382
|
-
});
|
|
21403
|
+
_assertAuthAttrs(pairs, null);
|
|
21383
21404
|
var setOf = b.setOf(pairs);
|
|
21384
21405
|
preimage = setOf;
|
|
21385
21406
|
authAttrsDer = b.contextConstructed(2, setOf.subarray(_tlvHeaderLen(setOf)));
|
|
@@ -21429,6 +21450,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21429
21450
|
var CmsError = frameworkError.CmsError;
|
|
21430
21451
|
var WRAP_KEK_LENGTHS = schemaCms.WRAP_KEK_LENGTHS;
|
|
21431
21452
|
var KEM_CT_LENGTHS = schemaCms.KEM_CT_LENGTHS;
|
|
21453
|
+
var AEAD_ALGS = schemaCms.AEAD_ALGS;
|
|
21432
21454
|
function O(n) {
|
|
21433
21455
|
return oid.byName(n);
|
|
21434
21456
|
}
|
|
@@ -21724,16 +21746,24 @@ var require_cms_decrypt = __commonJS({
|
|
|
21724
21746
|
}
|
|
21725
21747
|
function _assertContentCipherMode(eci, ct) {
|
|
21726
21748
|
var oidStr = eci.contentEncryptionAlgorithm.oid;
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
if (
|
|
21730
|
-
|
|
21749
|
+
var isAead = guard.intrinsic.hasOwn(AEAD_ALGS, oidStr);
|
|
21750
|
+
if (!isAead && !guard.intrinsic.hasOwn(CONTENT_MODE, oidStr)) return;
|
|
21751
|
+
if (ct === "authEnvelopedData") {
|
|
21752
|
+
if (isAead) return;
|
|
21753
|
+
throw _err("cms/unsupported-algorithm", "contentEncryptionAlgorithm " + oidStr + " is not an authenticated encryption algorithm, which authEnvelopedData requires (RFC 5083 sec. 2)");
|
|
21731
21754
|
}
|
|
21755
|
+
if (!isAead) return;
|
|
21756
|
+
throw _err("cms/unsupported-algorithm", "contentEncryptionAlgorithm " + oidStr + " is an authenticated encryption algorithm, which belongs in an authEnvelopedData rather than a " + ct + " (RFC 5083 sec. 2)");
|
|
21732
21757
|
}
|
|
21733
21758
|
async function _openContent(parsed, eci, cek, ct) {
|
|
21734
21759
|
var alg = eci.contentEncryptionAlgorithm;
|
|
21735
|
-
var keyBits = CONTENT_KEYBITS[alg.oid];
|
|
21736
|
-
if (!keyBits)
|
|
21760
|
+
var keyBits = guard.intrinsic.hasOwn(CONTENT_KEYBITS, alg.oid) ? CONTENT_KEYBITS[alg.oid] : 0;
|
|
21761
|
+
if (!keyBits) {
|
|
21762
|
+
if (guard.intrinsic.hasOwn(AEAD_ALGS, alg.oid) && AEAD_ALGS[alg.oid] === "ccm") {
|
|
21763
|
+
throw _err("cms/unsupported-algorithm", "contentEncryptionAlgorithm " + alg.oid + " is AES-CCM. RFC 5084 sec. 3.1 permits it for this content type; this toolkit implements AES-GCM only for content encryption");
|
|
21764
|
+
}
|
|
21765
|
+
throw _err("cms/unsupported-algorithm", "unsupported contentEncryptionAlgorithm " + alg.oid);
|
|
21766
|
+
}
|
|
21737
21767
|
if (eci.encryptedContent == null) throw _err("cms/no-encrypted-content", "the message has no encryptedContent (detached; supply it out of band)");
|
|
21738
21768
|
var substitute = null;
|
|
21739
21769
|
if (cek == null || cek.length !== keyBits / 8) {
|
|
@@ -21747,7 +21777,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21747
21777
|
}
|
|
21748
21778
|
var iv = asn1.read.octetString(asn1.decode(alg.parameters));
|
|
21749
21779
|
if (iv.length !== 16) throw _fail();
|
|
21750
|
-
return pbes2.cbcDecrypt(cek, iv, eci.encryptedContent, keyBits);
|
|
21780
|
+
return pbes2.cbcDecrypt(cek, iv, eci.encryptedContent, keyBits, CmsError, "cms/decrypt-failed");
|
|
21751
21781
|
} catch (e) {
|
|
21752
21782
|
if (e instanceof CmsError && e.code !== "cms/decrypt-failed") throw e;
|
|
21753
21783
|
throw _fail();
|
|
@@ -21760,7 +21790,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21760
21790
|
var d = nodeCrypto.createDecipheriv("aes-" + keyBits + "-gcm", cek, nonce, { authTagLength: icvLen });
|
|
21761
21791
|
d.setAuthTag(tag);
|
|
21762
21792
|
if (aad && aad.length) d.setAAD(aad);
|
|
21763
|
-
return
|
|
21793
|
+
return guard.secret.cipherFinish(d, ct, CmsError, "cms/decrypt-failed", "the recovered content");
|
|
21764
21794
|
}
|
|
21765
21795
|
async function _decryptEncryptedData(parsed, km, opts) {
|
|
21766
21796
|
var eci = parsed.encryptedContentInfo;
|
|
@@ -21774,7 +21804,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21774
21804
|
if (cek.length !== keyBits / 8) throw _err("cms/bad-input", "the supplied cek length does not match the content algorithm");
|
|
21775
21805
|
var iv = asn1.read.octetString(asn1.decode(alg.parameters));
|
|
21776
21806
|
try {
|
|
21777
|
-
return _originFields({ content: pbes2.cbcDecrypt(cek, iv, eci.encryptedContent, keyBits), contentType: eci.contentType, contentTypeName: oid.name(eci.contentType) || eci.contentType, recipientType: "cek", recipientIndex: -1, contentEncryptionAlgorithm: alg.name || alg.oid, authenticated: false }, null, null);
|
|
21807
|
+
return _originFields({ content: pbes2.cbcDecrypt(cek, iv, eci.encryptedContent, keyBits, CmsError, "cms/decrypt-failed"), contentType: eci.contentType, contentTypeName: oid.name(eci.contentType) || eci.contentType, recipientType: "cek", recipientIndex: -1, contentEncryptionAlgorithm: alg.name || alg.oid, authenticated: false }, null, null);
|
|
21778
21808
|
} catch (_e) {
|
|
21779
21809
|
throw _fail();
|
|
21780
21810
|
}
|
|
@@ -21804,7 +21834,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21804
21834
|
if (pwE.owned) guard.secret.zeroize(pwE.bytes, CmsError, "cms/bad-input", "the password encoding");
|
|
21805
21835
|
}
|
|
21806
21836
|
try {
|
|
21807
|
-
return _originFields({ content: pbes2.cbcDecrypt(key, iv, eci.encryptedContent, keyBits), contentType: eci.contentType, contentTypeName: oid.name(eci.contentType) || eci.contentType, recipientType: "password", recipientIndex: -1, contentEncryptionAlgorithm: oid.name(encOid) || encOid, authenticated: false }, null, null);
|
|
21837
|
+
return _originFields({ content: 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);
|
|
21808
21838
|
} catch (_e) {
|
|
21809
21839
|
throw _fail();
|
|
21810
21840
|
} finally {
|
|
@@ -21841,18 +21871,19 @@ var require_cms_decrypt = __commonJS({
|
|
|
21841
21871
|
var blk = 16, alg = "aes-" + keyBits + "-cbc";
|
|
21842
21872
|
if (wrapped.length < 2 * blk || wrapped.length % blk !== 0) throw _fail();
|
|
21843
21873
|
var n = wrapped.length;
|
|
21844
|
-
var
|
|
21845
|
-
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21874
|
+
var lastDec = null, pass1 = null, body = null;
|
|
21875
|
+
try {
|
|
21876
|
+
var ecb = nodeCrypto.createDecipheriv("aes-" + keyBits + "-ecb", kek, Buffer.alloc(0));
|
|
21877
|
+
ecb.setAutoPadding(false);
|
|
21878
|
+
lastDec = guard.secret.cipherFinish(ecb, wrapped.subarray(n - blk), CmsError, "cms/decrypt-failed", "the recovered CBC last block");
|
|
21879
|
+
var iv2 = Buffer.alloc(blk);
|
|
21880
|
+
for (var i = 0; i < blk; i++) iv2[i] = lastDec[i] ^ wrapped[n - 2 * blk + i];
|
|
21881
|
+
var d1 = nodeCrypto.createDecipheriv(alg, kek, iv2);
|
|
21882
|
+
d1.setAutoPadding(false);
|
|
21883
|
+
pass1 = guard.secret.cipherFinish(d1, wrapped, CmsError, "cms/decrypt-failed", "the PWRI first-pass plaintext");
|
|
21884
|
+
var d2 = nodeCrypto.createDecipheriv(alg, kek, iv);
|
|
21885
|
+
d2.setAutoPadding(false);
|
|
21886
|
+
body = guard.secret.cipherFinish(d2, pass1, CmsError, "cms/decrypt-failed", "the PWRI plaintext block");
|
|
21856
21887
|
var count = body[0];
|
|
21857
21888
|
if (count < 1 || count + 4 > body.length) throw _fail();
|
|
21858
21889
|
var cek = body.subarray(4, 4 + count);
|
|
@@ -21861,7 +21892,7 @@ var require_cms_decrypt = __commonJS({
|
|
|
21861
21892
|
if (bad !== 0) throw _fail();
|
|
21862
21893
|
return Buffer.from(cek);
|
|
21863
21894
|
} finally {
|
|
21864
|
-
guard.secret.zeroizeAll([body, pass1], CmsError, "cms/bad-input", "the PWRI plaintext block");
|
|
21895
|
+
guard.secret.zeroizeAll([body, pass1, lastDec], CmsError, "cms/bad-input", "the PWRI plaintext block");
|
|
21865
21896
|
}
|
|
21866
21897
|
}
|
|
21867
21898
|
function _oaepHashFromParams(paramsBytes) {
|
|
@@ -30341,7 +30372,7 @@ var require_key = __commonJS({
|
|
|
30341
30372
|
if (pwK.owned) guard.secret.zeroize(pwK.bytes, KeyError, "key/bad-input", "the password encoding");
|
|
30342
30373
|
}
|
|
30343
30374
|
try {
|
|
30344
|
-
var ciphertext = pbes2.cbcEncrypt(dk, iv, der, keyBits);
|
|
30375
|
+
var ciphertext = pbes2.cbcEncrypt(dk, iv, der, keyBits, KeyError, "key/bad-input");
|
|
30345
30376
|
var epki = b.sequence([pbes2.pbes2AlgId(salt, iterations, prf, cipherName, iv), b.octetString(ciphertext)]);
|
|
30346
30377
|
pkcs8.parseEncrypted(epki);
|
|
30347
30378
|
return opts.pem ? pkcs8.pemEncode(epki, "ENCRYPTED PRIVATE KEY") : epki;
|
|
@@ -31434,7 +31465,7 @@ var require_pkcs12_build = __commonJS({
|
|
|
31434
31465
|
try {
|
|
31435
31466
|
if (scheme.rc2) return rc2.cbcDecrypt(keyM, scheme.rc2, iv, ct, _err, "pkcs12/decrypt-failed");
|
|
31436
31467
|
var d = nodeCrypto.createDecipheriv(scheme.cipher, keyM, iv);
|
|
31437
|
-
return
|
|
31468
|
+
return guard.secret.cipherFinish(d, ct, Pkcs12Error, "pkcs12/bad-input", "the recovered safe contents");
|
|
31438
31469
|
} catch (_e) {
|
|
31439
31470
|
throw _err("pkcs12/decrypt-failed", "decryption failed");
|
|
31440
31471
|
} finally {
|
|
@@ -32183,7 +32214,7 @@ var require_hpke = __commonJS({
|
|
|
32183
32214
|
var nonce = this._nonce();
|
|
32184
32215
|
var c = nodeCrypto.createCipheriv(aead.cipher, this._key, nonce, { authTagLength: aead.Nt });
|
|
32185
32216
|
if (aad && aad.length) c.setAAD(aad);
|
|
32186
|
-
var body =
|
|
32217
|
+
var body = guard.secret.cipherFinish(c, _buf(pt), HpkeError, "hpke/bad-input", "a seal intermediate");
|
|
32187
32218
|
var ct = concat([body, c.getAuthTag()]);
|
|
32188
32219
|
this._inc();
|
|
32189
32220
|
return ct;
|
|
@@ -32200,7 +32231,7 @@ var require_hpke = __commonJS({
|
|
|
32200
32231
|
d.setAuthTag(ct.subarray(ct.length - aead.Nt));
|
|
32201
32232
|
var pt;
|
|
32202
32233
|
try {
|
|
32203
|
-
pt =
|
|
32234
|
+
pt = guard.secret.cipherFinish(d, ct.subarray(0, ct.length - aead.Nt), HpkeError, "hpke/bad-input", "the recovered plaintext");
|
|
32204
32235
|
} catch (e) {
|
|
32205
32236
|
throw _err("hpke/open-failed", "AEAD authentication failed (RFC 9180 sec. 5.2)", e);
|
|
32206
32237
|
}
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:035db9d2-b000-46ab-bdef-fe4bff353228",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-20T17:21:22.951Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.18.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.18.42",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.18.
|
|
25
|
+
"version": "0.18.42",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.18.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.18.42",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.18.
|
|
57
|
+
"ref": "@blamejs/core@0.18.42",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|