Texts after the AIP-22 erratum of 2026-10-01 (an anchor certificate shows that its signers sealed the block post-quantum, not that it was decided); SD-JWT key-binding nbf probe and its negative control
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5f1e60b8d2
commit
f84a5e8c18
@ -10,7 +10,7 @@ notarization command of the verification layer, and the agents' x402 wallet (EIP
|
||||
| [`pq-kms/`](pq-kms/) | a transit-style key management service where every key is hybrid: X25519 + ML-KEM-768 for encryption, Ed25519 + ML-DSA-65 for signatures (both halves required); versions, rotation, rewrap, data keys, a chained audit log; the root key from the environment or sealed by an HSM through PKCS#11 |
|
||||
| [`pq-pki/`](pq-pki/) | a private certificate authority for ML-DSA (X.509 v3, RFC 9881): root and issuing CAs, leaf certificates, revocation lists, and a strict chain verifier compared against OpenSSL |
|
||||
| [`crypto-inventory/`](crypto-inventory/) | a cryptographic inventory of source code (JavaScript/TypeScript, Python, Java, Go, PEM blocks, dependency manifests): every use classified by its exposure to a quantum computer, with a migration target, written as a CycloneDX 1.6 CBOM; nothing from the scanned tree is executed, and its cost stays linear on input built to be slow |
|
||||
| [`verify-layer/`](verify-layer/) | an audit-log sidecar for any deployment: entries are AIP-23 envelopes in a hash chain, the runtime adapter records every running Docker or Kubernetes container without any secret value, and the head of the chain can be signed by the operator (ML-DSA-65) and notarized on Aere Network for post-quantum finality; it says plainly what that proves (the history before a published head) and what it does not (that the host told the truth); the same log as a Merkle tree (RFC 9162): signed tree heads, and inclusion and consistency proofs of a few hashes that anyone checks without the log |
|
||||
| [`verify-layer/`](verify-layer/) | an audit-log sidecar for any deployment: entries are AIP-23 envelopes in a hash chain, the runtime adapter records every running Docker or Kubernetes container without any secret value, and the head of the chain can be signed by the operator (ML-DSA-65) and notarized on Aere Network under a post-quantum validator certificate; it says plainly what that proves (the history before a published head) and what it does not (that the host told the truth); the same log as a Merkle tree (RFC 9162): signed tree heads, and inclusion and consistency proofs of a few hashes that anyone checks without the log |
|
||||
| [`proof-kinds/`](proof-kinds/) | the AIP-23 envelope builder the verification layer uses: fourteen proof kinds, one envelope format, digests instead of raw content |
|
||||
| [`readiness/`](readiness/) | the post-quantum readiness scanner of a public hostname: real TLS handshakes (hybrid only, hybrid preferred, TLS 1.2), HSTS, the certificate; no connection to an address not proven public; a rate limit per client that X-Forwarded-For cannot bypass |
|
||||
| [`control-plane/`](control-plane/) | from findings to a finished migration: a prioritized plan from the inventory and the scanner, its execution through the gateway, KMS and PKI with consent per action and a measured proof afterwards, recipes for the servers the products do not touch and a rescan that judges them, a compliance report against NIST IR 8547, the EU roadmap and optionally CNSA 2.0, and a console that checks it all again |
|
||||
|
||||
@ -155,7 +155,7 @@ button.ghost{border:1px solid var(--line2);background:transparent;color:var(--mu
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Post-quantum finality <span class="rule"></span></h2>
|
||||
<h2>Post-quantum certificate <span class="rule"></span></h2>
|
||||
<div class="ladder" id="ladder"></div>
|
||||
</section>
|
||||
|
||||
|
||||
@ -37,6 +37,8 @@ const PLANTARI = [
|
||||
['crit primit', "if (Object.hasOwn(antet, 'crit')) throw", 'if (false) throw', 'REVIZUIRE: crit'],
|
||||
['base64url necanonic primit', "if (b.toString('base64url') !== s) throw", 'if (false) throw', 'REVIZUIRE: crit'],
|
||||
['exp-ul KB nu se mai cere', 'if (K.exp !== undefined && (!Number.isFinite(K.exp) || acum >= K.exp)) return', 'if (false) return', 'REVIZUIRE: crit'],
|
||||
// 2026-10-01: a doua jumatate a "exp/nbf ale KB"; fara plantarea ei, paznicul scos lasa proba verde (masurat: 23/23)
|
||||
['nbf-ul KB nu se mai cere', 'if (K.nbf !== undefined && (!Number.isFinite(K.nbf) || K.nbf - clockSkewS > acum)) return', 'if (false) return', 'REVIZUIRE: crit'],
|
||||
['_sd_alg scos de la orice nivel', "!(sus && k === '_sd_alg')", "k !== '_sd_alg'", 'REVIZUIRE: crit'],
|
||||
['cheia publica Node nu mai e primita', "(k.type === 'public' ? k : crypto.createPublicKey(k))", 'crypto.createPublicKey(k)', 'REVIZUIRE: cheia emitentului'],
|
||||
['o afirmatie __proto__ primita (prototipul schimbat)', "if (Object.hasOwn(x, '__proto__')) throw", 'if (false) throw', 'ATAC: o afirmatie numita __proto__'],
|
||||
|
||||
@ -178,7 +178,7 @@ test('REVIZUIRE: tipul jetonului: un KB-JWT sau un JWT cu typ JWT dat drept jeto
|
||||
cere(bun.valid && bun.issuerChecked, 'emitentul asteptat refuzat');
|
||||
cere(refuz(J.verifySdJwt(arata(E.sdJwt, ['age_over_18']), { issuerKey: iss, audience: AUD, nonce: NONCE, now: LA, expectedIssuer: 'https://altul.example' }), /issued by/), 'alt emitent a trecut');
|
||||
});
|
||||
test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expirat -> refuzate; _sd_alg imbricat ramane afirmatie', () => {
|
||||
test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expirat sau inca nevalabil (nbf) -> refuzate; _sd_alg imbricat ramane afirmatie', () => {
|
||||
const corp = { iss: 'x', exp: NOW + 100, _sd_alg: 'sha-256', meta: { _sd_alg: 'x', note: 1 } };
|
||||
for (const crit of [[], 'b64', ['b64']]) cere(refuz(J.verifySdJwt(jwtDin({ alg: 'EdDSA', typ: J.TYP, crit, b64: false }, corp, iss.privat.ed25519) + '~', { issuerKey: iss, requireKeyBinding: false, now: LA }), /crit/), 'crit ' + JSON.stringify(crit));
|
||||
const j = jwtDin({ alg: 'EdDSA', typ: J.TYP }, corp, iss.privat.ed25519);
|
||||
@ -193,6 +193,13 @@ test('REVIZUIRE: crit (orice forma), base64url necanonic al semnaturii, KB expir
|
||||
const sh = crypto.createHash('sha256').update(Buffer.from(baza, 'ascii')).digest('base64url');
|
||||
const kbExp = jwtDin({ alg: 'EdDSA', typ: 'kb+jwt' }, { iat: NOW, aud: AUD, nonce: NONCE, sd_hash: sh, exp: NOW - 100 }, hol.privat.ed25519);
|
||||
cere(refuz(judeca(baza + kbExp), /key binding: expired/), 'KB expirat a trecut');
|
||||
// 2026-10-01: nbf-ul KB (a doua jumatate a reparatiei "exp/nbf ale KB" din B-32) nu avea proba: paznicul scos lasa proba 23/23.
|
||||
// Martorul aceluiasi KB facut de mana, cu nbf in toleranta de ceas, e VALID: refuzul de mai jos e al nbf-ului, nu al constructiei.
|
||||
const kbNbf = (nbf) => jwtDin({ alg: 'EdDSA', typ: 'kb+jwt' }, { iat: NOW, aud: AUD, nonce: NONCE, sd_hash: sh, nbf }, hol.privat.ed25519);
|
||||
const rNbfBun = judeca(baza + kbNbf(NOW + 30));
|
||||
cere(rNbfBun.valid, 'martorul: KB cu nbf in toleranta (30 s) trebuie sa fie VALID: ' + rNbfBun.reason);
|
||||
cere(refuz(judeca(baza + kbNbf(NOW + 600)), /key binding: not valid before/), 'KB inca nevalabil (nbf peste 10 minute) a trecut');
|
||||
cere(refuz(judeca(baza + kbNbf('maine')), /key binding: not valid before/), 'KB cu nbf necitibil a trecut');
|
||||
});
|
||||
|
||||
test('linia de comanda: verify-sdjwt pe prezentarea RFC 9901 s.5.2 -> 0 VALID la momentul ei (--at), 1 INVALID acum (KB vechi); o cheie privata -> 2', () => {
|
||||
|
||||
@ -13,7 +13,7 @@ const envelope = buildProof('runtime', { host, artifactContent, attested, matche
|
||||
A kind is a schema: its required fields, some of them digests, plus `createdAt`. Raw content given for a digest field is hashed
|
||||
(bytes as they are, strings as UTF-8, other values as their JSON text), and a value that is already a 32-byte digest is kept, so
|
||||
an envelope carries digests, never the raw content. A missing required field stops the build with an error instead of producing
|
||||
an incomplete envelope. Notarization and post-quantum finality come from AIP-23, not from this builder.
|
||||
an incomplete envelope. Notarization and the post-quantum certificate over it come from AIP-23, not from this builder.
|
||||
|
||||
Test: `node proba-proof-kinds.mjs` (24 checks: every kind built and found `VALID` by the reference verifier, six negative
|
||||
controls such as content changed after hashing or a required field missing, no raw content in any envelope, bytes hashed as
|
||||
|
||||
@ -4,7 +4,8 @@ A sidecar that runs next to a deployment, on any cloud or on premises, and keeps
|
||||
AERE Proof Protocol envelope (AIP-23), built by the same `proof-kinds` builder and checked by the same AIP-23 reference
|
||||
verifier as every other AERE proof, and every entry covers the hash of the one before it (an append-only hash chain,
|
||||
`hash = sha256(seq | prev | envelope)`, genesis `0x00..00`). The head of the chain can be notarized on Aere Network, which
|
||||
gives the history up to that head post-quantum finality that anyone can check.
|
||||
binds the history up to that head under a post-quantum validator certificate that anyone can check (what such a
|
||||
certificate proves, and what it does not, is in the AIP-22 erratum of 2026-10-01).
|
||||
|
||||
Node.js 24, no dependencies; `notarize-head` alone needs `ethers` (`npm install` in this directory).
|
||||
|
||||
@ -17,8 +18,8 @@ Node.js 24, no dependencies; `notarize-head` alone needs `ethers` (`npm install`
|
||||
`verify-log` on that file alone reports it intact. A partial edit is caught (the chain breaks at the edited entry and
|
||||
`verify-log` names it), a full rewrite is not.
|
||||
- **What is checkable without trusting the host is the history before a published head.** `attest-head` turns the current
|
||||
head into an envelope; `notarize-head` records its hash on the AereNotary contract; the AIP-23 reference verifier then gives
|
||||
it post-quantum finality (the most recent certified anchor, the parent header bound by hash, its state root, and a Merkle
|
||||
head into an envelope; `notarize-head` records its hash on the AereNotary contract; the AIP-23 reference verifier then shows
|
||||
it under a post-quantum certificate (the most recent certified anchor, the parent header bound by hash, its state root, and a Merkle
|
||||
proof of `firstSeen[statementHash]`). `verify-log --attested <head.json>` requires that today's log **continues** that head:
|
||||
the same first `count` entries, the entry `count - 1` hashing to the attested head. A rewritten or shortened history fails.
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user