@blamejs/core 0.14.0 → 0.14.2
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 +4 -0
- package/lib/_test/crypto-fixtures.js +3 -3
- package/lib/a2a-tasks.js +18 -18
- package/lib/a2a.js +4 -4
- package/lib/acme.js +3 -3
- package/lib/agent-idempotency.js +1 -1
- package/lib/agent-orchestrator.js +8 -8
- package/lib/agent-posture-chain.js +2 -2
- package/lib/agent-saga.js +1 -1
- package/lib/agent-snapshot.js +1 -1
- package/lib/agent-stream.js +1 -1
- package/lib/agent-tenant.js +1 -1
- package/lib/agent-trace.js +3 -3
- package/lib/ai-capability.js +1 -1
- package/lib/ai-dp.js +4 -4
- package/lib/ai-input.js +3 -3
- package/lib/ai-model-manifest.js +7 -7
- package/lib/ai-pref.js +3 -3
- package/lib/archive-gz.js +2 -2
- package/lib/archive-read.js +25 -25
- package/lib/archive-tar-read.js +2 -2
- package/lib/archive-tar.js +20 -20
- package/lib/archive-wrap.js +10 -10
- package/lib/argon2-builtin.js +1 -1
- package/lib/asn1-der.js +45 -34
- package/lib/atomic-file.js +2 -2
- package/lib/audit-daily-review.js +3 -3
- package/lib/audit-sign.js +5 -5
- package/lib/audit-tools.js +1 -1
- package/lib/audit.js +2 -2
- package/lib/auth/acr-vocabulary.js +2 -2
- package/lib/auth/bot-challenge.js +3 -3
- package/lib/auth/ciba.js +7 -7
- package/lib/auth/dpop.js +3 -3
- package/lib/auth/fido-mds3.js +8 -8
- package/lib/auth/jar.js +11 -0
- package/lib/auth/jwt-external.js +5 -5
- package/lib/auth/oauth.js +7 -9
- package/lib/auth/oid4vci.js +10 -10
- package/lib/auth/oid4vp.js +2 -2
- package/lib/auth/openid-federation.js +2 -2
- package/lib/auth/passkey.js +3 -3
- package/lib/auth/saml.js +29 -25
- package/lib/auth/sd-jwt-vc-disclosure.js +1 -1
- package/lib/auth/sd-jwt-vc.js +4 -4
- package/lib/auth/status-list.js +10 -10
- package/lib/auth/step-up.js +1 -1
- package/lib/auth-bot-challenge.js +1 -1
- package/lib/backup/index.js +7 -7
- package/lib/base32.js +8 -8
- package/lib/budr.js +2 -2
- package/lib/cache-status.js +2 -2
- package/lib/calendar.js +23 -23
- package/lib/cbor.js +12 -12
- package/lib/cdn-cache-control.js +1 -1
- package/lib/cert.js +5 -5
- package/lib/cloud-events.js +5 -5
- package/lib/cms-codec.js +21 -21
- package/lib/codepoint-class.js +12 -12
- package/lib/compliance-sanctions-fuzzy.js +4 -4
- package/lib/compliance-sanctions.js +4 -4
- package/lib/compliance.js +29 -29
- package/lib/content-credentials.js +36 -36
- package/lib/cookies.js +1 -1
- package/lib/cose.js +13 -13
- package/lib/cra-report.js +1 -1
- package/lib/crdt.js +1 -1
- package/lib/crypto-field.js +2 -2
- package/lib/crypto-xwing.js +7 -7
- package/lib/crypto.js +6 -6
- package/lib/csp.js +2 -2
- package/lib/cwt.js +4 -4
- package/lib/dark-patterns.js +2 -2
- package/lib/data-act.js +2 -2
- package/lib/db-file-lifecycle.js +4 -4
- package/lib/db-query.js +1 -1
- package/lib/db.js +6 -6
- package/lib/dbsc.js +13 -13
- package/lib/did.js +17 -17
- package/lib/dora.js +4 -4
- package/lib/dsr.js +1 -1
- package/lib/early-hints.js +2 -2
- package/lib/eat.js +4 -4
- package/lib/external-db-migrate.js +1 -1
- package/lib/external-db.js +1 -1
- package/lib/flag-cache.js +1 -1
- package/lib/flag-evaluation-context.js +2 -2
- package/lib/graphql-federation.js +4 -4
- package/lib/guard-agent-registry.js +5 -5
- package/lib/guard-archive.js +24 -24
- package/lib/guard-cidr.js +33 -33
- package/lib/guard-csv.js +1 -1
- package/lib/guard-domain.js +10 -10
- package/lib/guard-dsn.js +4 -4
- package/lib/guard-email.js +19 -19
- package/lib/guard-event-bus-payload.js +4 -4
- package/lib/guard-event-bus-topic.js +6 -6
- package/lib/guard-filename.js +7 -7
- package/lib/guard-graphql.js +9 -9
- package/lib/guard-html-wcag-tagwalk.js +1 -1
- package/lib/guard-html-wcag.js +4 -4
- package/lib/guard-html.js +7 -7
- package/lib/guard-idempotency-key.js +6 -6
- package/lib/guard-image.js +4 -4
- package/lib/guard-imap-command.js +17 -17
- package/lib/guard-jmap.js +20 -20
- package/lib/guard-json.js +12 -12
- package/lib/guard-jsonpath.js +3 -3
- package/lib/guard-jwt.js +4 -4
- package/lib/guard-list-id.js +7 -7
- package/lib/guard-list-unsubscribe.js +8 -8
- package/lib/guard-mail-compose.js +4 -4
- package/lib/guard-mail-move.js +5 -5
- package/lib/guard-mail-query.js +3 -3
- package/lib/guard-mail-reply.js +3 -3
- package/lib/guard-mail-sieve.js +6 -6
- package/lib/guard-managesieve-command.js +25 -25
- package/lib/guard-markdown.js +31 -31
- package/lib/guard-message-id.js +5 -5
- package/lib/guard-mime.js +1 -1
- package/lib/guard-oauth.js +3 -3
- package/lib/guard-pdf.js +6 -6
- package/lib/guard-pop3-command.js +11 -11
- package/lib/guard-posture-chain.js +5 -5
- package/lib/guard-regex.js +10 -10
- package/lib/guard-saga-config.js +5 -5
- package/lib/guard-smtp-command.js +6 -6
- package/lib/guard-snapshot-envelope.js +3 -3
- package/lib/guard-stream-args.js +4 -4
- package/lib/guard-svg.js +11 -11
- package/lib/guard-tenant-id.js +5 -5
- package/lib/guard-time.js +15 -15
- package/lib/guard-trace-context.js +4 -4
- package/lib/guard-uuid.js +11 -11
- package/lib/guard-xml.js +12 -12
- package/lib/guard-yaml.js +16 -16
- package/lib/honeytoken.js +5 -5
- package/lib/http-client.js +1 -1
- package/lib/http-message-signature.js +2 -2
- package/lib/iab-mspa.js +3 -3
- package/lib/iab-tcf.js +70 -70
- package/lib/inbox.js +4 -4
- package/lib/ip-utils.js +15 -15
- package/lib/jose-jwe-experimental.js +2 -2
- package/lib/json-path.js +3 -3
- package/lib/json-schema.js +1 -1
- package/lib/jsonapi.js +3 -3
- package/lib/jtd.js +2 -2
- package/lib/link-header.js +1 -1
- package/lib/local-db-thin.js +1 -1
- package/lib/log.js +1 -1
- package/lib/lro.js +4 -4
- package/lib/mail-agent.js +1 -1
- package/lib/mail-arc-sign.js +6 -6
- package/lib/mail-auth.js +43 -43
- package/lib/mail-bimi.js +3 -3
- package/lib/mail-crypto-pgp.js +53 -45
- package/lib/mail-crypto-smime.js +5 -5
- package/lib/mail-dav.js +1 -1
- package/lib/mail-deploy.js +39 -39
- package/lib/mail-dkim.js +11 -11
- package/lib/mail-greylist.js +12 -12
- package/lib/mail-helo.js +1 -1
- package/lib/mail-journal.js +8 -8
- package/lib/mail-rbl.js +7 -7
- package/lib/mail-scan.js +7 -7
- package/lib/mail-send-deliver.js +2 -2
- package/lib/mail-server-imap.js +12 -12
- package/lib/mail-server-jmap.js +16 -16
- package/lib/mail-server-managesieve.js +4 -4
- package/lib/mail-server-mx.js +17 -17
- package/lib/mail-server-pop3.js +4 -4
- package/lib/mail-server-rate-limit.js +2 -2
- package/lib/mail-server-submission.js +21 -21
- package/lib/mail-sieve.js +2 -2
- package/lib/mail-spam-score.js +5 -5
- package/lib/mail-srs.js +12 -12
- package/lib/mail-store-fts.js +2 -2
- package/lib/mail-store.js +8 -8
- package/lib/mail-unsubscribe.js +4 -4
- package/lib/mail.js +4 -4
- package/lib/mcp-tool-registry.js +4 -4
- package/lib/mcp.js +8 -8
- package/lib/mdoc.js +2 -2
- package/lib/metrics.js +8 -8
- package/lib/middleware/age-gate.js +1 -1
- package/lib/middleware/api-encrypt.js +7 -7
- package/lib/middleware/assetlinks.js +2 -2
- package/lib/middleware/asyncapi-serve.js +2 -2
- package/lib/middleware/bearer-auth.js +5 -5
- package/lib/middleware/body-parser.js +5 -5
- package/lib/middleware/compose-pipeline.js +15 -15
- package/lib/middleware/csp-report.js +4 -4
- package/lib/middleware/daily-byte-quota.js +1 -1
- package/lib/middleware/dpop.js +1 -1
- package/lib/middleware/headers.js +2 -2
- package/lib/middleware/host-allowlist.js +1 -1
- package/lib/middleware/idempotency-key.js +12 -12
- package/lib/middleware/nel.js +1 -1
- package/lib/middleware/openapi-serve.js +2 -2
- package/lib/middleware/protected-resource-metadata.js +2 -2
- package/lib/middleware/require-aal.js +1 -1
- package/lib/middleware/require-bound-key.js +2 -2
- package/lib/middleware/require-content-type.js +1 -1
- package/lib/middleware/require-methods.js +1 -1
- package/lib/middleware/require-step-up.js +2 -2
- package/lib/middleware/scim-server.js +1 -1
- package/lib/middleware/security-txt.js +3 -3
- package/lib/middleware/tus-upload.js +12 -12
- package/lib/middleware/web-app-manifest.js +2 -2
- package/lib/network-byte-quota.js +1 -1
- package/lib/network-dns-resolver.js +23 -23
- package/lib/network-dns.js +29 -29
- package/lib/network-dnssec.js +33 -33
- package/lib/network-smtp-policy.js +10 -10
- package/lib/network-tls.js +99 -94
- package/lib/network-tsig.js +33 -33
- package/lib/nis2-report.js +1 -1
- package/lib/ntp-check.js +3 -3
- package/lib/observability-otlp-exporter.js +17 -17
- package/lib/observability-tracer.js +6 -6
- package/lib/observability.js +8 -8
- package/lib/openapi-yaml.js +1 -1
- package/lib/openapi.js +1 -1
- package/lib/outbox.js +6 -6
- package/lib/pqc-agent.js +4 -4
- package/lib/pqc-software.js +1 -1
- package/lib/privacy-pass.js +5 -5
- package/lib/problem-details.js +5 -5
- package/lib/promise-pool.js +1 -1
- package/lib/protobuf-encoder.js +9 -1
- package/lib/queue.js +4 -2
- package/lib/redact.js +2 -2
- package/lib/request-helpers.js +1 -1
- package/lib/router.js +10 -10
- package/lib/safe-async.js +2 -2
- package/lib/safe-dns.js +71 -71
- package/lib/safe-ical.js +19 -19
- package/lib/safe-icap.js +24 -24
- package/lib/safe-jsonpath.js +2 -2
- package/lib/safe-mime.js +10 -10
- package/lib/safe-mount-info.js +3 -3
- package/lib/safe-redirect.js +1 -1
- package/lib/safe-sieve.js +23 -23
- package/lib/safe-smtp.js +1 -1
- package/lib/safe-vcard.js +14 -14
- package/lib/sandbox.js +5 -5
- package/lib/sec-cyber.js +1 -1
- package/lib/self-update-standalone-verifier.js +3 -3
- package/lib/self-update.js +3 -3
- package/lib/server-timing.js +3 -3
- package/lib/session-device-binding.js +7 -7
- package/lib/session.js +8 -8
- package/lib/standard-webhooks.js +4 -4
- package/lib/storage.js +2 -2
- package/lib/stream-throttle.js +1 -1
- package/lib/structured-fields.js +15 -15
- package/lib/subject.js +1 -1
- package/lib/tcpa-10dlc.js +1 -1
- package/lib/tenant-quota.js +3 -3
- package/lib/test-harness.js +1 -1
- package/lib/tracing.js +1 -1
- package/lib/tsa.js +5 -5
- package/lib/uri-template.js +5 -5
- package/lib/vault/index.js +2 -2
- package/lib/vault/seal-pem-file.js +4 -4
- package/lib/vc.js +2 -2
- package/lib/vendor-data.js +1 -1
- package/lib/watcher.js +4 -4
- package/lib/web-push-vapid.js +21 -21
- package/lib/webhook.js +2 -2
- package/lib/websocket.js +3 -3
- package/lib/worker-pool.js +3 -3
- package/lib/ws-client.js +24 -24
- package/lib/xml-c14n.js +2 -2
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -87,7 +87,7 @@ var BUILTIN_RANKS = {
|
|
|
87
87
|
"ial2": 30,
|
|
88
88
|
"fal2": 30,
|
|
89
89
|
"aal2": 35,
|
|
90
|
-
"urn:mace:incommon:iap:silver": 32, //
|
|
90
|
+
"urn:mace:incommon:iap:silver": 32, // ACR rank, not bytes
|
|
91
91
|
|
|
92
92
|
// Phishing-resistant multi-factor (passkey UV)
|
|
93
93
|
"phrh": 60, // allow:raw-time-literal — ACR rank, not seconds
|
|
@@ -98,7 +98,7 @@ var BUILTIN_RANKS = {
|
|
|
98
98
|
"ial3": 75,
|
|
99
99
|
"fal3": 75,
|
|
100
100
|
"aal3": 75,
|
|
101
|
-
"urn:mace:incommon:iap:gold": 80, //
|
|
101
|
+
"urn:mace:incommon:iap:gold": 80, // ACR rank, not bytes
|
|
102
102
|
|
|
103
103
|
// In-person identity-proofed + hardware-bound
|
|
104
104
|
"loa4": 95,
|
|
@@ -97,7 +97,7 @@ var MAX_TOKEN_BYTES = C.BYTES.kib(4);
|
|
|
97
97
|
// headroom; operators can override per-call but cannot drop below
|
|
98
98
|
// MIN_TIMEOUT_MS without the create() factory refusing the opts.
|
|
99
99
|
var DEFAULT_TIMEOUT_MS = C.TIME.seconds(5);
|
|
100
|
-
var MIN_TIMEOUT_MS = 500; // anti-misconfiguration floor //
|
|
100
|
+
var MIN_TIMEOUT_MS = 500; // anti-misconfiguration floor // 500ms wall-clock floor, not a byte literal
|
|
101
101
|
|
|
102
102
|
// Response-body cap. Provider siteverify responses are small JSON
|
|
103
103
|
// (well under 4 KiB); a multi-MiB response is either a redirect to
|
|
@@ -116,7 +116,7 @@ var EXPECTED_CONTENT_TYPE_PREFIX = "application/json";
|
|
|
116
116
|
// the surfaced bytes are not the secret token (≈ 48 bits visible vs.
|
|
117
117
|
// ~2 KiB total), but large enough to cluster verifications belonging
|
|
118
118
|
// to the same widget render in a debug session.
|
|
119
|
-
var TOKEN_PREFIX_AUDIT_CHARS = 8; //
|
|
119
|
+
var TOKEN_PREFIX_AUDIT_CHARS = 8; // debug-prefix length, not a byte literal
|
|
120
120
|
|
|
121
121
|
// ---- provider catalog ----
|
|
122
122
|
//
|
|
@@ -440,7 +440,7 @@ function create(opts) {
|
|
|
440
440
|
"siteverify transport failure: " + ((e && e.message) || String(e)));
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
if (res.statusCode < 200 || res.statusCode >= 300) { //
|
|
443
|
+
if (res.statusCode < 200 || res.statusCode >= 300) { // HTTP 2xx range bounds
|
|
444
444
|
_safeAudit(safeEmit, "auth.bot_challenge.verify", "failure", {
|
|
445
445
|
provider: providerKey, ok: false, reason: "non-2xx",
|
|
446
446
|
statusCode: res.statusCode, prefix: tokenPrefix,
|
package/lib/auth/ciba.js
CHANGED
|
@@ -174,7 +174,7 @@ function create(opts) {
|
|
|
174
174
|
// 2026-05-11). CIBA §7.1.2 requires the token be opaque + hard to
|
|
175
175
|
// guess; the framework's other token-shaped primitives enforce 32
|
|
176
176
|
// chars minimum. A 4-char token was previously accepted; refuse.
|
|
177
|
-
if (clientNotificationToken !== null && clientNotificationToken.length < 32) { //
|
|
177
|
+
if (clientNotificationToken !== null && clientNotificationToken.length < 32) { // RFC 9700 §7.1.2 token char-length minimum, not bytes
|
|
178
178
|
throw new AuthError("auth-ciba/notification-token-too-short",
|
|
179
179
|
"auth.ciba.client.create: clientNotificationToken must be >= 32 chars " +
|
|
180
180
|
"(generate via b.crypto.generateToken(32) or stronger; CIBA §7.1.2 " +
|
|
@@ -239,7 +239,7 @@ function create(opts) {
|
|
|
239
239
|
(cc >= 0x200b && cc <= 0x200f) ||
|
|
240
240
|
(cc >= 0x202a && cc <= 0x202e) ||
|
|
241
241
|
(cc >= 0x2066 && cc <= 0x2069) ||
|
|
242
|
-
cc === 0xfeff) { //
|
|
242
|
+
cc === 0xfeff) { // codepoint constants for control / bidi / zero-width / BOM
|
|
243
243
|
throw new AuthError("auth-ciba/binding-message-control-chars",
|
|
244
244
|
"ciba: bindingMessage contains control / bidi / zero-width characters");
|
|
245
245
|
}
|
|
@@ -278,7 +278,7 @@ function create(opts) {
|
|
|
278
278
|
var err;
|
|
279
279
|
try { err = safeJson.parse(bodyText, { maxBytes: MAX_RESPONSE_BYTES }); } catch (_e) { /* silent-catch: non-JSON IdP error body falls through to the bodyText snippet path below */ }
|
|
280
280
|
var code = (err && err.error) || ("http-" + res.statusCode);
|
|
281
|
-
var msg = (err && (err.error_description || err.error)) || bodyText.slice(0, 200); //
|
|
281
|
+
var msg = (err && (err.error_description || err.error)) || bodyText.slice(0, 200); // error-message snippet length
|
|
282
282
|
var aerr = new AuthError("auth-ciba/" + code, "ciba: " + msg);
|
|
283
283
|
aerr.cibaError = err || null;
|
|
284
284
|
aerr.statusCode = res.statusCode;
|
|
@@ -355,8 +355,8 @@ function create(opts) {
|
|
|
355
355
|
if (clientAuth === "jwt") {
|
|
356
356
|
var assertion = await opts.clientAssertionSigner({
|
|
357
357
|
iss: opts.clientId, sub: opts.clientId, aud: endpoint,
|
|
358
|
-
iat: Math.floor(Date.now() / 1000), //
|
|
359
|
-
exp: Math.floor(Date.now() / 1000) + 300, //
|
|
358
|
+
iat: Math.floor(Date.now() / 1000), // ms→s
|
|
359
|
+
exp: Math.floor(Date.now() / 1000) + 300, // assertion 5m TTL
|
|
360
360
|
jti: generateToken(16),
|
|
361
361
|
});
|
|
362
362
|
body.set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
|
|
@@ -465,8 +465,8 @@ function create(opts) {
|
|
|
465
465
|
if (clientAuth === "jwt") {
|
|
466
466
|
var assertion = await opts.clientAssertionSigner({
|
|
467
467
|
iss: opts.clientId, sub: opts.clientId, aud: endpoint,
|
|
468
|
-
iat: Math.floor(Date.now() / 1000), //
|
|
469
|
-
exp: Math.floor(Date.now() / 1000) + 300, //
|
|
468
|
+
iat: Math.floor(Date.now() / 1000), // ms→s
|
|
469
|
+
exp: Math.floor(Date.now() / 1000) + 300, // assertion 5m TTL
|
|
470
470
|
jti: generateToken(16),
|
|
471
471
|
});
|
|
472
472
|
body.set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
|
package/lib/auth/dpop.js
CHANGED
|
@@ -131,9 +131,9 @@ function _signParamsForAlg(alg) {
|
|
|
131
131
|
if (alg === "RS256") return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
132
132
|
if (alg === "RS384") return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
133
133
|
if (alg === "RS512") return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
134
|
-
if (alg === "PS256") return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 }; //
|
|
135
|
-
if (alg === "PS384") return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 48 }; //
|
|
136
|
-
if (alg === "PS512") return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 }; //
|
|
134
|
+
if (alg === "PS256") return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 }; // RFC 7518 PS256 salt length
|
|
135
|
+
if (alg === "PS384") return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 48 }; // RFC 7518 PS384 salt length
|
|
136
|
+
if (alg === "PS512") return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 }; // RFC 7518 PS512 salt length
|
|
137
137
|
if (alg === "ES256") return { hash: "sha256", dsaEncoding: "ieee-p1363" };
|
|
138
138
|
if (alg === "ES384") return { hash: "sha384", dsaEncoding: "ieee-p1363" };
|
|
139
139
|
if (alg === "ES512") return { hash: "sha512", dsaEncoding: "ieee-p1363" };
|
package/lib/auth/fido-mds3.js
CHANGED
|
@@ -97,7 +97,7 @@ function _b64urlDecode(s) {
|
|
|
97
97
|
// node:crypto.X509Certificate accepts it.
|
|
98
98
|
function _derToPem(b64) {
|
|
99
99
|
var lines = [];
|
|
100
|
-
for (var i = 0; i < b64.length; i += 64) lines.push(b64.slice(i, i + 64)); //
|
|
100
|
+
for (var i = 0; i < b64.length; i += 64) lines.push(b64.slice(i, i + 64)); // RFC 7468 PEM line width
|
|
101
101
|
return "-----BEGIN CERTIFICATE-----\n" + lines.join("\n") +
|
|
102
102
|
"\n-----END CERTIFICATE-----\n";
|
|
103
103
|
}
|
|
@@ -145,9 +145,9 @@ function _verifyParamsForAlg(alg) {
|
|
|
145
145
|
case "RS256": return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
146
146
|
case "RS384": return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
147
147
|
case "RS512": return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PADDING };
|
|
148
|
-
case "PS256": return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 }; //
|
|
149
|
-
case "PS384": return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 48 }; //
|
|
150
|
-
case "PS512": return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 }; //
|
|
148
|
+
case "PS256": return { hash: "sha256", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 }; // SHA-256 hash length
|
|
149
|
+
case "PS384": return { hash: "sha384", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 48 }; // SHA-384 hash length
|
|
150
|
+
case "PS512": return { hash: "sha512", padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 64 }; // SHA-512 hash length
|
|
151
151
|
case "ES256": return { hash: "sha256", dsaEncoding: "ieee-p1363" };
|
|
152
152
|
case "ES384": return { hash: "sha384", dsaEncoding: "ieee-p1363" };
|
|
153
153
|
case "ES512": return { hash: "sha512", dsaEncoding: "ieee-p1363" };
|
|
@@ -292,7 +292,7 @@ function _getCache() {
|
|
|
292
292
|
_sharedCache = cache().create({
|
|
293
293
|
namespace: "auth-fido-mds3.blob",
|
|
294
294
|
ttlMs: MAX_CACHE_TTL_MS,
|
|
295
|
-
maxEntries: 8, //
|
|
295
|
+
maxEntries: 8, // operator-pinned URL set
|
|
296
296
|
});
|
|
297
297
|
return _sharedCache;
|
|
298
298
|
}
|
|
@@ -315,7 +315,7 @@ function _ttlFromNextUpdate(nextUpdateDate) {
|
|
|
315
315
|
// valid future timestamp and influence the cache-TTL clamp downstream.
|
|
316
316
|
function _parseNextUpdate(s) {
|
|
317
317
|
if (typeof s !== "string") return null;
|
|
318
|
-
var m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/); //
|
|
318
|
+
var m = s.match(/^(\d{4})-(\d{2})-(\d{2})$/); // ISO-8601 date components
|
|
319
319
|
if (!m) return null;
|
|
320
320
|
var year = parseInt(m[1], 10);
|
|
321
321
|
var month = parseInt(m[2], 10) - 1;
|
|
@@ -464,7 +464,7 @@ async function fetch(opts) { // allow:raw-outbound-http — function name is f
|
|
|
464
464
|
throw new FidoMds3Error("fido-mds3/network",
|
|
465
465
|
"BLOB GET " + url + " failed: " + ((e && e.message) || String(e)));
|
|
466
466
|
}
|
|
467
|
-
if (rsp.statusCode < 200 || rsp.statusCode >= 300) { //
|
|
467
|
+
if (rsp.statusCode < 200 || rsp.statusCode >= 300) { // HTTP 2xx range
|
|
468
468
|
throw new FidoMds3Error("fido-mds3/bad-status",
|
|
469
469
|
"BLOB GET " + url + " returned " + rsp.statusCode);
|
|
470
470
|
}
|
|
@@ -539,7 +539,7 @@ function lookupAaguid(blob, aaguid) {
|
|
|
539
539
|
throw new FidoMds3Error("fido-mds3/bad-aaguid", "aaguid must be a non-empty string");
|
|
540
540
|
}
|
|
541
541
|
var canon = aaguid.replace(/-/g, "").toLowerCase();
|
|
542
|
-
if (!safeBuffer.isHex(canon, 32)) { //
|
|
542
|
+
if (!safeBuffer.isHex(canon, 32)) { // 32 = AAGUID hex-char count, not bytes
|
|
543
543
|
throw new FidoMds3Error("fido-mds3/bad-aaguid",
|
|
544
544
|
"aaguid must be a UUID (with or without dashes)");
|
|
545
545
|
}
|
package/lib/auth/jar.js
CHANGED
|
@@ -130,6 +130,17 @@ async function parse(jar, opts) {
|
|
|
130
130
|
audience: opts.audience,
|
|
131
131
|
clockSkewMs: opts.clockSkewMs,
|
|
132
132
|
});
|
|
133
|
+
// RFC 9101 §10.8 — the request object MUST be explicitly typed so a JWT
|
|
134
|
+
// minted for another purpose (id_token / access-token / logout-token)
|
|
135
|
+
// and signed by the same client key cannot be replayed here as a request
|
|
136
|
+
// object (cross-JWT confusion). Require the registered media type, with or
|
|
137
|
+
// without the "application/" prefix; an absent or mismatched typ is refused.
|
|
138
|
+
var jarTyp = verified.header && verified.header.typ;
|
|
139
|
+
if (jarTyp !== JAR_TYP && jarTyp !== "application/" + JAR_TYP) {
|
|
140
|
+
throw new AuthJarError("auth-jar/bad-typ",
|
|
141
|
+
"jar.parse: request object header.typ must be \"" + JAR_TYP +
|
|
142
|
+
"\" (RFC 9101 §10.8 — cross-JWT-confusion defense)");
|
|
143
|
+
}
|
|
133
144
|
var payload = verified.claims;
|
|
134
145
|
|
|
135
146
|
// RFC 9101 §5.2 — the request object MUST carry a client_id claim,
|
package/lib/auth/jwt-external.js
CHANGED
|
@@ -75,9 +75,9 @@ var MAX_TOKEN_BYTES = C.BYTES.kib(16);
|
|
|
75
75
|
var REFUSED_ALGS = ["HS256", "HS384", "HS512", "none"];
|
|
76
76
|
|
|
77
77
|
// PSS salt lengths per RFC 7518 §3.5.
|
|
78
|
-
var PSS_SALT_SHA256 = 32; //
|
|
79
|
-
var PSS_SALT_SHA384 = 48; //
|
|
80
|
-
var PSS_SALT_SHA512 = 64; //
|
|
78
|
+
var PSS_SALT_SHA256 = 32; // RFC 7518 SHA-256 salt length
|
|
79
|
+
var PSS_SALT_SHA384 = 48; // RFC 7518 SHA-384 salt length
|
|
80
|
+
var PSS_SALT_SHA512 = 64; // RFC 7518 SHA-512 salt length
|
|
81
81
|
|
|
82
82
|
var SUPPORTED_CLASSICAL_ALGS = [
|
|
83
83
|
"RS256", "RS384", "RS512",
|
|
@@ -105,7 +105,7 @@ function _b64urlDecode(s) {
|
|
|
105
105
|
throw new AuthError("auth-jwt-external/bad-base64", "expected base64url string");
|
|
106
106
|
}
|
|
107
107
|
var padded = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
108
|
-
while (padded.length % 4) padded += "="; //
|
|
108
|
+
while (padded.length % 4) padded += "="; // base64 quartet padding
|
|
109
109
|
return Buffer.from(padded, "base64");
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -241,7 +241,7 @@ async function _fetchJwks(uri, cacheMs) {
|
|
|
241
241
|
maxBytes: MAX_JWKS_BYTES,
|
|
242
242
|
timeoutMs: C.TIME.seconds(10),
|
|
243
243
|
});
|
|
244
|
-
if (res.statusCode < 200 || res.statusCode >= 300) { //
|
|
244
|
+
if (res.statusCode < 200 || res.statusCode >= 300) { // HTTP 2xx range
|
|
245
245
|
throw new AuthError("auth-jwt-external/jwks-fetch-failed",
|
|
246
246
|
"JWKS endpoint " + uri + " returned " + res.statusCode);
|
|
247
247
|
}
|
package/lib/auth/oauth.js
CHANGED
|
@@ -836,10 +836,10 @@ function create(opts) {
|
|
|
836
836
|
// only in claim validation (no nonce, audience = clientId, no
|
|
837
837
|
// ID-token-specific claims). We wrap verifyIdToken with the
|
|
838
838
|
// skip-nonce flag and apply JARM-specific claim checks below.
|
|
839
|
+
// verifyIdToken applies the create()-level accepted algorithms / JWKS /
|
|
840
|
+
// clock-skew; only the JARM-specific skip-nonce flag is passed here.
|
|
839
841
|
var verified = await verifyIdToken(responseJwt, {
|
|
840
842
|
skipNonceCheck: true,
|
|
841
|
-
acceptedAlgs: jopts.acceptedAlgs,
|
|
842
|
-
maxClockSkewMs: jopts.maxClockSkewMs,
|
|
843
843
|
});
|
|
844
844
|
var c = verified.claims;
|
|
845
845
|
// Per JARM §4: `iss` MUST match the OP issuer; `aud` MUST contain
|
|
@@ -1297,7 +1297,7 @@ function create(opts) {
|
|
|
1297
1297
|
if (!rv || typeof rv.request_uri !== "string" || rv.request_uri.length === 0) {
|
|
1298
1298
|
throw new OAuthError("auth-oauth/par-bad-response",
|
|
1299
1299
|
"pushAuthorizationRequest: IdP did not return a request_uri (got " +
|
|
1300
|
-
JSON.stringify(rv).slice(0, 200) + ")"); //
|
|
1300
|
+
JSON.stringify(rv).slice(0, 200) + ")"); // error-message snippet length
|
|
1301
1301
|
}
|
|
1302
1302
|
// Build the browser-side redirect URL: /authorize?client_id=...&request_uri=...
|
|
1303
1303
|
var authzEndpoint = await _resolveEndpoint("authorizationEndpoint");
|
|
@@ -1419,12 +1419,10 @@ function create(opts) {
|
|
|
1419
1419
|
}
|
|
1420
1420
|
// Reuse verifyIdToken's signature-verification path. It looks up
|
|
1421
1421
|
// the IdP JWKS and checks the JWS — same trust anchor.
|
|
1422
|
+
// verifyIdToken applies the create()-level issuer / clientId / accepted
|
|
1423
|
+
// algorithms / JWKS / clock-skew — the same trust anchor as id_tokens.
|
|
1424
|
+
// Only the per-call logout-token semantics are passed here.
|
|
1422
1425
|
var verified = await verifyIdToken(logoutToken, {
|
|
1423
|
-
issuer: issuer,
|
|
1424
|
-
clientId: clientId,
|
|
1425
|
-
acceptedAlgs: vopts.acceptedAlgs,
|
|
1426
|
-
jwksUri: vopts.jwksUri,
|
|
1427
|
-
maxClockSkewMs: vopts.maxClockSkewMs,
|
|
1428
1426
|
// Logout tokens have no nonce — disable the nonce check that
|
|
1429
1427
|
// verifyIdToken would otherwise enforce on id_tokens.
|
|
1430
1428
|
skipNonceCheck: true,
|
|
@@ -1953,7 +1951,7 @@ function create(opts) {
|
|
|
1953
1951
|
}
|
|
1954
1952
|
// Terminal errors.
|
|
1955
1953
|
throw new OAuthError("auth-oauth/device-" + (err || "unknown"),
|
|
1956
|
-
"pollDeviceCode: " + (parsed && parsed.error_description ? parsed.error_description : text.slice(0, 200))); //
|
|
1954
|
+
"pollDeviceCode: " + (parsed && parsed.error_description ? parsed.error_description : text.slice(0, 200))); // 200-char error-snippet cap, not bytes
|
|
1957
1955
|
}
|
|
1958
1956
|
throw new OAuthError("auth-oauth/device-poll-timeout",
|
|
1959
1957
|
"pollDeviceCode: exceeded maxWaitMs " + (popts.maxWaitMs || C.TIME.minutes(10)));
|
package/lib/auth/oid4vci.js
CHANGED
|
@@ -98,7 +98,7 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
|
|
|
98
98
|
}
|
|
99
99
|
var header, payload;
|
|
100
100
|
try {
|
|
101
|
-
header = safeJson.parse(_b64uDecodeStr(parts[0]), { maxBytes: 4096 }); //
|
|
101
|
+
header = safeJson.parse(_b64uDecodeStr(parts[0]), { maxBytes: 4096 }); // proof header cap
|
|
102
102
|
payload = safeJson.parse(_b64uDecodeStr(parts[1]), { maxBytes: MAX_PROOF_BYTES });
|
|
103
103
|
} catch (e) {
|
|
104
104
|
throw new AuthError("auth-oid4vci/bad-proof-decode",
|
|
@@ -240,7 +240,7 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
|
|
|
240
240
|
* tokenEndpoint: string, // public URL for /token (re-used by the pre-auth flow)
|
|
241
241
|
* sdJwtIssuer: <b.auth.sdJwtVc.issuer instance>, // mints the SD-JWT VC
|
|
242
242
|
* supportedCredentials: { [id]: { format, vct, claims, ... } },
|
|
243
|
-
* proofAlgorithms: string[], // default ["ES256", "ES384"]
|
|
243
|
+
* proofAlgorithms: string[], // default ["ES256", "ES384", "EdDSA"]
|
|
244
244
|
* preAuthCodeTtlMs?: number, // default 5m
|
|
245
245
|
* accessTokenTtlMs?: number, // default 15m
|
|
246
246
|
* cNonceTtlMs?: number, // default 5m
|
|
@@ -367,7 +367,7 @@ function create(opts) {
|
|
|
367
367
|
"createCredentialOffer: credentialId \"" + id + "\" not in supportedCredentials");
|
|
368
368
|
}
|
|
369
369
|
});
|
|
370
|
-
var preAuthCode = generateToken(32); //
|
|
370
|
+
var preAuthCode = generateToken(32); // 256-bit single-use pre-auth code
|
|
371
371
|
var txCode = coOpts.txCode || null;
|
|
372
372
|
if (txCode !== null) {
|
|
373
373
|
if (typeof txCode !== "object" || typeof txCode.value !== "string") {
|
|
@@ -388,7 +388,7 @@ function create(opts) {
|
|
|
388
388
|
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
|
|
389
389
|
"pre-authorized_code": preAuthCode,
|
|
390
390
|
tx_code: txCode ? {
|
|
391
|
-
length: typeof txCode.length === "number" ? txCode.length : 4, //
|
|
391
|
+
length: typeof txCode.length === "number" ? txCode.length : 4, // default tx-code 4 digits
|
|
392
392
|
input_mode: txCode.input_mode || "numeric",
|
|
393
393
|
description: txCode.description || undefined,
|
|
394
394
|
} : undefined,
|
|
@@ -467,8 +467,8 @@ function create(opts) {
|
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
469
|
await codeStore.delete(eopts.preAuthCode);
|
|
470
|
-
var accessToken = generateToken(32); //
|
|
471
|
-
var cNonce = generateToken(16); //
|
|
470
|
+
var accessToken = generateToken(32); // 256-bit access token
|
|
471
|
+
var cNonce = generateToken(16); // 128-bit c_nonce
|
|
472
472
|
var record = {
|
|
473
473
|
subject: entry.subject,
|
|
474
474
|
credentialIds: entry.credentialIds,
|
|
@@ -485,9 +485,9 @@ function create(opts) {
|
|
|
485
485
|
return {
|
|
486
486
|
access_token: accessToken,
|
|
487
487
|
token_type: "Bearer",
|
|
488
|
-
expires_in: Math.floor(accessTokenTtl / 1000), //
|
|
488
|
+
expires_in: Math.floor(accessTokenTtl / 1000), // ms→s
|
|
489
489
|
c_nonce: cNonce,
|
|
490
|
-
c_nonce_expires_in: Math.floor(cNonceTtl / 1000), //
|
|
490
|
+
c_nonce_expires_in: Math.floor(cNonceTtl / 1000), // ms→s
|
|
491
491
|
authorization_details: entry.credentialIds.map(function (id) {
|
|
492
492
|
return {
|
|
493
493
|
type: "openid_credential",
|
|
@@ -572,7 +572,7 @@ function create(opts) {
|
|
|
572
572
|
|
|
573
573
|
// Rotate c_nonce so a replayed proof-JWT for a follow-up
|
|
574
574
|
// batch_credential request is rejected.
|
|
575
|
-
var newCNonce = generateToken(16); //
|
|
575
|
+
var newCNonce = generateToken(16); // 128-bit c_nonce
|
|
576
576
|
await cNonceStore.set(iopts.accessToken, newCNonce);
|
|
577
577
|
|
|
578
578
|
// AUTH-6 — when single-use is on (default), DELETE the access token
|
|
@@ -600,7 +600,7 @@ function create(opts) {
|
|
|
600
600
|
format: spec.format,
|
|
601
601
|
credential: sdJwtToken.token,
|
|
602
602
|
c_nonce: newCNonce,
|
|
603
|
-
c_nonce_expires_in: Math.floor(cNonceTtl / 1000), //
|
|
603
|
+
c_nonce_expires_in: Math.floor(cNonceTtl / 1000), // ms→s
|
|
604
604
|
};
|
|
605
605
|
}
|
|
606
606
|
|
package/lib/auth/oid4vp.js
CHANGED
|
@@ -348,8 +348,8 @@ function create(opts) {
|
|
|
348
348
|
"createRequest: dcql is required");
|
|
349
349
|
}
|
|
350
350
|
_validateDcql(ropts.dcql);
|
|
351
|
-
var nonce = ropts.nonce || generateToken(16); //
|
|
352
|
-
var state = ropts.state || generateToken(16); //
|
|
351
|
+
var nonce = ropts.nonce || generateToken(16); // 128-bit nonce
|
|
352
|
+
var state = ropts.state || generateToken(16); // 128-bit state
|
|
353
353
|
var request = {
|
|
354
354
|
response_type: "vp_token",
|
|
355
355
|
response_mode: ropts.responseMode || "direct_post",
|
|
@@ -82,7 +82,7 @@ var _emitMetric = emit.metric;
|
|
|
82
82
|
|
|
83
83
|
var SUPPORTED_ALGS = ["ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "EdDSA"];
|
|
84
84
|
var MAX_STATEMENT_BYTES = 64 * 1024; // allow:raw-byte-literal — entity-statement size cap
|
|
85
|
-
var MAX_CHAIN_DEPTH = 10; //
|
|
85
|
+
var MAX_CHAIN_DEPTH = 10; // federation chain depth ceiling
|
|
86
86
|
|
|
87
87
|
function _b64uDecodeStr(s) { return Buffer.from(s, "base64url").toString("utf8"); }
|
|
88
88
|
|
|
@@ -117,7 +117,7 @@ function parseEntityStatement(jwt) {
|
|
|
117
117
|
}
|
|
118
118
|
var header, payload;
|
|
119
119
|
try {
|
|
120
|
-
header = safeJson.parse(_b64uDecodeStr(parts[0]), { maxBytes: 4096 }); //
|
|
120
|
+
header = safeJson.parse(_b64uDecodeStr(parts[0]), { maxBytes: 4096 }); // header cap
|
|
121
121
|
payload = safeJson.parse(_b64uDecodeStr(parts[1]), { maxBytes: MAX_STATEMENT_BYTES });
|
|
122
122
|
} catch (e) {
|
|
123
123
|
throw new AuthError("auth-openid-federation/bad-decode",
|
package/lib/auth/passkey.js
CHANGED
|
@@ -64,7 +64,7 @@ var { AuthError } = require("../framework-error");
|
|
|
64
64
|
// W3C WebAuthn name field cap — same as the rpName/userName ceiling in
|
|
65
65
|
// the spec's CredentialUserEntity / PublicKeyCredentialEntity dictionaries
|
|
66
66
|
// (no normative limit but RPs broadly cap at 256 to defeat DOM cost).
|
|
67
|
-
var MAX_NAME_LEN = 256; //
|
|
67
|
+
var MAX_NAME_LEN = 256; // UTF-16 codepoint count, not bytes
|
|
68
68
|
|
|
69
69
|
function _vendor() {
|
|
70
70
|
return _wa;
|
|
@@ -306,7 +306,7 @@ async function conditionalAuthOptions(opts) {
|
|
|
306
306
|
|
|
307
307
|
// CTAP2.1 §6.5 — PRF eval inputs are 32-byte salts. Caps every
|
|
308
308
|
// extension input that ships through the binary normalizer.
|
|
309
|
-
var MAX_EXT_INPUT_BYTES = 32; //
|
|
309
|
+
var MAX_EXT_INPUT_BYTES = 32; // CTAP2.1 §6.5 PRF salt length
|
|
310
310
|
|
|
311
311
|
function _b64urlExtInput(value, name, maxBytes) {
|
|
312
312
|
// Accept a base64url string OR a Buffer / Uint8Array. Normalize the
|
|
@@ -436,7 +436,7 @@ function _credBlobExt(args) {
|
|
|
436
436
|
throw new AuthError("auth-passkey/bad-credblob",
|
|
437
437
|
"extensions.credBlob blob must be a Uint8Array / Buffer");
|
|
438
438
|
}
|
|
439
|
-
if (buf.length === 0 || buf.length > 32) { //
|
|
439
|
+
if (buf.length === 0 || buf.length > 32) { // CTAP2.1 §11.1 credBlob max
|
|
440
440
|
throw new AuthError("auth-passkey/credblob-bad-length",
|
|
441
441
|
"extensions.credBlob blob must be 1-32 bytes (CTAP2.1 §11.1)");
|
|
442
442
|
}
|
package/lib/auth/saml.js
CHANGED
|
@@ -592,10 +592,14 @@ function create(opts) {
|
|
|
592
592
|
var nameId = _textContent(nameIdEl);
|
|
593
593
|
var nameIdFormat = _attr(nameIdEl, "Format");
|
|
594
594
|
|
|
595
|
-
var nowSec = Math.floor((vopts.now || Date.now()) / 1000); //
|
|
595
|
+
var nowSec = Math.floor((vopts.now || Date.now()) / 1000); // ms→s
|
|
596
596
|
var confirmations = _findAllChildren(subject, "SubjectConfirmation", SAML_NS.assertion);
|
|
597
597
|
var bearerOk = false;
|
|
598
598
|
var hokOk = false;
|
|
599
|
+
// InResponseTo of the SubjectConfirmation that actually passed bearer
|
|
600
|
+
// validation — captured so the returned value can't be sourced from a
|
|
601
|
+
// different (non-validated) confirmation when several are present.
|
|
602
|
+
var matchedInResponseTo = null;
|
|
599
603
|
var hokFingerprint = null;
|
|
600
604
|
// Holder-of-Key SubjectConfirmation per SAML 2.0 Profile §3.1
|
|
601
605
|
// (urn:oasis:names:tc:SAML:2.0:cm:holder-of-key). The IdP binds
|
|
@@ -680,10 +684,10 @@ function create(opts) {
|
|
|
680
684
|
// as Bearer (Profile §3.1 incorporates §3 by reference).
|
|
681
685
|
var nbHok = _attr(scdHok, "NotBefore");
|
|
682
686
|
var noaHok = _attr(scdHok, "NotOnOrAfter");
|
|
683
|
-
if (nbHok && isFinite(Date.parse(nbHok) / 1000) && //
|
|
684
|
-
Date.parse(nbHok) / 1000 > nowSec + clockSkewSec) continue; //
|
|
685
|
-
if (noaHok && isFinite(Date.parse(noaHok) / 1000) && //
|
|
686
|
-
Date.parse(noaHok) / 1000 < nowSec - clockSkewSec) continue; //
|
|
687
|
+
if (nbHok && isFinite(Date.parse(nbHok) / 1000) && // ms→s
|
|
688
|
+
Date.parse(nbHok) / 1000 > nowSec + clockSkewSec) continue; // ms→s
|
|
689
|
+
if (noaHok && isFinite(Date.parse(noaHok) / 1000) && // ms→s
|
|
690
|
+
Date.parse(noaHok) / 1000 < nowSec - clockSkewSec) continue; // ms→s
|
|
687
691
|
var recipHok = _attr(scdHok, "Recipient");
|
|
688
692
|
if (recipHok && recipHok !== opts.assertionConsumerServiceUrl) continue;
|
|
689
693
|
hokOk = true;
|
|
@@ -694,14 +698,14 @@ function create(opts) {
|
|
|
694
698
|
if (!scd) continue;
|
|
695
699
|
var notOnOrAfter = _attr(scd, "NotOnOrAfter");
|
|
696
700
|
if (notOnOrAfter) {
|
|
697
|
-
var t = Date.parse(notOnOrAfter) / 1000; //
|
|
701
|
+
var t = Date.parse(notOnOrAfter) / 1000; // ms→s
|
|
698
702
|
if (!isFinite(t) || t < nowSec - clockSkewSec) {
|
|
699
703
|
continue; // expired confirmation — try next
|
|
700
704
|
}
|
|
701
705
|
}
|
|
702
706
|
var notBefore = _attr(scd, "NotBefore");
|
|
703
707
|
if (notBefore) {
|
|
704
|
-
var nb = Date.parse(notBefore) / 1000; //
|
|
708
|
+
var nb = Date.parse(notBefore) / 1000; // ms→s
|
|
705
709
|
if (isFinite(nb) && nb > nowSec + clockSkewSec) continue;
|
|
706
710
|
}
|
|
707
711
|
var recipient = _attr(scd, "Recipient");
|
|
@@ -721,6 +725,7 @@ function create(opts) {
|
|
|
721
725
|
"AuthnRequest ID (replay defense)");
|
|
722
726
|
}
|
|
723
727
|
}
|
|
728
|
+
matchedInResponseTo = inResponseTo;
|
|
724
729
|
bearerOk = true;
|
|
725
730
|
break;
|
|
726
731
|
}
|
|
@@ -736,14 +741,14 @@ function create(opts) {
|
|
|
736
741
|
var cNotBefore = _attr(conditions, "NotBefore");
|
|
737
742
|
var cNotOnOrAfter = _attr(conditions, "NotOnOrAfter");
|
|
738
743
|
if (cNotBefore) {
|
|
739
|
-
var cnb = Date.parse(cNotBefore) / 1000; //
|
|
744
|
+
var cnb = Date.parse(cNotBefore) / 1000; // ms→s
|
|
740
745
|
if (isFinite(cnb) && cnb > nowSec + clockSkewSec) {
|
|
741
746
|
throw new AuthError("auth-saml/conditions-not-yet-valid",
|
|
742
747
|
"Conditions NotBefore is in the future");
|
|
743
748
|
}
|
|
744
749
|
}
|
|
745
750
|
if (cNotOnOrAfter) {
|
|
746
|
-
var cnoa = Date.parse(cNotOnOrAfter) / 1000; //
|
|
751
|
+
var cnoa = Date.parse(cNotOnOrAfter) / 1000; // ms→s
|
|
747
752
|
if (isFinite(cnoa) && cnoa < nowSec - clockSkewSec) {
|
|
748
753
|
throw new AuthError("auth-saml/conditions-expired",
|
|
749
754
|
"Conditions NotOnOrAfter has passed");
|
|
@@ -787,8 +792,7 @@ function create(opts) {
|
|
|
787
792
|
sessionIndex: sessionIndex,
|
|
788
793
|
attributes: attributes,
|
|
789
794
|
audience: audience,
|
|
790
|
-
inResponseTo: bearerOk ?
|
|
791
|
-
"SubjectConfirmationData", SAML_NS.assertion), "InResponseTo") : null,
|
|
795
|
+
inResponseTo: bearerOk ? matchedInResponseTo : null,
|
|
792
796
|
issuer: issuer,
|
|
793
797
|
};
|
|
794
798
|
}
|
|
@@ -884,7 +888,7 @@ function create(opts) {
|
|
|
884
888
|
throw new AuthError("auth-saml/no-idp-slo",
|
|
885
889
|
"buildLogoutRequest: opts.idpSloUrl (or sp.create's opts.idpSloUrl) required");
|
|
886
890
|
}
|
|
887
|
-
var id = "_" + generateToken(20); //
|
|
891
|
+
var id = "_" + generateToken(20); // 20-byte SAML ID token
|
|
888
892
|
var issueInstant = new Date().toISOString();
|
|
889
893
|
var c14n = xmlC14n();
|
|
890
894
|
var nameIdFormatAttr = bopts.nameIdFormat
|
|
@@ -1085,7 +1089,7 @@ function create(opts) {
|
|
|
1085
1089
|
validateOpts.requireNonEmptyString(bopts.inResponseTo, "inResponseTo", AuthError, "auth-saml/no-in-response-to");
|
|
1086
1090
|
validateOpts.requireNonEmptyString(bopts.destination, "destination", AuthError, "auth-saml/no-destination");
|
|
1087
1091
|
var statusCode = bopts.statusCode || "urn:oasis:names:tc:SAML:2.0:status:Success";
|
|
1088
|
-
var id = "_" + generateToken(20); //
|
|
1092
|
+
var id = "_" + generateToken(20); // 20-byte SAML ID token
|
|
1089
1093
|
var issueInstant = new Date().toISOString();
|
|
1090
1094
|
var c14n = xmlC14n();
|
|
1091
1095
|
var xml =
|
|
@@ -1288,7 +1292,7 @@ function create(opts) {
|
|
|
1288
1292
|
throw new AuthError("auth-saml/no-idp-slo",
|
|
1289
1293
|
"buildLogoutRequestPost: opts.idpSloUrl required");
|
|
1290
1294
|
}
|
|
1291
|
-
var id = "_" + generateToken(20); //
|
|
1295
|
+
var id = "_" + generateToken(20); // 20-byte SAML ID token
|
|
1292
1296
|
var issueInstant = new Date().toISOString();
|
|
1293
1297
|
var c14n = xmlC14n();
|
|
1294
1298
|
var nameIdFormatAttr = bopts.nameIdFormat
|
|
@@ -1663,18 +1667,18 @@ function _decryptEncryptedAssertion(encAssertion, spPrivateKeyPem) {
|
|
|
1663
1667
|
var clearBytes;
|
|
1664
1668
|
if (contentAlg === "http://www.w3.org/2009/xmlenc11#aes128-gcm" ||
|
|
1665
1669
|
contentAlg === "http://www.w3.org/2009/xmlenc11#aes256-gcm") {
|
|
1666
|
-
var aesBits = contentAlg.indexOf("aes128") !== -1 ? 128 : 256; //
|
|
1667
|
-
var expectedKeyBytes = aesBits / 8; //
|
|
1670
|
+
var aesBits = contentAlg.indexOf("aes128") !== -1 ? 128 : 256; // AES key size
|
|
1671
|
+
var expectedKeyBytes = aesBits / 8; // bits→bytes
|
|
1668
1672
|
if (cek.length !== expectedKeyBytes) {
|
|
1669
1673
|
throw new AuthError("auth-saml/encrypted-wrong-cek-len",
|
|
1670
1674
|
"AES-" + aesBits + "-GCM CEK length is " + cek.length + ", expected " + expectedKeyBytes);
|
|
1671
1675
|
}
|
|
1672
|
-
if (contentBlob.length < 28) { //
|
|
1676
|
+
if (contentBlob.length < 28) { // 12 IV + 16 tag
|
|
1673
1677
|
throw new AuthError("auth-saml/encrypted-content-too-short",
|
|
1674
1678
|
"AES-GCM CipherValue too short to contain IV (12) + tag (16)");
|
|
1675
1679
|
}
|
|
1676
|
-
var iv = contentBlob.subarray(0, 12); //
|
|
1677
|
-
var tag = contentBlob.subarray(contentBlob.length - 16); //
|
|
1680
|
+
var iv = contentBlob.subarray(0, 12); // GCM IV size
|
|
1681
|
+
var tag = contentBlob.subarray(contentBlob.length - 16); // GCM tag size
|
|
1678
1682
|
var ct = contentBlob.subarray(12, contentBlob.length - 16);
|
|
1679
1683
|
var decipher = nodeCrypto.createDecipheriv("aes-" + aesBits + "-gcm", cek, iv);
|
|
1680
1684
|
decipher.setAuthTag(tag);
|
|
@@ -1684,16 +1688,16 @@ function _decryptEncryptedAssertion(encAssertion, spPrivateKeyPem) {
|
|
|
1684
1688
|
"AES-GCM authentication tag mismatch: " + ((eD && eD.message) || String(eD)));
|
|
1685
1689
|
}
|
|
1686
1690
|
} else if (contentAlg === "urn:blamejs:experimental:xmlenc:xchacha20-poly1305") {
|
|
1687
|
-
if (cek.length !== 32) { //
|
|
1691
|
+
if (cek.length !== 32) { // XChaCha20 key size
|
|
1688
1692
|
throw new AuthError("auth-saml/encrypted-wrong-cek-len",
|
|
1689
1693
|
"XChaCha20-Poly1305 CEK length is " + cek.length + ", expected 32");
|
|
1690
1694
|
}
|
|
1691
|
-
if (contentBlob.length < 40) { //
|
|
1695
|
+
if (contentBlob.length < 40) { // 24 nonce + 16 tag
|
|
1692
1696
|
throw new AuthError("auth-saml/encrypted-content-too-short",
|
|
1693
1697
|
"XChaCha20-Poly1305 CipherValue too short");
|
|
1694
1698
|
}
|
|
1695
|
-
var xnonce = contentBlob.subarray(0, 24); //
|
|
1696
|
-
var xtag = contentBlob.subarray(contentBlob.length - 16); //
|
|
1699
|
+
var xnonce = contentBlob.subarray(0, 24); // XChaCha20 nonce size
|
|
1700
|
+
var xtag = contentBlob.subarray(contentBlob.length - 16); // Poly1305 tag size
|
|
1697
1701
|
var xct = contentBlob.subarray(24, contentBlob.length - 16);
|
|
1698
1702
|
try {
|
|
1699
1703
|
clearBytes = bCrypto.aeadDecrypt({
|
|
@@ -1971,7 +1975,7 @@ function _sigAlgUrn(alg) {
|
|
|
1971
1975
|
var keyObj = (sk && typeof sk === "object" && sk.type === "private") ? sk
|
|
1972
1976
|
: (typeof sk === "string" || (sk && sk.kty)) ? nodeCrypto.createPrivateKey(sk)
|
|
1973
1977
|
: nodeCrypto.createPrivateKey({ key: Buffer.concat([
|
|
1974
|
-
Buffer.from("302e020100300506032b657004220420", "hex"), //
|
|
1978
|
+
Buffer.from("302e020100300506032b657004220420", "hex"), // Ed25519 PKCS#8 prefix
|
|
1975
1979
|
Buffer.from(sk),
|
|
1976
1980
|
]), format: "der", type: "pkcs8" });
|
|
1977
1981
|
return nodeCrypto.sign(null, Buffer.from(bytes), keyObj);
|
|
@@ -1980,7 +1984,7 @@ function _sigAlgUrn(alg) {
|
|
|
1980
1984
|
var keyObj = (pk && typeof pk === "object" && pk.type === "public") ? pk
|
|
1981
1985
|
: (typeof pk === "string" || (pk && pk.kty)) ? nodeCrypto.createPublicKey(pk)
|
|
1982
1986
|
: nodeCrypto.createPublicKey({ key: Buffer.concat([
|
|
1983
|
-
Buffer.from("302a300506032b6570032100", "hex"), //
|
|
1987
|
+
Buffer.from("302a300506032b6570032100", "hex"), // Ed25519 SPKI prefix
|
|
1984
1988
|
Buffer.from(pk),
|
|
1985
1989
|
]), format: "der", type: "spki" });
|
|
1986
1990
|
return nodeCrypto.verify(null, Buffer.from(msg), keyObj, Buffer.from(sig));
|
|
@@ -17,7 +17,7 @@ var nodeCrypto = require("node:crypto");
|
|
|
17
17
|
var safeJson = require("../safe-json");
|
|
18
18
|
var { AuthError } = require("../framework-error");
|
|
19
19
|
|
|
20
|
-
var DEFAULT_SALT_BYTES = 16; //
|
|
20
|
+
var DEFAULT_SALT_BYTES = 16; // 128-bit salt per spec recommendation
|
|
21
21
|
|
|
22
22
|
function _newSalt(opts) {
|
|
23
23
|
if (opts && opts.saltSource && typeof opts.saltSource === "function") {
|
package/lib/auth/sd-jwt-vc.js
CHANGED
|
@@ -239,8 +239,8 @@ function issue(opts) {
|
|
|
239
239
|
sdDigests.sort();
|
|
240
240
|
|
|
241
241
|
var now = (typeof opts.issuedAt === "number" && isFinite(opts.issuedAt))
|
|
242
|
-
? Math.floor(opts.issuedAt / 1000) : Math.floor(Date.now() / 1000); //
|
|
243
|
-
var ttlSec = opts.ttlMs ? Math.floor(opts.ttlMs / 1000) : 30 * 24 * 60 * 60; //
|
|
242
|
+
? Math.floor(opts.issuedAt / 1000) : Math.floor(Date.now() / 1000); // ms→s conversion factor
|
|
243
|
+
var ttlSec = opts.ttlMs ? Math.floor(opts.ttlMs / 1000) : 30 * 24 * 60 * 60; // ms→s conversion + 30-day default in seconds
|
|
244
244
|
|
|
245
245
|
var payload = Object.assign({}, plainClaims, {
|
|
246
246
|
iss: opts.issuer,
|
|
@@ -355,7 +355,7 @@ function present(opts) {
|
|
|
355
355
|
"present: algorithm must be one of " + SUPPORTED_ALGS.join(", "));
|
|
356
356
|
}
|
|
357
357
|
var now = (typeof opts.issuedAt === "number" && isFinite(opts.issuedAt))
|
|
358
|
-
? Math.floor(opts.issuedAt / 1000) : Math.floor(Date.now() / 1000); //
|
|
358
|
+
? Math.floor(opts.issuedAt / 1000) : Math.floor(Date.now() / 1000); // ms→s conversion factor
|
|
359
359
|
// The KB-JWT's hash binds it to the specific SD-JWT + presentation
|
|
360
360
|
var kbHashInput = presentation; // jwt~d1~d2~ (without KB)
|
|
361
361
|
// sd_hash uses the SAME hash algorithm the credential's _sd
|
|
@@ -505,7 +505,7 @@ async function verify(presentation, opts) {
|
|
|
505
505
|
|
|
506
506
|
// 2. Validate iss / iat / exp / vct
|
|
507
507
|
var nowSec = (typeof opts.now === "number" && isFinite(opts.now))
|
|
508
|
-
? Math.floor(opts.now / 1000) : Math.floor(Date.now() / 1000); //
|
|
508
|
+
? Math.floor(opts.now / 1000) : Math.floor(Date.now() / 1000); // ms→s conversion factor
|
|
509
509
|
var skew = (typeof opts.maxClockSkewSec === "number") ? opts.maxClockSkewSec : 60; // allow:raw-time-literal — default 60s clock-skew tolerance
|
|
510
510
|
if (typeof jwtParsed.payload.iat === "number" && jwtParsed.payload.iat > nowSec + skew) {
|
|
511
511
|
throw new AuthError("auth-sd-jwt-vc/iat-future",
|