Commit Graph

9 Commits

Author SHA1 Message Date
Aere Network
5f1e60b8d2 identity: verify-sdjwt on the command line (an SD-JWT+KB checked with the issuer key you give; Aere Cloud runs it behind POST /v1/identity/sd-jwt/verify)
The issuer key (a public JWK, or the public keys of an AERE identity) is checked first: one that cannot be read, is private, or is not
a key for the algorithm asked exits 2 with the reason, instead of reporting the token INVALID. --json prints compact JSON (indented
output grew with the square of the claims' nesting depth). --at judges at a given time, as for verify. Test on the RFC 9901 example
presentation: valid at its own time, invalid now, a private key refused. Tests: SD-JWT 23/23, negative control 28/28; identity 44/44,
negative control 49/49.
2026-09-30 13:17:07 +03:00
Aere Network
4ffec8d7e3 identity: standard SD-JWT (IETF RFC 9901) from the same keys - issue, present with key binding, verify
sdjwt.mjs: an issuer-signed JWT with the digests of the disclosable claims (_sd, list elements as {"...": digest}, _sd_alg sha-256),
the holder's key in cnf.jwk and exp, followed by the disclosures; the holder keeps the ones it picks and adds a Key Binding JWT
(kb+jwt, aud, nonce, iat, sd_hash); the verifier follows RFC 9901 sections 7.1 and 7.3 with the issuer key it chose, and requires its
audience and nonce, exp, and an explicitly typed token. Algorithms: ES256, EdDSA (Ed25519, the key every AERE identity has) and
ML-DSA-65 (JWK type AKP, names from the IETF draft draft-ietf-cose-dilithium, not yet a published standard).

Checked against the standard's own vectors (fixturi-rfc9901.json, from RFC 9901 Section 5 and Appendix A.5): the ten example
disclosure digests, the example SD-JWT signed by someone else with the A.5 key, and the example presentation with key binding, which
gives exactly the processed payload printed in the RFC. Not checked against another SD-JWT library.

An adversarial review before publication found ten defects, all fixed with a test and a planted negative control each (among them:
the issuer signed SD-JWT structure coming in claim values; the holder revealed an element with the same value from any list; audience
and nonce were not required). Tests: SD-JWT 22/22, negative control 28/28; identity 44/44.
2026-09-30 12:37:17 +03:00
Aere Network
6c42fb2c0b identity: the compliance record's evidence digest is the digest of the presentation's signed binding
Before, it was the digest of the whole presentation object, so an unsigned top-level field added by anyone changed it without
changing anything signed, and the digest did not name one presentation. The binding names, by hash, the whole credential, the
disclosures, the delegation chain, the audience, the nonce and the time; the signature is left out (ML-DSA signs with randomness,
so one binding can carry many valid signatures).

Tests: compliance 15/15, negative control 14/14.
2026-09-30 11:46:51 +03:00
Aere Network
0b56d8e5df identity: 60 s of clock allowance on starts (validFrom, notBefore) and, the careful way, on revocations; none on ends
A credential issued on a machine whose clock was one second ahead was "not yet valid" at a verifier synchronized by NTP: measured on
2026-09-30 through the Aere Cloud identity route, the first time a credential was issued on one machine and judged on another.
Starts (a credential's and a status list's validFrom, a delegation's notBefore) are now accepted up to 60 s in the verifier's future
(verifyPresentation clockSkewS, 0..600); a revocation dated up to 60 s ahead already applies; ends (validUntil, notAfter) get no
allowance, since that would extend a validity.

Tests: identity 44/44, negative control 49/49.
2026-09-30 11:36:02 +03:00
Aere Network
aec0ccbead identity: verify and comply as a service can judge (--json, --at), subject in the result, refused input exits 2
- verify: --at <RFC 3339 UTC> judges on that clock (the verifier's clock in any case), so a verdict given at one moment can be checked
  again later with the same result; a broken --trust-issuer or --max-age exits 2 with the reason instead of failing without a verdict;
  the JSON result names the subject (type, credential, issuer, holder, presenter, delegations) when no check failed
- comply: --json [--with-record] prints the result and the record in one object; with --at the record's time is the same, so the same
  command gives the same record byte for byte; a refused policy exits 2 with its reason
- Aere Cloud runs this command line unmodified behind POST /v1/identity/verify and POST /v1/compliance/check

Tests: identity 43/43, negative control 46/46.
2026-09-30 11:16:37 +03:00
Aere Network
8f5f0bd00d verify-layer: verify-consistency names the signer of each head (or unsigned); identity: Travel Rule requires a replay store
- verify-consistency without --signer now says whether each head is signed and by which key, and that no expected signer was
  checked (verify-inclusion already did; the README said the output does)
- openMessage opens nothing without a replay store (seen: an object with has/add that keeps the ids for at least maxAgeS);
  before, the same signed and sealed message could be opened any number of times when no store was given

Tests: verify-layer tree 20/20, negative control 14/14; sidecar 44/44, 9/9; travel rule 19/19, negative control 19/19.
2026-09-30 10:31:23 +03:00
Aere Network
f75c33454a identity: the Travel Rule between VASPs, post-quantum - IVMS101 data sealed for the receiving VASP (X25519 + ML-KEM-768), signed, bound to the transfer and acknowledged; both VASPs proven by registry credentials 2026-09-30 10:02:39 +03:00
Aere Network
154c424e94 identity: compliance without surveillance - a verifier's policy judged on a presentation, recorded as an AIP-23 envelope that carries no personal data 2026-09-30 09:52:16 +03:00
Aere Network
b5e1628265 identity: post-quantum credentials with selective disclosure, delegation that can only narrow, revocation and an issuer status list, checked offline from the files 2026-09-30 09:18:53 +03:00