Articoli approfonditi sulla tecnologia che plasma il futuro.

Le chiavi CA deboli di eMudhra: 5 miti sulla PKI, smentiti

Una CA fidata ha spedito chiavi private violabili in millisecondi. Cinque miti su PKI, generazione delle chiavi e audit, alla prova del caso eMudhra.

Un enorme portone blindato di una cassaforte protetto solo da un piccolo lucchetto giocattolo
Diciassette mesi di sicurezza di una certificate authority poggiavano su otto bit di entropia.

La chiave privata di una delle CA di eMudhra è il numero 4. Non un numero a 384 bit che inizia con 4: proprio 4, con 47 byte a zero a imbottirlo per farlo sembrare rispettabile. È un errore nella generazione delle chiavi di una certificate authority che avrei definito impossibile, e che è sopravvissuto ad audit, alla cross-signature di Sectigo e a diciassette mesi di infrastruttura quasi in produzione, prima che qualcuno provasse la cosa più ovvia: un brute force su un singolo byte. Ecco cinque convinzioni sulla PKI che questo incidente demolisce senza pietà.

Mito 1: «Un certificato strutturalmente valido è un certificato sicuro»

Ogni controllo automatico nella pipeline diceva che quei certificati erano a posto. E in un senso stretto e inutile, avevano ragione. La chiave pubblica corrispondente a d = 4 è un punto perfettamente valido sulla curva P-384. La codifica ASN.1 viene parsata. La firma viene verificata. La catena si costruisce. Ogni linter, ogni validatore strutturale, ogni checklist di conformità che scorre un certificato e verifica che sia ben formato lo lascerà passare, perché è davvero ben formato.

Qui sta la trappola. La validazione strutturale risponde alla domanda «questo è un certificato formattato correttamente?». Non risponde a «la chiave al suo interno è stata generata correttamente?». Per una chiave a curva ellittica sono proprietà quasi completamente indipendenti. La chiave privata è semplicemente uno scalare d; la chiave pubblica è d × G, dove G è il punto generatore della curva. Tutta l'argomentazione di sicurezza si regge sul fatto che recuperare d dal punto pubblico richiede di risolvere il problema del logaritmo discreto, ma solo se d è stato scelto dall'intero spazio a 384 bit. Se lo scegli da 8 bit, il problema «impossibile» diventa un ciclo che gira al massimo 255 iterazioni.

Nulla nel certificato risultante lascia intuire il problema. Il punto pubblico derivato da d = 4 sembra esattamente casuale quanto quello derivato da una chiave generata correttamente. Non puoi capirlo a occhio. Non puoi verificarlo con un linter. L'unico modo per saperlo è provare valori piccoli e pattern noti come deboli, ed è esattamente ciò che è successo: il segnalatore ha eseguito la suite di test paranoid_crypto di Google sul corpus del Common CA Database, così com'è, e ha trovato un riscontro. Un controllo che richiede millisecondi su un laptop, su chiavi che ancorano la fiducia dei browser reali.

Quindi la prima lezione: la validità è necessaria, ma tutt'altro che sufficiente. Se i tuoi test PKI si fermano a «il certificato viene parsato e si concatena», stai testando la busta e ignorando la lettera.

Mito 2: «Requisiti di base e audit intercettano i bug nella generazione delle chiavi»

Le CA operano secondo i Baseline Requirements del CA/Browser Forum e vengono sottoposte ad audit secondo i criteri WebTrust o ETSI. Ci sono documentazioni delle cerimonie, requisiti per gli HSM, requisiti sulla lunghezza delle chiavi. Le chiavi di eMudhra avevano la lunghezza giusta: 384 bit sulla carta. Il vuoto dell'audit sta nel fatto che la conformità verifica la rappresentazione della chiave, non l'entropia del processo che l'ha prodotta. Una chiave imbottita con 47 byte a zero occupa comunque 48 byte su disco.

Secondo il resoconto dello stesso eMudhra, pubblicato sul ticket di incidente di Mozilla, la causa radice sembra una commedia nera: un bug nello script della cerimonia ha generato una seconda coppia di chiavi debole sull'HSM; le due coppie avevano nomi simili; una persona ha scelto quella sbagliata per la CSR. Tre fallimenti separati (un bug nello script, una collisione di nomi, un errore di selezione) e in nessun momento un controllo si è chiesto «questa chiave ha davvero l'entropia per cui abbiamo pagato l'HSM?».

