From 6afa59d18ff61f4899795bf4afa4492b344ea53f Mon Sep 17 00:00:00 2001
From: Albrecht Degering
Date: Thu, 20 Aug 2026 00:21:31 +0200
Subject: [PATCH] feat: release authentication laboratories 0.3.0
---
CHANGELOG.md | 13 +
README.md | 24 +-
SECURITY.md | 15 +-
THIRD_PARTY_NOTICES.md | 3 +-
package-lock.json | 17 +-
package.json | 3 +-
public/CHANGELOG.md | 13 +
public/LICENSES/npm-runtime-licenses.txt | 28 +
public/README.md | 24 +-
public/SECURITY.md | 15 +-
public/THIRD_PARTY_NOTICES.md | 3 +-
public/toolbox-app.json | 6 +-
src/components/HelpDialog.tsx | 11 +
src/components/otp/OtpAdvancedTools.tsx | 278 +++++++++
src/components/otp/OtpWorkspace.tsx | 224 +++++++-
.../webauthn/WebAuthnExtensionsLab.tsx | 535 ++++++++++++++++++
.../webauthn/WebAuthnTrustPolicyLab.tsx | 256 +++++++++
src/components/webauthn/WebAuthnWorkspace.tsx | 17 +-
src/otp/collection.ts | 259 +++++++++
src/otp/migration.ts | 132 +++++
src/otp/otp.ts | 58 ++
src/otp/pskc.ts | 449 +++++++++++++++
src/otp/vendor-backups.ts | 171 +++++-
src/qr/camera.ts | 129 +++++
src/styles.css | 116 +++-
src/toolbox/manifest.source.json | 6 +-
src/version.ts | 2 +-
src/webauthn/extensions.ts | 190 +++++++
src/webauthn/live.ts | 152 ++++-
src/webauthn/metadata.ts | 2 +
src/webauthn/trace.ts | 245 ++++++++
src/webauthn/trust-policy.ts | 259 +++++++++
src/webauthn/x509.ts | 110 ++++
tests/browser/workbench.spec.ts | 36 +-
tests/otp/collection.test.ts | 57 ++
tests/otp/migration.test.ts | 24 +
tests/otp/otp.test.ts | 28 +
tests/otp/pskc.test.ts | 93 +++
tests/otp/vendor-backups.test.ts | 96 ++++
tests/qr/camera.test.ts | 59 ++
tests/webauthn/extensions.test.ts | 40 ++
tests/webauthn/live.test.ts | 45 ++
tests/webauthn/trace.test.ts | 73 +++
tests/webauthn/trust-policy.test.ts | 82 +++
44 files changed, 4332 insertions(+), 66 deletions(-)
create mode 100644 src/components/otp/OtpAdvancedTools.tsx
create mode 100644 src/components/webauthn/WebAuthnExtensionsLab.tsx
create mode 100644 src/components/webauthn/WebAuthnTrustPolicyLab.tsx
create mode 100644 src/otp/collection.ts
create mode 100644 src/otp/pskc.ts
create mode 100644 src/qr/camera.ts
create mode 100644 src/webauthn/extensions.ts
create mode 100644 src/webauthn/trace.ts
create mode 100644 src/webauthn/trust-policy.ts
create mode 100644 tests/otp/collection.test.ts
create mode 100644 tests/otp/pskc.test.ts
create mode 100644 tests/qr/camera.test.ts
create mode 100644 tests/webauthn/extensions.test.ts
create mode 100644 tests/webauthn/live.test.ts
create mode 100644 tests/webauthn/trace.test.ts
create mode 100644 tests/webauthn/trust-policy.test.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29b0b95..c74370b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,19 @@ All notable changes are documented here.
## Unreleased
+## 0.3.0 - 2026-08-19
+
+- Added a live WebAuthn Extensions Lab for `credProps`, PRF, `largeBlob`, `appid` and `appidExclude`, including client-capability detection and normalized request/result inspection.
+- Added bounded, versioned WebAuthn ceremony traces with raw and redacted export, offline cryptographic replay and structural comparison.
+- Added user-pinned Metadata Service trust roots, signer-chain signature validation and historical, firmware-aware attestation status policy evaluation.
+- Added strict Google Authenticator migration export with multi-part QR rendering and loss-prevention checks.
+- Added local password-vault decryption for Aegis AES-256-GCM/scrypt password slots with bounded work parameters.
+- Added an authenticated RFC 6030 PSKC password profile using PBKDF2, AES-CBC, an encrypted MAC key and per-secret HMAC `ValueMAC` checks.
+- Added secret-free collection snapshots, before/after comparison, secret-reuse detection and prioritized rotation planning.
+- Added bounded HOTP counter resynchronization with optional consecutive-code confirmation.
+- Added explicitly triggered camera QR scanning with native/fallback decoding, automatic track cleanup and a dedicated-origin Permissions Policy.
+- Added `@noble/hashes` 2.3.0 for audited, asynchronous local scrypt derivation; the locked dependency audit reports no known vulnerabilities.
+
## 0.2.0 - 2026-08-19
- Added auditable TOTP time travel using live time, bounded positive or negative period offsets, or a frozen local date/time interpreted in an explicit IANA timezone.
diff --git a/README.md b/README.md
index 5c8cc15..b06ce38 100644
--- a/README.md
+++ b/README.md
@@ -11,15 +11,19 @@ Authentication material stays in the active tab. The application has no backend,
- Auditable TOTP time travel using positive/negative period offsets or a frozen local date/time in an explicit IANA timezone, including DST-gap rejection and repeated-time disambiguation.
- Bounded clock-drift search, past/current/future OTP timelines, downloadable interoperability vectors and custom RFC 6238 T0 diagnostics.
- RFC 6287 OCRA-1 suite parsing and computation for counter, numeric/alphanumeric/hex challenge, PIN/password hash, session and timestamp inputs. Official RFC interoperability vectors cover SHA-1, SHA-256 and SHA-512 paths.
-- Import of line-delimited provisioning URIs, complete Google Authenticator multi-QR batches, Aegis plaintext JSON, 2FAS JSON, andOTP plaintext JSON, legacy FreeOTP JSON, the documented CSV shape and RFC 6030 PSKC files containing plain secrets. Unsupported encrypted vendor formats are rejected rather than guessed.
-- Cross-browser QR image decoding through native `BarcodeDetector` when available and a bundled jsQR fallback everywhere else.
-- Credential-collection health reports for duplicated secrets/labels, weak secret lengths and non-default timing.
+- Import of line-delimited provisioning URIs, complete Google Authenticator multi-QR batches, password-encrypted or plaintext Aegis JSON, 2FAS JSON, andOTP plaintext JSON, legacy FreeOTP JSON, the documented CSV shape, and plain or password-encrypted RFC 6030 PSKC.
+- Google Authenticator migration export in bounded multi-part QR batches and an authenticated PSKC password profile using PBKDF2, AES-CBC, an encrypted MAC key and per-secret `ValueMAC` verification.
+- Cross-browser QR image decoding through native `BarcodeDetector` when available and a bundled jsQR fallback everywhere else, including an explicitly triggered, time-limited camera scanner on the dedicated origin.
+- Credential-collection health reports, secret-free inventory snapshots, before/after comparison and prioritized rotation plans for duplicated secrets, changed parameters and removed credentials.
+- Bounded HOTP resynchronization with one code or stronger consecutive-code confirmation; suggested counters are never applied automatically.
- Explicit URI-list and CSV export with an unencrypted-secret warning, plus a versioned authenticated encrypted backup using PBKDF2-SHA-256 and AES-256-GCM.
- Bounded CBOR, `clientDataJSON`, authenticator-data and attestation-object inspection, including flags, RP ID hash, counter, AAGUID, credential ID, COSE key and extensions.
- Layered assertion verification for challenge, origin, cross-origin state, RP ID hash, user presence/verification, signature counter, and ES256, RS256, PS256 or Ed25519 signatures.
- Layered registration verification for none, packed/self, FIDO U2F, TPM 2.0, Android Key and Apple anonymous attestation, including certificate signatures and format-specific credential/challenge bindings.
-- Explicit offline FIDO Metadata Service v3 JWT snapshot import, signer verification, AAGUID matching and authenticator status display. Imported metadata never silently establishes a trust root.
+- Explicit offline FIDO Metadata Service v3 JWT snapshot import, signer verification, user-pinned PEM trust roots, signer-chain validation, historical effective-date and firmware-aware status policy evaluation. Imported metadata never silently establishes trust.
- Serializable registration/request option examples, browser capability diagnostics and an ephemeral in-memory live ceremony lab.
+- A WebAuthn Extensions Lab for `credProps`, `prf`, `largeBlob`, `appid` and `appidExclude`, with `getClientCapabilities()` inspection and normalized request/result output.
+- Versioned registration/authentication trace capture, raw or privacy-redacted export, offline cryptographic replay and structural comparison.
## Security boundary
@@ -31,7 +35,7 @@ https://auth.toolbox.add-ideas.de/
The same immutable release can be served there, top-level, with RP ID `auth.toolbox.add-ideas.de`. The RP ID is never widened to `add-ideas.de`, and arbitrary RP IDs can only be inspected offline.
-Raw CTAP/token administration is not claimed: browsers expose ordinary WebAuthn but block the FIDO HID usage page from WebHID. Camera and USB permissions are not requested. QR images can be selected locally in current browsers; provisioning text can always be pasted.
+Raw CTAP/token administration is not claimed: browsers expose ordinary WebAuthn but block the FIDO HID usage page from WebHID. USB is never requested. Camera access is granted only on the dedicated Auth Tools host and is requested only after clicking **Scan with camera**; tracks stop on success, cancellation, timeout or teardown. QR images and pasted provisioning text remain available without camera permission.
See [SECURITY.md](SECURITY.md) for the threat model and limitations.
@@ -50,11 +54,11 @@ The Vite base is relative, so both `/` and nested paths work. `npm run toolbox:c
## Static deployment
-Serve `dist/` or the contents of `release/auth-tools-0.2.0.zip` over HTTPS. Recommended response headers:
+Serve `dist/` or the contents of `release/auth-tools-0.3.0.zip` over HTTPS. Recommended response headers for the dedicated Auth Tools origin:
```text
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self' blob:; manifest-src 'self'
-Permissions-Policy: camera=(), microphone=(), geolocation=(), usb=()
+Permissions-Policy: camera=(self), microphone=(), geolocation=(), usb=()
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
Cross-Origin-Opener-Policy: same-origin
@@ -67,10 +71,12 @@ For Portal integration, pin the immutable Gitea release ZIP and SHA-256 in `tool
- This is an engineering and interoperability workbench, not a certified authenticator, relying-party server, password manager, FIDO certification tool or recovery system.
- Live credentials are forgotten on reload and cannot be exported by WebAuthn design.
-- Attestation cryptography and metadata status are evidence, not automatic device trust. No trust root or policy is bundled, and FIDO metadata is never downloaded silently.
-- All parts of a Google multi-QR batch must be supplied. Google migration export, Aegis password-vault decryption, FreeOTP 2.x encrypted XML and encrypted PSKC decryption are not claimed.
+- Attestation cryptography and metadata status are evidence, not automatic device trust. No trust root is bundled, metadata is never downloaded silently, and the local signer-chain verifier is a pinned-root signature path check rather than a complete RFC 5280 PKIX/revocation implementation.
+- All parts of a Google multi-QR batch must be supplied. Google export refuses settings its format cannot preserve. Aegis biometric/raw-key slots and FreeOTP 2.x encrypted XML are not claimed.
+- Encrypted PSKC supports the documented password-derived PBKDF2 + AES-CBC + HMAC `ValueMAC` profile. A namespaced Auth Tools extension preserves non-SHA-1 OTP hash selection without changing the RFC container structure. Asymmetric, pre-shared-key and unverified encrypted-value profiles are rejected.
- CSV and URI exports contain raw OTP seeds. The encrypted export is a portable backup file, not a persistent browser vault or recovery service.
- QR generation supports byte-mode error-correction M through version 10. Larger provisioning records remain available as text exports.
+- Redacted WebAuthn traces remove labels and top-level identifiers but retain signed ceremony blobs needed for replay; those blobs can contain stable correlatable identifiers.
## Licence
diff --git a/SECURITY.md b/SECURITY.md
index 2f81840..539c40d 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -6,12 +6,15 @@ All inputs are processed in the browser tab. There are no application `fetch`, W
Downloads and clipboard writes require a user action. URI/CSV exports are not encrypted; the dedicated encrypted format uses an authenticated cipher and a user-supplied password. The UI masks OTP secrets and provisioning URIs by default, but masking is not memory protection.
+Camera capture is never started automatically. The dedicated origin requests it only after the user selects camera scanning, reads bounded frames locally, and stops all media tracks after a match, cancellation, timeout or component teardown. The shared Portal origin keeps camera permission disabled.
+
## Trust boundaries
- The static release and its hosting origin are trusted code. A compromised host can alter JavaScript and steal subsequently entered material; verify the release SHA-256 when this matters.
- Imported URIs, CSV, XML, protobuf, JSON, Base64url and CBOR are untrusted. Size/depth/count limits are applied before or during decoding. Imported text is rendered by React, never as markup. The only generated markup insertion is the project-owned QR SVG serializer, which receives an already serialized provisioning URI and emits path coordinates only.
- WebAuthn client data is verified as exact strings/bytes. Origins and RP IDs are not suffix-matched. The expected challenge is caller-supplied ceremony state; the tool cannot prove that a server generated or consumed it once.
-- Assertion signatures establish consistency with the supplied COSE public key. Attestation checks establish format-specific cryptographic bindings; certificate-chain trust and authenticator policy remain separate. Imported FIDO metadata has its JWS signer checked but does not silently install a trust root.
+- Assertion signatures establish consistency with the supplied COSE public key. Attestation checks establish format-specific cryptographic bindings; certificate-chain trust and authenticator policy remain separate. Imported FIDO metadata has its JWS signer checked and can be evaluated against explicitly supplied roots, but no root is installed or downloaded silently. The signer-chain check validates supported certificate signatures to the pinned root; it is not a full RFC 5280 name-constraints, policy, revocation or path-building engine.
+- WebAuthn trace redaction removes user labels, handles and top-level credential identifiers. Signed client/authenticator/attestation blobs remain intact for replay and can still contain stable identifiers; redacted traces require review before publication.
## Origin isolation
@@ -19,22 +22,28 @@ Downloads and clipboard writes require a user action. URI/CSV exports are not en
## Cryptography
-HMAC, digest, random generation, PBKDF2 key derivation, AES-GCM authenticated encryption, public-key import and signature verification use the browser Web Cryptography API. No custom cryptographic primitive is implemented. OTP dynamic truncation, OCRA data-input assembly and bounded DER/TPM structure interpretation are project code covered by tests.
+HMAC, digest, random generation, PBKDF2 key derivation, AES-GCM authenticated encryption, PSKC AES-CBC encryption/decryption, public-key import and signature verification use the browser Web Cryptography API. Aegis password slots use the maintained `@noble/hashes` scrypt implementation with explicit memory/work bounds. No project-authored cryptographic primitive is used for key derivation or encryption. OTP dynamic truncation, OCRA data-input assembly and bounded DER/TPM structure interpretation are project code covered by tests.
The encrypted backup format uses a 16-byte random salt, 600,000 PBKDF2-HMAC-SHA-256 iterations, a 256-bit AES-GCM key, a 96-bit random IV, a 128-bit authentication tag and authenticated version/KDF/cipher metadata. Decryption failures do not expose partial plaintext. It is an export format, not persistent storage.
+The password-encrypted PSKC profile derives a 128/192/256-bit AES-CBC key with bounded PBKDF2, encrypts a random MAC key with that key, prepends a fresh IV to every encrypted value, and authenticates every encrypted secret with HMAC before decryption. A PSKC extension in the Auth Tools namespace preserves the selected OTP hash. Unsupported or unauthenticated encrypted PSKC profiles are rejected.
+
SHA-1 remains available only where HOTP/TOTP/OCRA interoperability standards require it; it is used inside HMAC or as an explicitly selected OCRA PIN digest, not as a collision-resistant document signature.
## Parser limits
- Provisioning URI: 16 KiB.
-- Migration/CSV/PSKC input: 4 MiB; vendor/encrypted backup input: 16 MiB.
+- Migration/CSV/plain PSKC input: 4 MiB; encrypted PSKC and vendor/encrypted backup input: 16 MiB.
- Google protobuf: bounded input, varints at most 10 bytes, supported wire types only.
- CBOR: 4 MiB, depth 32, 10,000 items, definite lengths only, duplicate map keys rejected.
- OTP secret: 1 KiB; random generation: 16–1,024 bytes.
- Verification windows: routine TOTP 100 steps maximum; explicit drift search 10,000 periods; HOTP 10,000 counters maximum.
+- Aegis password derivation: scrypt N at most 65,536, r at most 16, p at most 4 and a 64 MiB memory policy.
+- PSKC password derivation: PBKDF2 at most 2,000,000 iterations; export requires at least 100,000 iterations and a 12-character password.
+- WebAuthn trace and OTP collection snapshot: 8 MiB; collection/profile count 10,000.
- QR encoder: version 10 maximum. QR decoder: 16 MiB, 4096 px per side and 16 megapixels.
- FIDO Metadata BLOB: 32 MiB, 100,000 entries and 20 signer certificates maximum.
+- Camera QR scan: 60 seconds, about 10 frames/second and 1,280 px maximum processing edge.
## Not persistent storage or an identity provider
diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md
index bb54595..35d3d8b 100644
--- a/THIRD_PARTY_NOTICES.md
+++ b/THIRD_PARTY_NOTICES.md
@@ -8,11 +8,12 @@ The release preparation step collates licence files for the exact locked runtime
| -------------------------------- | ------- | ---------- | ------------------------------- | ------------------------------------------- |
| `@add-ideas/toolbox-contract` | 0.2.3 | Apache-2.0 | manifest and context contract | https://git.add-ideas.de/lotobo/toolbox-sdk |
| `@add-ideas/toolbox-shell-react` | 0.2.3 | Apache-2.0 | shared shell, theme and actions | https://git.add-ideas.de/lotobo/toolbox-sdk |
+| `@noble/hashes` | 2.3.0 | MIT | local Aegis scrypt derivation | https://github.com/paulmillr/noble-hashes |
| `jsqr` | 1.4.0 | Apache-2.0 | local QR image decoding | https://github.com/cozmo/jsQR |
| `react` | 19.2.6 | MIT | application UI | https://github.com/facebook/react |
| `react-dom` | 19.2.6 | MIT | browser rendering | https://github.com/facebook/react |
-`scheduler`, distributed by the React project under MIT, is the only transitive runtime package. Exact licence texts, including jsQR's Apache-2.0 terms, are collated from the locked install into the release.
+`scheduler`, distributed by the React project under MIT, is the only transitive runtime package. Exact licence texts, including jsQR's Apache-2.0 and noble-hashes' MIT terms, are collated from the locked install into the release.
## QR construction
diff --git a/package-lock.json b/package-lock.json
index 3a277ad..70442a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "auth-tools",
- "version": "0.2.0",
+ "version": "0.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "auth-tools",
- "version": "0.2.0",
+ "version": "0.3.0",
"license": "GPL-3.0-or-later",
"dependencies": {
"@add-ideas/toolbox-contract": "0.2.3",
"@add-ideas/toolbox-shell-react": "0.2.3",
+ "@noble/hashes": "2.3.0",
"jsqr": "1.4.0",
"react": "19.2.6",
"react-dom": "19.2.6"
@@ -853,6 +854,18 @@
"@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3"
}
},
+ "node_modules/@noble/hashes": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz",
+ "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@oxc-project/types": {
"version": "0.142.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz",
diff --git a/package.json b/package.json
index 2d2b699..d6036ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "auth-tools",
- "version": "0.2.0",
+ "version": "0.3.0",
"description": "Inspect and test OTP and WebAuthn authentication locally in the browser.",
"license": "GPL-3.0-or-later",
"author": "Albrecht Degering",
@@ -41,6 +41,7 @@
"dependencies": {
"@add-ideas/toolbox-contract": "0.2.3",
"@add-ideas/toolbox-shell-react": "0.2.3",
+ "@noble/hashes": "2.3.0",
"jsqr": "1.4.0",
"react": "19.2.6",
"react-dom": "19.2.6"
diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md
index 29b0b95..c74370b 100644
--- a/public/CHANGELOG.md
+++ b/public/CHANGELOG.md
@@ -4,6 +4,19 @@ All notable changes are documented here.
## Unreleased
+## 0.3.0 - 2026-08-19
+
+- Added a live WebAuthn Extensions Lab for `credProps`, PRF, `largeBlob`, `appid` and `appidExclude`, including client-capability detection and normalized request/result inspection.
+- Added bounded, versioned WebAuthn ceremony traces with raw and redacted export, offline cryptographic replay and structural comparison.
+- Added user-pinned Metadata Service trust roots, signer-chain signature validation and historical, firmware-aware attestation status policy evaluation.
+- Added strict Google Authenticator migration export with multi-part QR rendering and loss-prevention checks.
+- Added local password-vault decryption for Aegis AES-256-GCM/scrypt password slots with bounded work parameters.
+- Added an authenticated RFC 6030 PSKC password profile using PBKDF2, AES-CBC, an encrypted MAC key and per-secret HMAC `ValueMAC` checks.
+- Added secret-free collection snapshots, before/after comparison, secret-reuse detection and prioritized rotation planning.
+- Added bounded HOTP counter resynchronization with optional consecutive-code confirmation.
+- Added explicitly triggered camera QR scanning with native/fallback decoding, automatic track cleanup and a dedicated-origin Permissions Policy.
+- Added `@noble/hashes` 2.3.0 for audited, asynchronous local scrypt derivation; the locked dependency audit reports no known vulnerabilities.
+
## 0.2.0 - 2026-08-19
- Added auditable TOTP time travel using live time, bounded positive or negative period offsets, or a frozen local date/time interpreted in an explicit IANA timezone.
diff --git a/public/LICENSES/npm-runtime-licenses.txt b/public/LICENSES/npm-runtime-licenses.txt
index 7381b77..7a11882 100644
--- a/public/LICENSES/npm-runtime-licenses.txt
+++ b/public/LICENSES/npm-runtime-licenses.txt
@@ -398,6 +398,34 @@ Installed from: node_modules/@add-ideas/toolbox-shell-react
limitations under the License.
+==============================================================================
+@noble/hashes@2.3.0
+Declared licence: MIT
+Installed from: node_modules/@noble/hashes
+==============================================================================
+--- LICENSE ---
+The MIT License (MIT)
+
+Copyright (c) 2022 Paul Miller (https://paulmillr.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the “Software”), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
==============================================================================
jsqr@1.4.0
Declared licence: Apache-2.0
diff --git a/public/README.md b/public/README.md
index 5c8cc15..b06ce38 100644
--- a/public/README.md
+++ b/public/README.md
@@ -11,15 +11,19 @@ Authentication material stays in the active tab. The application has no backend,
- Auditable TOTP time travel using positive/negative period offsets or a frozen local date/time in an explicit IANA timezone, including DST-gap rejection and repeated-time disambiguation.
- Bounded clock-drift search, past/current/future OTP timelines, downloadable interoperability vectors and custom RFC 6238 T0 diagnostics.
- RFC 6287 OCRA-1 suite parsing and computation for counter, numeric/alphanumeric/hex challenge, PIN/password hash, session and timestamp inputs. Official RFC interoperability vectors cover SHA-1, SHA-256 and SHA-512 paths.
-- Import of line-delimited provisioning URIs, complete Google Authenticator multi-QR batches, Aegis plaintext JSON, 2FAS JSON, andOTP plaintext JSON, legacy FreeOTP JSON, the documented CSV shape and RFC 6030 PSKC files containing plain secrets. Unsupported encrypted vendor formats are rejected rather than guessed.
-- Cross-browser QR image decoding through native `BarcodeDetector` when available and a bundled jsQR fallback everywhere else.
-- Credential-collection health reports for duplicated secrets/labels, weak secret lengths and non-default timing.
+- Import of line-delimited provisioning URIs, complete Google Authenticator multi-QR batches, password-encrypted or plaintext Aegis JSON, 2FAS JSON, andOTP plaintext JSON, legacy FreeOTP JSON, the documented CSV shape, and plain or password-encrypted RFC 6030 PSKC.
+- Google Authenticator migration export in bounded multi-part QR batches and an authenticated PSKC password profile using PBKDF2, AES-CBC, an encrypted MAC key and per-secret `ValueMAC` verification.
+- Cross-browser QR image decoding through native `BarcodeDetector` when available and a bundled jsQR fallback everywhere else, including an explicitly triggered, time-limited camera scanner on the dedicated origin.
+- Credential-collection health reports, secret-free inventory snapshots, before/after comparison and prioritized rotation plans for duplicated secrets, changed parameters and removed credentials.
+- Bounded HOTP resynchronization with one code or stronger consecutive-code confirmation; suggested counters are never applied automatically.
- Explicit URI-list and CSV export with an unencrypted-secret warning, plus a versioned authenticated encrypted backup using PBKDF2-SHA-256 and AES-256-GCM.
- Bounded CBOR, `clientDataJSON`, authenticator-data and attestation-object inspection, including flags, RP ID hash, counter, AAGUID, credential ID, COSE key and extensions.
- Layered assertion verification for challenge, origin, cross-origin state, RP ID hash, user presence/verification, signature counter, and ES256, RS256, PS256 or Ed25519 signatures.
- Layered registration verification for none, packed/self, FIDO U2F, TPM 2.0, Android Key and Apple anonymous attestation, including certificate signatures and format-specific credential/challenge bindings.
-- Explicit offline FIDO Metadata Service v3 JWT snapshot import, signer verification, AAGUID matching and authenticator status display. Imported metadata never silently establishes a trust root.
+- Explicit offline FIDO Metadata Service v3 JWT snapshot import, signer verification, user-pinned PEM trust roots, signer-chain validation, historical effective-date and firmware-aware status policy evaluation. Imported metadata never silently establishes trust.
- Serializable registration/request option examples, browser capability diagnostics and an ephemeral in-memory live ceremony lab.
+- A WebAuthn Extensions Lab for `credProps`, `prf`, `largeBlob`, `appid` and `appidExclude`, with `getClientCapabilities()` inspection and normalized request/result output.
+- Versioned registration/authentication trace capture, raw or privacy-redacted export, offline cryptographic replay and structural comparison.
## Security boundary
@@ -31,7 +35,7 @@ https://auth.toolbox.add-ideas.de/
The same immutable release can be served there, top-level, with RP ID `auth.toolbox.add-ideas.de`. The RP ID is never widened to `add-ideas.de`, and arbitrary RP IDs can only be inspected offline.
-Raw CTAP/token administration is not claimed: browsers expose ordinary WebAuthn but block the FIDO HID usage page from WebHID. Camera and USB permissions are not requested. QR images can be selected locally in current browsers; provisioning text can always be pasted.
+Raw CTAP/token administration is not claimed: browsers expose ordinary WebAuthn but block the FIDO HID usage page from WebHID. USB is never requested. Camera access is granted only on the dedicated Auth Tools host and is requested only after clicking **Scan with camera**; tracks stop on success, cancellation, timeout or teardown. QR images and pasted provisioning text remain available without camera permission.
See [SECURITY.md](SECURITY.md) for the threat model and limitations.
@@ -50,11 +54,11 @@ The Vite base is relative, so both `/` and nested paths work. `npm run toolbox:c
## Static deployment
-Serve `dist/` or the contents of `release/auth-tools-0.2.0.zip` over HTTPS. Recommended response headers:
+Serve `dist/` or the contents of `release/auth-tools-0.3.0.zip` over HTTPS. Recommended response headers for the dedicated Auth Tools origin:
```text
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; worker-src 'self' blob:; manifest-src 'self'
-Permissions-Policy: camera=(), microphone=(), geolocation=(), usb=()
+Permissions-Policy: camera=(self), microphone=(), geolocation=(), usb=()
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
Cross-Origin-Opener-Policy: same-origin
@@ -67,10 +71,12 @@ For Portal integration, pin the immutable Gitea release ZIP and SHA-256 in `tool
- This is an engineering and interoperability workbench, not a certified authenticator, relying-party server, password manager, FIDO certification tool or recovery system.
- Live credentials are forgotten on reload and cannot be exported by WebAuthn design.
-- Attestation cryptography and metadata status are evidence, not automatic device trust. No trust root or policy is bundled, and FIDO metadata is never downloaded silently.
-- All parts of a Google multi-QR batch must be supplied. Google migration export, Aegis password-vault decryption, FreeOTP 2.x encrypted XML and encrypted PSKC decryption are not claimed.
+- Attestation cryptography and metadata status are evidence, not automatic device trust. No trust root is bundled, metadata is never downloaded silently, and the local signer-chain verifier is a pinned-root signature path check rather than a complete RFC 5280 PKIX/revocation implementation.
+- All parts of a Google multi-QR batch must be supplied. Google export refuses settings its format cannot preserve. Aegis biometric/raw-key slots and FreeOTP 2.x encrypted XML are not claimed.
+- Encrypted PSKC supports the documented password-derived PBKDF2 + AES-CBC + HMAC `ValueMAC` profile. A namespaced Auth Tools extension preserves non-SHA-1 OTP hash selection without changing the RFC container structure. Asymmetric, pre-shared-key and unverified encrypted-value profiles are rejected.
- CSV and URI exports contain raw OTP seeds. The encrypted export is a portable backup file, not a persistent browser vault or recovery service.
- QR generation supports byte-mode error-correction M through version 10. Larger provisioning records remain available as text exports.
+- Redacted WebAuthn traces remove labels and top-level identifiers but retain signed ceremony blobs needed for replay; those blobs can contain stable correlatable identifiers.
## Licence
diff --git a/public/SECURITY.md b/public/SECURITY.md
index 2f81840..539c40d 100644
--- a/public/SECURITY.md
+++ b/public/SECURITY.md
@@ -6,12 +6,15 @@ All inputs are processed in the browser tab. There are no application `fetch`, W
Downloads and clipboard writes require a user action. URI/CSV exports are not encrypted; the dedicated encrypted format uses an authenticated cipher and a user-supplied password. The UI masks OTP secrets and provisioning URIs by default, but masking is not memory protection.
+Camera capture is never started automatically. The dedicated origin requests it only after the user selects camera scanning, reads bounded frames locally, and stops all media tracks after a match, cancellation, timeout or component teardown. The shared Portal origin keeps camera permission disabled.
+
## Trust boundaries
- The static release and its hosting origin are trusted code. A compromised host can alter JavaScript and steal subsequently entered material; verify the release SHA-256 when this matters.
- Imported URIs, CSV, XML, protobuf, JSON, Base64url and CBOR are untrusted. Size/depth/count limits are applied before or during decoding. Imported text is rendered by React, never as markup. The only generated markup insertion is the project-owned QR SVG serializer, which receives an already serialized provisioning URI and emits path coordinates only.
- WebAuthn client data is verified as exact strings/bytes. Origins and RP IDs are not suffix-matched. The expected challenge is caller-supplied ceremony state; the tool cannot prove that a server generated or consumed it once.
-- Assertion signatures establish consistency with the supplied COSE public key. Attestation checks establish format-specific cryptographic bindings; certificate-chain trust and authenticator policy remain separate. Imported FIDO metadata has its JWS signer checked but does not silently install a trust root.
+- Assertion signatures establish consistency with the supplied COSE public key. Attestation checks establish format-specific cryptographic bindings; certificate-chain trust and authenticator policy remain separate. Imported FIDO metadata has its JWS signer checked and can be evaluated against explicitly supplied roots, but no root is installed or downloaded silently. The signer-chain check validates supported certificate signatures to the pinned root; it is not a full RFC 5280 name-constraints, policy, revocation or path-building engine.
+- WebAuthn trace redaction removes user labels, handles and top-level credential identifiers. Signed client/authenticator/attestation blobs remain intact for replay and can still contain stable identifiers; redacted traces require review before publication.
## Origin isolation
@@ -19,22 +22,28 @@ Downloads and clipboard writes require a user action. URI/CSV exports are not en
## Cryptography
-HMAC, digest, random generation, PBKDF2 key derivation, AES-GCM authenticated encryption, public-key import and signature verification use the browser Web Cryptography API. No custom cryptographic primitive is implemented. OTP dynamic truncation, OCRA data-input assembly and bounded DER/TPM structure interpretation are project code covered by tests.
+HMAC, digest, random generation, PBKDF2 key derivation, AES-GCM authenticated encryption, PSKC AES-CBC encryption/decryption, public-key import and signature verification use the browser Web Cryptography API. Aegis password slots use the maintained `@noble/hashes` scrypt implementation with explicit memory/work bounds. No project-authored cryptographic primitive is used for key derivation or encryption. OTP dynamic truncation, OCRA data-input assembly and bounded DER/TPM structure interpretation are project code covered by tests.
The encrypted backup format uses a 16-byte random salt, 600,000 PBKDF2-HMAC-SHA-256 iterations, a 256-bit AES-GCM key, a 96-bit random IV, a 128-bit authentication tag and authenticated version/KDF/cipher metadata. Decryption failures do not expose partial plaintext. It is an export format, not persistent storage.
+The password-encrypted PSKC profile derives a 128/192/256-bit AES-CBC key with bounded PBKDF2, encrypts a random MAC key with that key, prepends a fresh IV to every encrypted value, and authenticates every encrypted secret with HMAC before decryption. A PSKC extension in the Auth Tools namespace preserves the selected OTP hash. Unsupported or unauthenticated encrypted PSKC profiles are rejected.
+
SHA-1 remains available only where HOTP/TOTP/OCRA interoperability standards require it; it is used inside HMAC or as an explicitly selected OCRA PIN digest, not as a collision-resistant document signature.
## Parser limits
- Provisioning URI: 16 KiB.
-- Migration/CSV/PSKC input: 4 MiB; vendor/encrypted backup input: 16 MiB.
+- Migration/CSV/plain PSKC input: 4 MiB; encrypted PSKC and vendor/encrypted backup input: 16 MiB.
- Google protobuf: bounded input, varints at most 10 bytes, supported wire types only.
- CBOR: 4 MiB, depth 32, 10,000 items, definite lengths only, duplicate map keys rejected.
- OTP secret: 1 KiB; random generation: 16–1,024 bytes.
- Verification windows: routine TOTP 100 steps maximum; explicit drift search 10,000 periods; HOTP 10,000 counters maximum.
+- Aegis password derivation: scrypt N at most 65,536, r at most 16, p at most 4 and a 64 MiB memory policy.
+- PSKC password derivation: PBKDF2 at most 2,000,000 iterations; export requires at least 100,000 iterations and a 12-character password.
+- WebAuthn trace and OTP collection snapshot: 8 MiB; collection/profile count 10,000.
- QR encoder: version 10 maximum. QR decoder: 16 MiB, 4096 px per side and 16 megapixels.
- FIDO Metadata BLOB: 32 MiB, 100,000 entries and 20 signer certificates maximum.
+- Camera QR scan: 60 seconds, about 10 frames/second and 1,280 px maximum processing edge.
## Not persistent storage or an identity provider
diff --git a/public/THIRD_PARTY_NOTICES.md b/public/THIRD_PARTY_NOTICES.md
index bb54595..35d3d8b 100644
--- a/public/THIRD_PARTY_NOTICES.md
+++ b/public/THIRD_PARTY_NOTICES.md
@@ -8,11 +8,12 @@ The release preparation step collates licence files for the exact locked runtime
| -------------------------------- | ------- | ---------- | ------------------------------- | ------------------------------------------- |
| `@add-ideas/toolbox-contract` | 0.2.3 | Apache-2.0 | manifest and context contract | https://git.add-ideas.de/lotobo/toolbox-sdk |
| `@add-ideas/toolbox-shell-react` | 0.2.3 | Apache-2.0 | shared shell, theme and actions | https://git.add-ideas.de/lotobo/toolbox-sdk |
+| `@noble/hashes` | 2.3.0 | MIT | local Aegis scrypt derivation | https://github.com/paulmillr/noble-hashes |
| `jsqr` | 1.4.0 | Apache-2.0 | local QR image decoding | https://github.com/cozmo/jsQR |
| `react` | 19.2.6 | MIT | application UI | https://github.com/facebook/react |
| `react-dom` | 19.2.6 | MIT | browser rendering | https://github.com/facebook/react |
-`scheduler`, distributed by the React project under MIT, is the only transitive runtime package. Exact licence texts, including jsQR's Apache-2.0 terms, are collated from the locked install into the release.
+`scheduler`, distributed by the React project under MIT, is the only transitive runtime package. Exact licence texts, including jsQR's Apache-2.0 and noble-hashes' MIT terms, are collated from the locked install into the release.
## QR construction
diff --git a/public/toolbox-app.json b/public/toolbox-app.json
index 84a53a2..da70991 100644
--- a/public/toolbox-app.json
+++ b/public/toolbox-app.json
@@ -3,7 +3,7 @@
"schemaVersion": 1,
"id": "de.add-ideas.auth-tools",
"name": "OTP & Passkey Tools",
- "version": "0.2.0",
+ "version": "0.3.0",
"description": "Generate, inspect and verify OTP credentials and test WebAuthn/passkey ceremonies locally in the browser.",
"entry": "./",
"icon": "./favicon.svg",
@@ -18,7 +18,9 @@
"fido2",
"passkey",
"attestation",
- "assertion"
+ "assertion",
+ "extensions",
+ "migration"
],
"integration": {
"contextVersion": 1,
diff --git a/src/components/HelpDialog.tsx b/src/components/HelpDialog.tsx
index 9d40c92..d7c5313 100644
--- a/src/components/HelpDialog.tsx
+++ b/src/components/HelpDialog.tsx
@@ -46,6 +46,12 @@ export function HelpDialog({
hash/digit profile. The timeline and drift finder are diagnostics;
HOTP counters must remain synchronized.
+
+ Migration QR codes and plaintext exports reveal OTP seeds. Aegis and
+ PSKC password decryption happens locally. Collection snapshots omit
+ seeds but include stable fingerprints that can correlate accounts.
+ Camera scanning starts only after your click and stops automatically.
+
Passkey inspection
Inspection is offline. Verification is layered: client-data
@@ -61,6 +67,11 @@ export function HelpDialog({
Toolbox origin remains inspect-only so unrelated apps do not share its
credential namespace.
+
+ Extension results are browser/authenticator capabilities, not security
+ guarantees. Redacted ceremony traces retain signed evidence for replay
+ and may therefore still contain correlatable identifiers.
+
+ Snapshots contain labels, parameters and stable SHA-256 secret
+ fingerprints—not the secrets themselves. Fingerprints can still
+ correlate credentials and should remain private.
+