Verificare una prova offline
01Cosa permette questo documento #sec_e0af9bcf
REVIEWIT produce, ad ogni firma, un'attestazione sigillata da cui si può estrarre un pacchetto di verifica: un file che contiene tutto ciò che serve per rifare la dimostrazione altrove.
Questo documento è la specifica completa di questo formato. È pubblicato per una ragione precisa: permettere a un terzo di verificare una prova senza di noi, e anche senza crederci. Descrive abbastanza esattamente la canonicalizzazione, la costruzione degli alberi e la verifica delle prove di inclusione in modo che un auditor, una direzione dei sistemi informativi o uno studio indipendente possa scrivere il proprio verificatore e ottenere lo stesso verdetto del nostro.
È la forma più alta della garanzia che REVIEWIT annuncia. Una piattaforma che direbbe « fidati di noi, è sigillato » chiederebbe esattamente ciò che questo documento rende inutile.
02A chi si rivolge #sec_c1bc9732
A un lettore tecnico: la persona che verificherà una prova, o quella che scriverà lo strumento che la verifica. Non è necessario per leggere un rapporto di audit, né per utilizzare REVIEWIT.
Un auditor che desidera solo ottenere un verdetto non deve leggere questo testo: la schermata « Verificare una prova » del Workspace Center e lo strumento da riga di comando applicano questo contratto, senza deviazioni. Questo documento esiste per coloro che si rifiutano di affidarsi all'uno o all'altro — e hanno ragione di poterlo fare.
03Cosa vi serve #sec_48297a56
Quattro elementi, e non provengono dallo stesso posto:
- Il pacchetto di verifica — il file stesso. Vi viene consegnato con la prova che vi viene opposta, o lo scaricate da REVIEWIT.
- Un verificatore — quello che scrivete a partire da questo documento, o quello che REVIEWIT mette a disposizione. Entrambi devono rendere lo stesso verdetto; se divergono, è un difetto, e ci riguarda.
- Il portachiavi pubblico dell'autorità — servito da questo portale all'indirizzo /.well-known/seal-keyring.json, e consegnato con l'appendice sicurezza del vostro contratto. Porta le chiavi pubbliche con le quali si controlla la firma del sigillo, e solo essa. Tutto il resto — l'impronta, le radici di Merkle, il chaining, la prova di inclusione — si verifica senza alcuna chiave, dal solo file.
- L'impronta della chiave radice — portata dall'appendice sicurezza firmata con il vostro contratto. È lei, e solo lei, che stabilisce che il portachiavi che avete scaricato è proprio il nostro (§8.3).
04Cosa stabilisce il file da solo, e cosa non stabilisce #sec_192edcae
Senza portachiavi, un pacchetto rimane interamente verificabile nella sua coerenza interna: che il manifesto produca bene l'impronta annunciata, che le liste producano bene le radici attestate, che un elemento dato figuri bene nel perimetro sigillato.
Cosa il file da solo non stabilisce, è che questo contenuto è stato sigillato da noi. Un pacchetto può dichiararsi sigillato senza esserlo: questa dichiarazione non vale nulla finché la firma dell'autorità non è stata controllata con la sua chiave pubblica. Un verificatore conforme deve quindi distinguere questi due constatati e non presentare mai il secondo come acquisito a partire dal primo.
051. Canonicalizzazione, versione 1 #sec_53b1cef4
Un documento canonico è un JSON UTF-8 senza BOM, senza spazio né ritorno a capo, tale che:
- le chiavi di un oggetto sono ordinate per ordine ordinale dei punti di codice;
- le stringhe sono normalizzate Unicode NFC; solo ", \ e i caratteri di controllo sono escapati; il non-ASCII non è escapato;
- gli unici numeri sono interi firmati su 64 bit; nessun float; una proporzione si esprime per diecimila;
- gli istanti sono in tempo universale, nel formato yyyy-MM-ddTHH:mm:ss.ffffffZ — sei decimali, il settimo troncato; le date civili nel formato yyyy-MM-dd;
- un valore non applicabile è assente; non esiste né null, né stringa vuota al posto dell'assenza;
- le sequenze di ottetti sono in esadecimale minuscolo.
Un documento contenente un null, un float o una chiave duplicata non è un documento canonico ed è rifiutato.
062. Hashing #sec_9d21b1bf
SHA-256, identificatore "SHA-256" portato in cryptography.hash del manifesto.
073. Schema ad albero, versione 1 #sec_3b2d707a
| Elemento | Definizione | |
|---|---|---|
| Prefissi di dominio | foglia 0x00, nodo 0x01, albero vuoto 0x02, radice 0x03 | |
| Foglia | H(0x00 ‖ aleatorio ‖ contenuto) — l'aleatorio fa 32 ottetti, proprio di ogni foglia | |
| Nodo | H(0x01 ‖ sinistra ‖ destra) | |
| Livello dispari | il nodo orfano è promosso tale quale al livello superiore, mai duplicato | |
| Impegno | oggetto canonico `{"domain":{"empty":2,"leaf":0,"node":1,"root":3},"hash":"SHA-256","leafCount":n,"schema":1,"tree":"scope" | "decisions"}` |
| Radice pubblicata | H(0x03 ‖ impegno ‖ radice grezza) per n ≥ 1 | |
| Radice del lotto vuoto | H(0x02 ‖ impegno) con leafCount = 0 |
Ordine delle foglie. Chiave composita (SHA-256(identità), identità), confrontata ottetto per ottetto in lessicografico non firmato, il secondo termine non spartendo che le uguaglianze del primo. Due identità identiche in un lotto sono un rifiuto.
Due alberi. scope : il contenuto della foglia è l'identità stabile canonica {"criterion":…,"object":…,"type":…} . decisions : il contenuto è la decisione canonica (§5). Stesso ordine, stessa posizione per un medesimo elemento.
Aleatori. Derivati da SEAL dalla generazione cryptography.secretGeneration, per (albero, posizione). Il segreto non figura in nessun pacchetto.
084. Prova d'inclusione #sec_b535f3ee
{"commitment":{…},"content":hex,"path":[{"side":"left"|"right","sibling":hex} | {"promoted":true} …],"position":p,"root":hex,"salt":hex,"schema":1}
Verifica : ricalcolare la foglia, risalire il cammino esigendo a ogni livello esattamente ciò che la struttura impone — un fratello dal lato giusto quando l'indice ha un vicino, una promozione quando l'indice è l'ultimo di un livello dispari —, poi H(0x03 ‖ impegno ‖ nodo) e confrontare alla radice attestata. Un cammino più corto o più lungo della struttura è un rifiuto.
095. Manifesto, versione 1 #sec_9dbbc182
Blocchi dell'oggetto radice (chiavi ordinate) : actors, context, cryptography, decisions, governance, header, qualification, scope, snapshot, statement.
- header : attestation, canonicalization (1), complementRank, lot, originLot (assente per il lotto iniziale), schema (1).
- decisions[i] : actor, decidedAt, exceptionUntil, identity, justification, origin ( human | defaultRule | systemClosure | nonDecidedUncovered ), previous, rule ( id, motive, version — presente se e solo se l'origine non è umana), verdict .
- qualification : closure, conflictOfInterest, coverage ( complete ), decisionMode, origins (quattro conteggi, calcolati).
- governance.indicators : i quattro interi con collected:true, o {"collected":false} .
- cryptography : hash, preflight ( {"state":"unavailable"} o riferimento), secretGeneration, trees.scope e trees.decisions ( commitment, root ).
Forma sigillata. L'impronta sigillata — quella che l'ancoraggio porta — è SHA-256 della forma canonica dove scope e decisions sono sostituiti dal loro impegno {"count":n,"hash":SHA-256(lista canonica)} . Le liste non viaggiano che nel pacchetto completo ; le radici di Merkle le impegnano già.
106. Pacchetti #sec_de906bc8
| Campo | Completo | Puntuale |
|---|---|---|
| specification | REVIEWIT-SignOff-Verification/1 | idem |
| kind | complete | puntuale |
| attestation | forma sigillata | forma sigillata |
| digest | SHA-256(attestation) | idem |
| scope.items, decisions | liste complete, in ordine canonico | — |
| salts.scope, salts.decisions | tutti gli aleatori, per posizione | — |
| proof | — | una prova, con l'aleatorio della sola foglia svelata |
| sealing | {"state":"unanchored"} ; o anchored con domain, segment, rank, anchoredAt, seal:"pending" ; o sealed con in più seal.reference, seal.sealedAt | idem |
117. Procedura #sec_9a00ec24
- Rileggere il pacchetto come documento canonico (§1) ; rifiutare sennò.
- Verificare specification.
- Ricalcolare SHA-256(attestation) e confrontarlo a digest, e all'impronta tenuta altrove il caso occorra.
- Verificare header.schema, header.canonicalization, cryptography.hash.
- Completo : verificare gli impegni delle due liste ; verificare che a ogni posizione la decisione porta l'identità dell'elemento ; ricostruire ogni albero dalla lista e gli aleatori (§3) e confrontare radice e leafCount a cryptography.trees.
- Puntuale : verificare che la prova mira la radice e il leafCount attestati per il suo albero ; verificare la prova (§4).
- Leggere sealing.state e restituirlo tale quale : questa versione non verifica né l'ancoraggio né il sigillo, e un pacchetto unanchored non è opponibile.
Un pacchetto è valido quando tutti i controlli eseguiti riescono. Ciò non stabilisce che sia sigillato.
128. Portachiavi pubblico e ancoraggio per chiave radice #sec_71a42b6e
Il sigillo di un pacchetto si verifica con la chiave pubblica dell'autorità, pubblicata in un portachiavi : un file JSON, indipendente dai pacchetti, che il terzo detiene.
{
"keys": [ { "kid": "signing:1", "alg": "ecdsa-p256-sha256", "spki": "<DER SubjectPublicKeyInfo, base64>" } ],
"attestation": {
"version": "seal.keyring.v1",
"count": 1,
"digest": "<hex>",
"alg": "ecdsa-p256-sha256",
"rootKid": "keyring-root:1",
"rootSpki": "<DER SubjectPublicKeyInfo de la racine, base64>",
"signature": "<base64>"
}
}
Il pacchetto nomina la sua chiave, il portachiavi la fornisce. sealing.seal.keyId designa l'entrata da impiegare. Un'entrata non è mai ritirata da un portachiavi : ritirarla renderebbe inverificabili tutte le prove che ha sigillate.
8.1 Impronta del contenuto
Ritenere le entrate portanti al tempo stesso kid, alg e spki — un'entrata incompleta non conferisce alcuna chiave e non entra nel calcolo. Le ordinare per kid, in confronto ordinale sui punti di codice. Formare una linea per entrata, kid | alg | spki seguita da un salto di linea U+000A. L'impronta è lo SHA-256 della concatenazione UTF-8 di queste linee, in esadecimale minuscolo.
La data di creazione di un'entrata, se figura, non entra nel calcolo : è un istantaneo di visualizzazione.
8.2 Vettore firmato dalla radice
seal.keyring.v1|<nombre d'entrées retenues>|<empreinte du contenu>
Firmato in forma testo, codificato in UTF-8, dalla chiave radice, secondo attestation.alg. Le suite ammesse sono quelle del sigillo : ecdsa-p256-sha256 (firma ASN.1 DER, RFC 3279) e rsa-pkcs1-sha256 . Un algoritmo sconosciuto è un rifiuto, mai un'ammissione.
8.3 Ciò che il terzo detiene, e perché la radice
L'ancora del dispositivo è l'impronta della chiave radice — SHA-256 del suo SubjectPublicKeyInfo DER, in esadecimale minuscolo — portata dall'allegato sicurezza che il cliente firma con il suo contratto.
Porta sulla radice, mai sul file. Un portachiavi cresce : ogni rotazione di chiave di sigillamento vi aggiunge un'entrata. Un'impronta del file si perimererebbe dunque alla prima rotazione, e un revisore detenendo il buon file, perimato, vedrebbe cadere una prova autentica. La radice, lei, non cambia ; l'allegato firmato non è mai riaperto.
8.4 Procedura di verifica di un portachiavi
- Ricalcolare l'impronta del contenuto (§8.1) e il numero di entrate ritenute, e confrontarle a attestation.digest e attestation.count. Ricalcolare prima, verificare la firma poi : controllare la firma sull'impronta dichiarata lascerebbe passare un portachiavi di cui si sono cambiate le chiavi conservando il blocco firmato.
- Verificare attestation.signature sul vettore (§8.2) con attestation.rootSpki .
- Confrontare l'impronta di attestation.rootSpki a quella che porta l'allegato.
Sei esiti, e uno solo è opponibile :
| Esito | Ciò che è stabilito |
|---|---|
| Portachiavi ancorato | Firma verificata e radice conforme all'allegato. Solo stato opponibile. |
| Firmato, radice non controllata | Nessuna impronta d'allegato fornita : coerenza interna soltanto — chiunque può firmare un portachiavi con la sua propria radice. |
| Firmato da un'altra radice | Il file non è quello che l'allegato designa. |
| Alterato | Il contenuto non produce più l'impronta attestata. |
| Attestazione invalida | La radice dichiarata non ha firmato questo contenuto. |
| Non ancorato | Nessun blocco attestation — un portachiavi anteriore al dispositivo. Non è una colpa ; è un file senza ancora. |
Un portachiavi non ancorato permette sempre di controllare un sigillo. Ciò che non permette, è di stabilire da dove viene la chiave pubblica impiegata — e una firma verificata con una chiave di provenienza sconosciuta non stabilisce nulla.