Questa è la parte che dovrebbe preoccupare ogni ingegnere che gestisce una PKI interna. Se una CA pubblicamente fidata, con i programmi root che le stanno col fiato sul collo e gli audit in calendario, può distribuire una chiave privata uguale a 4, cosa c'è dentro il backend PKI di Vault o nei template di Active Directory Certificate Services? La correzione costa poco e non c'è scusa per non applicarla. Dopo aver generato una chiave, e prima di firmare qualsiasi cosa con essa, passala attraverso paranoid_crypto o almeno un banale controllo di sanità:

from cryptography.hazmat.primitives.asymmetric import ec
CURVE_ORDER_BITS = 384
def sanity_check_private_key(key: ec.EllipticCurvePrivateKey) -> None:
d = key.private_numbers().private_value
# Reject keys whose effective entropy is far below the curve size.
# A healthy P-384 key should have a bit length close to 384.
if d.bit_length() < CURVE_ORDER_BITS - 32:
raise ValueError(
f"Suspiciously small private scalar: {d.bit_length()} bits"
)
# Also reject known bad values outright.
if d < 2**16:
raise ValueError("Private scalar is trivially brute-forceable")

Trenta secondi di lavoro. Avrebbe intercettato ognuna delle otto chiavi di eMudhra. Gli audit verificano che i processi esistano; non verificano che abbiano funzionato in un qualsiasi martedì di aprile. Solo il test sull'output lo fa.

Mito 3: «Una chiave CA compromessa può essere contenuta»

Quando una chiave CA viene «compromessa» nel senso usuale, c'è un ladro. Qualcuno ha esfiltrato la chiave in un momento preciso, e puoi ragionare sul raggio d'azione: i certificati emessi dopo il furto, da parti in possesso della chiave rubata. Brutto, ma limitato. Abbiamo già scritto di cosa succede quando la compromissione di una CA intermedia spezza una catena di fiducia, e il manuale standard (revoca, distrust, riemissione) presuppone un prima e un dopo.

Questo incidente non ha un prima e un dopo. La chiave era di fatto pubblica dal momento in cui il certificato è stato creato, perché chiunque l'avesse osservato poteva recuperarla in millisecondi. Non c'è un evento di furto da delimitare. La finestra coincide con l'intera vita dei certificati, da aprile 2025 in poi, e non c'è modo di sapere chi, se qualcuno, sia passato dalla porta aperta. La dichiarazione di eMudhra secondo cui le intermedie non hanno emesso certificati per entità finali, confermata dai log di Certificate Transparency, è davvero rassicurante per ciò che quelle CA hanno fatto. Non dice nulla su ciò che chiunque avesse d=4 avrebbe potuto fare in modo opportunistico lungo un percorso di rete.

Peggio ancora, la risposta non può arrivare del tutto. Chrome e Firefox hanno bloccato le intermedie in poche ore tramite CRLSet e OneCRL, e poiché entrambi richiedono il logging in CT, i certificati TLS falsificati non sarebbero comunque stati validati in quei browser. Bene. Ma questa protezione finisce al confine del browser, e ci porta al mito successivo.

Mito 4: «Se i browser sono al sicuro, lo è tutto l'ecosistema»

Una finestra di browser corazzata e luminosa, circondata da centinaia di dispositivi connessi esposti nel buio
I browser sono stati patchati in poche ore; tutto il resto dell'ecosistema TLS è ancora esposto.

I browser sono lo scenario migliore nell'ecosistema TLS, e rappresentano una minoranza dei client TLS che contano davvero dal punto di vista operativo. Pensa a cosa stabilisce effettivamente le connessioni HTTPS nella tua infrastruttura: curl, requests di Python, Node, binari Go, servizi Java, git, package manager, SDK cloud. Questi client condividono tre caratteristiche che qui si sommano male: si fidano di un bundle di CA su disco, non controllano la revoca per impostazione predefinita e non verificano la Certificate Transparency. Tutte e tre le protezioni che hanno salvato gli utenti di Chrome sono assenti.

Scott Helme lo ha dimostrato concretamente: con un certificato falso per api.stripe.com concatenato a una delle intermedie deboli di eMudhra, curl di default riportava SSL certificate verify ok, Python completava l'handshake, Node segnalava la connessione come autorizzata e Windows CryptoAPI accettava la catena. Su ogni macchina Linux e macOS testata. Un certificato falso per qualsiasi hostname, accettato dagli strumenti predefiniti su cui sono costruiti i tuoi script di deploy e i runner CI. Non è un problema del browser; è un problema della tua infrastruttura.

La mappa dell'esposizione è peggiore di quanto la maggior parte delle persone immagini:

  • Installer curl | sh e self-updater. rustup, nvm, l'installer di Homebrew, innumerevoli pagine «install.sh». Un certificato falso qui significa eseguire codice dell'attaccante, spesso come root.
  • Pipeline CI/CD. I runner scaricano dipendenze e pubblicano artefatti mentre detengono credenziali cloud e chiavi di firma, spesso su immagini base non aggiornate.
  • Traffico server-to-server. Webhook di pagamento, scambi di token OAuth, chiamate SDK cloud che trasportano segreti negli header.
  • IoT e dispositivi embedded. Firmware congelati con bundle di CA che non cambieranno finché i certificati non scadranno, a luglio 2039.
  • Code signing su Windows. Due delle otto chiavi deboli appartenevano a CA per il code signing; il malware firmato con esse sembra software di un editore legittimo.

Il consiglio pratico è noioso e corretto: aggiorna tutto ciò che distribuisce un bundle di CA. Il pacchetto ca-certificates del sistema operativo, certifi, Node, Homebrew, e ricostruisci le immagini dei container una volta che le immagini base recepiscono la revoca, perché i layer ricordano. La parte non risolvibile è il dispositivo che non puoi aggiornare. Quella smart TV continuerà a fidarsi di una chiave uguale a 4 per un altro decennio e mezzo. Se ti serviva un altro argomento per segmentare la rete dei dispositivi IoT, eccolo.

Mito 5: «Qualcuno dovrebbe già controllarlo»

La frase più silenziosamente sconfortante dell'incidente è venuta dal segnalatore: la scoperta è arrivata eseguendo paranoid_crypto sul corpus CCADB come test rapido sul corpus, prima di passare ai certificati dei sottoscrittori. La frutta a portata di mano. Parole del segnalatore: «Gran parte del mio tempo è stato speso a rivedere le basi che tutti davano per scontato fossero già state fatte da qualcun altro: un errore critico da commettere in un contesto di sicurezza».

Rileggilo. Otto chiavi private di CA (i gioielli di una autorità pubblicamente fidata, cross-firmate nella root AAA Certificate Services di Sectigo) sono rimaste vulnerabili al brute force per diciassette mesi, e sono state trovate non da un auditor, non da un programma root, non dalla CA stessa, ma da una persona che eseguiva uno strumento open source così com'era. L'ecosistema nel suo insieme dava per scontato che le basi fossero coperte. Nessuno le aveva coperte.

Questo è un pattern più ampio nell'infrastruttura di sicurezza, ed è il motivo per cui continuo a insistere sull'ingegneria difensiva, cioè sistemi che resistono alle catastrofi, anziché su sistemi che presuppongono un funzionamento corretto. I controlli che avrebbero intercettato questo problema costano così poco da risultare quasi imbarazzanti:

  1. Esegui paranoid_crypto o controlli equivalenti sulle chiavi deboli al momento della generazione e su ogni CSR prima della firma.
  2. Verifica l'entropia empiricamente: controlla la lunghezza in bit dello scalare privato e rifiuta qualsiasi valore con un'entropia effettiva implausibilmente bassa, come nel codice d'esempio sopra.
  3. Testa la cerimonia, non solo la configurazione. Simula le tue cerimonie di gestione delle chiavi e ispeziona gli artefatti reali prodotti, incluso quale oggetto HSM con nome finisce nella CSR.
  4. Scansiona in modo continuo i certificati emessi, non solo i template. Il certificato è la verità di riferimento; tutto ciò che sta a monte è intenzione.

Il certificato è la verità di riferimento. Tutto il resto (script, cerimonie, audit) è solo intenzione.

Otto bit sono tutto ciò che serve

C'è qualcosa di quasi rassicurante in una catastrofe con una causa così stupida. Un bug in uno script, due chiavi con nomi simili su un HSM, una persona che sceglie quella sbagliata: nessuno stato-nazione, nessuna crittanalisi innovativa, solo un episodio dei Tre Stooges con una miccia di diciassette mesi. Ma la stupidità è il monito. Se l'anello più debole di una CA pubblicamente fidata può essere un singolo byte, allora la robustezza della tua PKI non dipende dalla scelta della curva o dal budget per l'HSM. Dipende dal fatto che qualcuno, in un punto qualsiasi della pipeline, abbia davvero testato l'output.

I fornitori dei browser hanno fatto la loro parte nel giro di poche ore. Il resto tocca a noi: controlla la generazione delle tue chiavi, esegui i controlli economici, aggiorna ogni bundle di CA che riesci a raggiungere e segmenta i dispositivi che non puoi aggiornare. E smetti di dare per scontato che qualcun altro abbia già verificato le basi. In materia di sicurezza, è l'ipotesi più costosa che esista.