Al final del mòdul 4 vam deixar una frase incòmoda flotant en l'aire: tota la matemàtica és impecable, però descansa sobre una suposició sense verificar — que la clau pública que tens és de qui creus. MalloryClinic no necessita trencar RSA ni Curve25519: li basta colar-te la seva clau pública fent-se passar per la Clínica Sol. En aquesta lliçó construïm per fi la peça que falta: el certificat digital X.509, un document que lliga una clau pública a una identitat amb la signatura d'un tercer de confiança. Aprendràs a llegir certificats reals amb openssl i amb Python, entendràs la cadena de confiança que va del teu navegador fins a una autoritat arrel, generaràs una CSR per a portal.medinube.example i muntaràs una mini-PKI de laboratori. En acabar, l'atac de MalloryClinic de la lliçó 04-04 deixarà de funcionar — i sabràs exactament per què.
Contingut
- L'esquerda de la confiança: quin problema resol un certificat
- Anatomia d'un certificat X.509
- Inspeccionar un certificat real amb
openssli amb Python - La cadena de confiança: arrel, intermèdia i fulla
- Autoritats de certificació: per què funciona el model (i quan ha fallat)
- La CSR: demanar un certificat per a portal.medinube.example
- Tipus de validació: DV, OV i EV
- Mini-PKI de laboratori per a MediNube
- Com això derrota MalloryClinic
L'esquerda de la confiança: quin problema resol un certificat
Recapitulem el problema amb precisió. A 04-04, la Clínica Sol volia establir un canal xifrat amb MediNube fent servir X25519. MalloryClinic es va posar al mig i va interceptar l'intercanvi de claus públiques:
- A la clínica li va lliurar la seva clau pública dient "sóc MediNube".
- A MediNube li va lliurar una altra clau seva dient "sóc la Clínica Sol".
Cap primitiva del curs detecta això, perquè una clau pública, per si sola, és només un número. No diu de qui és. Les signatures de 04-03 tampoc ajuden per si soles: verificar la signatura de la Dra. Ferrer exigeix tenir la seva clau pública autèntica... que és exactament el mateix problema, un esglaó més amunt.
La solució no és una primitiva nova. És un document:
Certificat digital = clau pública + identitat + signatura d'un tercer de confiança.
És a dir: algú en qui ambdues parts ja confien (l'Autoritat de Certificació, CA) examina l'evidència que una clau pública pertany a una identitat ("aquest domini", "aquesta empresa") i ho deixa per escrit, signat amb la seva pròpia clau privada, fent servir exactament les signatures digitals que ja domines de la lliçó 04-03. Qui rebi el certificat pot verificar aquesta signatura i, si confia en la CA, confiar en l'associació clau↔identitat.
Fixa't que no hem inventat criptografia nova (regla d'or núm. 1): un certificat X.509 és una estructura de dades signada. La novetat és organitzativa: qui signa, què verifica abans de signar i com es distribueix la confiança.
Anatomia d'un certificat X.509
X.509 és el format estàndard de certificats (versió 3, definit a l'RFC 5280). Els seus camps essencials:
| Camp | Què conté | Exemple per a MediNube |
|---|---|---|
| Subject | La identitat del titular (qui és el propietari de la clau) | CN=portal.medinube.example |
| Subject Public Key Info | La clau pública del titular i el seu algorisme | Clau ECDSA P-256 o RSA 3072 |
| Issuer | Qui va emetre (signar) el certificat | CN=Lab CA de MediNube |
| Validity (Not Before / Not After) | Finestra temporal de validesa | 2026-07-07 → 2026-10-05 |
| Serial Number | Identificador únic del certificat dins la CA | 0x5A3F... |
| Subject Alternative Name (SAN) | Llista de noms DNS/IP que cobreix el certificat | DNS:portal.medinube.example |
| Key Usage / Extended Key Usage | Per a què està autoritzada la clau | digitalSignature, serverAuth |
| Basic Constraints | Si el certificat pot al seu torn signar-ne d'altres (CA:TRUE/FALSE) |
CA:FALSE en una fulla |
| Signature | La signatura de la CA sobre tot l'anterior | ECDSA o RSA-PSS/PKCS#1 |
I una dada derivada que faràs servir constantment:
- Empremta (fingerprint): el hash SHA-256 del certificat complet codificat en DER. No forma part del certificat; es calcula. Serveix per identificar-lo sense ambigüitat ("és aquest el certificat que hem desplegat?"), igual que fèieu servir hashes al mòdul 3 per verificar integritat.
Per què avui mana el SAN i no el CN
Històricament, la identitat del servidor es posava al CN (Common Name) del subject: CN=portal.medinube.example. Aquest disseny tenia dos problemes: el CN només admet un nom, i la seva semàntica és ambigua (és un camp genèric de nom, no específicament un domini). L'extensió SAN ho resol: una llista explícita de noms (DNS:..., IP:...), amb tantes entrades com calgui.
Des de 2017-2018, els navegadors i llibreries modernes ignoren el CN completament en validar el nom del servidor: si el domini no és al SAN, el certificat no val, encara que el CN coincideixi. Regla pràctica per a MediNube:
- El SAN és obligatori i és l'únic que es comprova per al nom.
- El CN és decoratiu; s'emplena per costum, però no hi confiïs ni el validis.
Inspeccionar un certificat real amb openssl i amb Python
La millor manera d'interioritzar l'anatomia és obrir un certificat de veritat. Descarreguem el d'un lloc real i examinem-lo (pots fer servir qualsevol domini públic; aquí, un d'exemple):
# Pas 1: connectar per TLS i desar el certificat que presenta el servidor.
# -connect indica host:port; -servername envia l'SNI (quin domini demanem).
# </dev/null tanca l'entrada perquè s_client no es quedi esperant.
openssl s_client -connect www.wikipedia.org:443 \
-servername www.wikipedia.org </dev/null 2>/dev/null \
| openssl x509 -out /tmp/wikipedia.pem
# Pas 2: bolcar el certificat en format llegible.
openssl x509 -in /tmp/wikipedia.pem -noout -textDesglossament de la segona ordre, que faràs servir centenars de vegades a la teva carrera:
x509: subcomanda d'openssl per treballar amb certificats.-in /tmp/wikipedia.pem: fitxer d'entrada, en format PEM (el Base64 entre-----BEGIN CERTIFICATE-----i-----END CERTIFICATE-----que ja vas conèixer a 04-01; el binari pur s'anomena DER).-noout: no reimprimeixis el bloc PEM.-text: mostra tots els camps decodificats.
A la sortida localitza: Issuer:, Validity, Subject:, X509v3 Subject Alternative Name: (allà hi són els dominis!), X509v3 Key Usage, X509v3 Extended Key Usage: TLS Web Server Authentication i, al final, Signature Algorithm. Algunes consultes ràpides sense llegir tot el bolcat:
openssl x509 -in /tmp/wikipedia.pem -noout -subject -issuer -dates openssl x509 -in /tmp/wikipedia.pem -noout -ext subjectAltName openssl x509 -in /tmp/wikipedia.pem -noout -fingerprint -sha256
Ara el mateix des de Python amb cryptography.x509, la cara programàtica que farà servir MediNube en les seves comprovacions automàtiques:
from cryptography import x509
from cryptography.hazmat.primitives import hashes
# Carreguem el mateix PEM que hem descarregat amb openssl.
with open("/tmp/wikipedia.pem", "rb") as f:
cert = x509.load_pem_x509_certificate(f.read())
print("Subject:", cert.subject.rfc4514_string())
print("Issuer: ", cert.issuer.rfc4514_string())
# not_valid_before_utc / not_valid_after_utc retornen datetimes amb zona UTC
# (les variants sense _utc estan obsoletes: retornaven datetimes "naive").
print("Vàlid des de:", cert.not_valid_before_utc)
print("Vàlid fins a:", cert.not_valid_after_utc)
# El SAN és una extensió: cal demanar-la explícitament.
san = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
print("SAN:", san.value.get_values_for_type(x509.DNSName))
# Empremta SHA-256 del certificat (sobre la seva codificació DER).
print("Empremta SHA-256:", cert.fingerprint(hashes.SHA256()).hex())Punts a entendre del codi:
load_pem_x509_certificatefa el parsing del PEM a un objecteCertificateimmutable.- Les extensions (SAN, Key Usage...) es consulten amb
get_extension_for_class; si no existeix, llançaExtensionNotFound— en un certificat de servidor modern el SAN ha d'existir. fingerprint(hashes.SHA256())és literalmentsha256(DER): el mòdul 3 treballant per al mòdul 5.
La cadena de confiança: arrel, intermèdia i fulla
I qui signa el certificat de la CA? A la pràctica, els certificats formen una cadena:
graph TD
R["CA Arrel<br/>(autosignada, clau offline,<br/>viu al trust store del SO/navegador)"]
I["CA Intermèdia<br/>(signada per l'arrel,<br/>emet certificats cada dia)"]
H["Certificat fulla<br/>portal.medinube.example<br/>(signat per la intermèdia, CA:FALSE)"]
R -- "signa" --> I
I -- "signa" --> H
- CA arrel: certificat autosignat (issuer = subject). La seva clau privada és tan valuosa que es custodia offline, en HSM, i es fa servir poquíssimes vegades: només per signar intermèdies. La teva confiança en ella no ve de cap signatura, sinó que està preinstal·lada al trust store del teu sistema operatiu o navegador (a Debian/Ubuntu:
/etc/ssl/certs/, gestionat pel paquetca-certificates; Firefox i Java porten el seu propi). - CA intermèdia: signada per l'arrel. És la que treballa cada dia emetent certificats. Si la seva clau es compromet, es revoca la intermèdia sense tocar l'arrel — és un tallafoc organitzatiu, i una altra aplicació del principi de criptoagilitat i compartimentació.
- Certificat fulla (leaf / end-entity): el del servidor, amb
CA:FALSE. No pot signar altres certificats.
Com es verifica la cadena
Quan un client (el navegador d'Ana Pérez, o el requests de la Clínica Sol) rep el certificat de portal.medinube.example, fa, entre d'altres, aquestes comprovacions:
- Construir la cadena: el servidor envia la fulla i les intermèdies; el client enllaça cada certificat amb el seu emissor (l'
issuerd'un ha de ser elsubjectdel següent) fins a arribar a una arrel que ja és al seu trust store. - Verificar cada signatura: amb la clau pública de l'emissor es verifica la signatura del certificat fill — exactament
verificar_firma()de 04-03, aplicada baula a baula. - Validesa temporal: ara ∈ [Not Before, Not After] en totes les baules.
- Restriccions: les intermèdies tenen
CA:TRUE; la fulla té els Key Usage adequats (serverAuth). - El nom: el domini demanat apareix al SAN de la fulla.
- Revocació: s'ha revocat alguna? (Els mecanismes — CRL, OCSP — els veurem a 05-03; per ara queda't amb el fet que els certificats també caduquen i es revoquen.)
Si tot passa, i només llavors, el client accepta que la clau pública de la fulla pertany a portal.medinube.example. La confiança flueix de l'arrel cap avall mitjançant signatures verificables: això és una PKI (Public Key Infrastructure).
Un matís pràctic: a la Web PKI les fulles fan servir avui claus ECDSA P-256/P-384 o RSA. Ed25519 —l'elecció de MediNube per a les receptes a 04-03— és excel·lent, però els navegadors encara no l'accepten en certificats TLS públics. Cada context té el seu ecosistema: receptes internes amb Ed25519, certificats web amb ECDSA/RSA. Criptoagilitat, regla núm. 8.
Autoritats de certificació: per què funciona el model (i quan ha fallat)
Una CA és una organització el negoci de la qual és verificar identitats i signar certificats, sotmesa a auditories (els Baseline Requirements del CA/Browser Forum) sota l'amenaça d'expulsió dels trust stores. El model funciona perquè:
- Escala: no cal intercanviar claus en persona amb cada web del planeta; n'hi ha prou de confiar en ~100-150 arrels preinstal·lades.
- La confiança és revocable: si una CA ho fa malament, els navegadors l'expulsen i tots els seus certificats deixen de valer de cop.
- Incentius alineats: la CA viu de la seva reputació.
Però és un model amb un defecte estructural: qualsevol CA del teu trust store pot emetre un certificat per a qualsevol domini. La seguretat la marca la pitjor CA de la llista, no la millor.
Cas històric: DigiNotar (2011). Aquesta CA holandesa va ser compromesa i els atacants van emetre més de 500 certificats fraudulents, inclòs un per a *.google.com, fet servir per interceptar el correu de milers d'usuaris a l'Iran — un MalloryClinic a escala estatal, amb certificats tècnicament vàlids. Quan es va descobrir, els navegadors van expulsar DigiNotar dels seus trust stores i l'empresa va fer fallida en setmanes. Moralitat doble: el sistema de càstig funciona, però el dany ja estava fet.
La resposta: Certificate Transparency (CT). Des de 2018, els navegadors exigeixen que tot certificat públic estigui inscrit en registres públics append-only (auditables, impossibles de reescriure discretament). Qualsevol pot monitoritzar-los: si demà una CA emetés un certificat per a portal.medinube.example que MediNube no ha demanat, l'equip ho veuria als logs de CT i saltarien les alarmes. Queda't amb el concepte: CT no impedeix la mala emissió, la fa detectable. (Pots explorar els logs en cercadors públics com crt.sh.)
La CSR: demanar un certificat per a portal.medinube.example
Com demana MediNube un certificat a una CA? Amb una CSR (Certificate Signing Request): un fitxer que conté la clau pública, la identitat sol·licitada (SAN inclòs) i una autosignatura que demostra que qui la demana posseeix la clau privada corresponent. Fonamental: la clau privada mai no viatja a la CA; es genera i es queda als servidors de MediNube.
Amb openssl, en dues ordres (o una de sola amb -newkey):
# 1) Generar la clau privada del servidor (ECDSA P-256, estàndard actual en TLS).
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 \
-out portal.key
chmod 600 portal.key # només el propietari la pot llegir
# 2) Generar la CSR: identitat + clau pública + autosignatura.
# -subj evita el qüestionari interactiu; -addext afegeix el SAN (el que de
# debò importa, com hem vist: el CN és decoratiu).
openssl req -new -key portal.key \
-subj "/CN=portal.medinube.example/O=MediNube SL" \
-addext "subjectAltName=DNS:portal.medinube.example" \
-out portal.csr
# 3) Revisar el que enviarem (el SAN ha de ser-hi!).
openssl req -in portal.csr -noout -textEl mateix des de Python, útil per automatitzar altes de clíniques en el futur:
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.oid import NameOID
# 1) Clau privada ECDSA P-256 — es queda a MediNube, mai no surt.
clau_privada = ec.generate_private_key(ec.SECP256R1())
# 2) Construir la CSR amb el patró "builder": cada crida retorna un
# builder nou amb aquesta dada afegida, i sign() la signa amb la nostra clau
# (l'autosignatura que demostra la possessió de la privada).
csr = (
x509.CertificateSigningRequestBuilder()
.subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, "portal.medinube.example"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "MediNube SL"),
]))
.add_extension(
x509.SubjectAlternativeName([x509.DNSName("portal.medinube.example")]),
critical=False,
)
.sign(clau_privada, hashes.SHA256())
)
# 3) Serialitzar a PEM per enviar-la a la CA.
with open("portal.csr", "wb") as f:
f.write(csr.public_bytes(serialization.Encoding.PEM))
with open("portal.key", "wb") as f:
f.write(clau_privada.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
# A 04-01 vas aprendre BestAvailableEncryption per protegir claus
# a disc; per a un servidor que ha d'arrencar sense intervenció
# humana se sol desar sense xifrar PERÒ amb permisos 600 i, millor,
# en un gestor de secrets (ho veurem a 06-01).
serialization.NoEncryption(),
))La CA rep la CSR, valida que controles la identitat que demanes (ara veurem com) i, si tot quadra, et retorna el certificat signat.
Tipus de validació: DV, OV i EV
Què comprova exactament la CA abans de signar? Depèn del tipus de certificat:
| Tipus | Què valida la CA | Com ho valida | Emissió | Què veu l'usuari | Ús típic |
|---|---|---|---|---|---|
| DV (Domain Validation) | Que controles el domini | Repte tècnic automatitzat (fitxer HTTP, registre DNS, correu) | Minuts, automatitzable (Let's Encrypt) | Cadenat; només el domini | La immensa majoria de la web; portal.medinube.example |
| OV (Organization Validation) | Domini + que l'organització existeix | DV + registres mercantils, verificació telefònica | Dies | El nom de l'empresa als detalls del certificat | Empreses que volen identitat corporativa visible |
| EV (Extended Validation) | Domini + verificació exhaustiva de l'entitat legal | Procés manual estricte | Dies/setmanes | Abans, barra verda amb el nom; avui els navegadors ja no la mostren | Banca i sectors regulats, en retrocés |
Detall clau: els tres xifren exactament igual. La criptografia d'un DV gratuït i d'un EV caríssim és la mateixa; canvia quanta identitat humana hi ha verificada al darrere. Per al portal de MediNube, un DV automatitzat és l'elecció moderna (i a 05-03 veuràs com automatitzar-ne l'emissió i la renovació amb ACME).
Mini-PKI de laboratori per a MediNube
Construirem la nostra pròpia CA i signarem un certificat, per tocar amb les mans tot l'anterior.
Només per a laboratori. Aquesta CA serveix per a l'entorn de desenvolupament intern de MediNube i per aprendre. Mai facis servir una CA casolana per a serveis públics, i mai instal·lis arrels de tercers al teu trust store a la lleugera: qui controla una arrel del teu trust store pot suplantar qualsevol web per a tu. En producció pública, sempre una CA real (05-03). I recorda: MediNube gestiona dades sanitàries fictícies en aquest curs; un desplegament real exigiria a més revisió de seguretat i compliment del RGPD.
mkdir -p ~/medinube-lab/pki && cd ~/medinube-lab/pki
# ── 1. La CA arrel del laboratori ──────────────────────────────────────
# Clau privada de l'arrel (aquesta és LA joia: en una PKI real viuria offline).
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out ca.key
chmod 600 ca.key
# Certificat arrel AUTOSIGNAT (-x509 emet certificat en lloc d'una CSR).
# basicConstraints CA:TRUE marcat critical: això SÍ que és una CA.
# keyUsage keyCertSign,cRLSign: la seva clau només signa certificats i CRL.
openssl req -x509 -new -key ca.key -sha384 -days 1825 \
-subj "/CN=MediNube Lab Root CA/O=MediNube SL" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-out ca.crt
# ── 2. La fulla: clau + CSR del portal (igual que a la secció anterior) ──
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out portal.key
chmod 600 portal.key
openssl req -new -key portal.key \
-subj "/CN=portal.medinube.example/O=MediNube SL" \
-addext "subjectAltName=DNS:portal.medinube.example" \
-out portal.csr
# ── 3. La CA signa la CSR i emet el certificat fulla ──────────────────
# -CA/-CAkey: qui signa. -copy_extensions copy: conserva el SAN de la CSR.
# 90 dies: vida curta a propòsit (a 05-03 veuràs per què és bona idea).
openssl x509 -req -in portal.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-days 90 -sha256 -copy_extensions copy \
-out portal.crt
# ── 4. Verificar la cadena: és vàlid portal.crt contra la nostra arrel? ────
openssl verify -CAfile ca.crt portal.crt
# → portal.crt: OKAquest openssl verify final executa en petit el que fa el teu navegador: construeix la cadena portal.crt → ca.crt i verifica signatura, dates i restriccions. Comprova el resultat també amb el que has après: openssl x509 -in portal.crt -noout -subject -issuer -ext subjectAltName — veuràs que l'issuer ja no és el mateix subject, sinó la teva CA de laboratori. (Hem omès la intermèdia per simplificar; el principi amb tres baules és idèntic.)
Com això derrota MalloryClinic
Tornem al diagrama de l'atac de 04-04, ara amb certificats en joc:
sequenceDiagram
participant C as Clínica Sol
participant M as MalloryClinic (MITM)
participant S as portal.medinube.example
C->>M: Hola, vull parlar amb portal.medinube.example
M->>C: Té "el meu" certificat (clau de Mallory)
Note over C: Verificació de cadena:<br/>1. Signat per una CA del meu trust store? ✗<br/>(o, si Mallory fa servir un cert robat d'altri:<br/>2. portal.medinube.example al SAN? ✗)
C--xM: AVORTAR connexió. Certificat invàlid.
MalloryClinic té exactament tres opcions, totes dolentes:
- Presentar la seva pròpia clau amb un certificat autosignat o de la seva CA casolana → la cadena no acaba en cap arrel del trust store de la clínica. Rebutjat.
- Presentar un certificat vàlid d'un altre domini (un que hagi aconseguit legítimament) → la signatura de la cadena val, però
portal.medinube.exampleno és al seu SAN. Rebutjat. - Aconseguir que una CA real li emeti un certificat per a
portal.medinube.example→ hauria de superar la validació de control del domini sense controlar-lo i, fins i tot si una CA fallés (DigiNotar), Certificate Transparency deixaria el certificat fraudulent a la vista dels monitors de MediNube.
La clau privada de la CA signa l'associació identitat↔clau abans que Mallory pugui intervenir, i aquesta signatura viatja amb el certificat. L'esquerda que arrosseguem des de 04-01 queda, per fi, tècnicament tancada. Nota's el preu: hem afegit un tercer de confiança i tot un aparell operatiu al voltant — certificats que caduquen, es renoven i es revoquen (05-03).
Errors Comuns i Consells
- Validar contra el CN en lloc del SAN. Codi heretat que compara el CN "a mà" accepta certificats que cap navegador acceptaria. Deixa la validació del nom a la llibreria (ho veuràs a 05-02); si algun dia la fas tu, SAN i només SAN.
- Confondre certificat i clau privada. El
.crtés públic, es regala; el.keyés el secret. Enviar a algú "el certificat" mai no inclou la clau. Si una CA et demana la teva clau privada, fuig. - Enviar la clau privada amb la CSR. La CSR ja conté la clau pública i la prova de possessió; la privada no surt del servidor. Mai.
- Desactivar la verificació "perquè falla". Un error de validació de certificat és el sistema funcionant. La temptació de silenciar-lo (el
verify=Falseque trobaràs en codi heretat de MediNube a 05-02) equival a tornar al món de 04-04 on Mallory campava a plaer. - Instal·lar arrels alegrement al trust store. Cada arrel que afegeixes pot suplantar qualsevol lloc per a tu. L'arrel de laboratori d'aquesta lliçó: només en entorns de desenvolupament controlats.
- Ignorar
Basic ConstraintsiKey Usageen emetre. Una fulla emesa per descuit ambCA:TRUEpot signar certificats per a qualsevol domini. En muntar la teva mini-PKI, marca sempre la fulla comCA:FALSE(el valor per defecte si no afegeixes l'extensió de CA) i limita els usos.
Exercicis
Exercici 1 — Autòpsia d'un certificat real. Amb openssl s_client + openssl x509, descarrega el certificat d'un domini públic que facis servir cada dia i respon: (a) qui és l'issuer i qui el subject? (b) quants noms hi ha al SAN? (c) quants dies de vida total té? (d) quina és la seva empremta SHA-256?
Exercici 2 — Auditor en Python. Escriu una funció auditar_certificat(ruta_pem: str) -> list[str] que carregui un certificat amb cryptography.x509 i retorni una llista d'avisos: "CADUCAT" si ja ha expirat, "SENSE_SAN" si no té l'extensió SAN, i "VIDA_EXCESSIVA" si Not After − Not Before supera 398 dies (el màxim que accepten els navegadors avui). Prova-la amb el certificat de l'exercici 1 i amb el teu portal.crt del laboratori.
Exercici 3 — Mallory contra la teva mini-PKI. Al teu laboratori, genera una segona CA (mallory-ca.key / mallory-ca.crt, CN MalloryClinic CA) i emet amb ella un certificat per a portal.medinube.example (Mallory pot escriure el que vulgui als seus propis certificats!). Comprova amb openssl verify -CAfile ca.crt mallory-portal.crt que no és vàlid contra l'arrel legítima de MediNube, i raona per què això modela exactament la derrota del MITM.
Solucions
Solució 1. Exemple de sessió (els valors concrets dependran del domini i la data):
openssl s_client -connect ejemplo.com:443 -servername ejemplo.com \
</dev/null 2>/dev/null | openssl x509 -out /tmp/cert.pem
openssl x509 -in /tmp/cert.pem -noout -subject -issuer # (a)
openssl x509 -in /tmp/cert.pem -noout -ext subjectAltName # (b) compta les entrades DNS:
openssl x509 -in /tmp/cert.pem -noout -dates # (c) resta notAfter - notBefore
openssl x509 -in /tmp/cert.pem -noout -fingerprint -sha256 # (d)És habitual trobar issuers com Let's Encrypt (C=US, O=Let's Encrypt, CN=...) — una CA intermèdia, no l'arrel: recorda que la fulla gairebé mai la signa l'arrel directament.
Solució 2.
from datetime import datetime, timedelta, timezone
from cryptography import x509
def auditar_certificat(ruta_pem: str) -> list[str]:
with open(ruta_pem, "rb") as f:
cert = x509.load_pem_x509_certificate(f.read())
avisos = []
ara = datetime.now(timezone.utc)
if cert.not_valid_after_utc < ara:
avisos.append("CADUCAT")
try:
cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
except x509.ExtensionNotFound:
avisos.append("SENSE_SAN")
vida = cert.not_valid_after_utc - cert.not_valid_before_utc
if vida > timedelta(days=398):
avisos.append("VIDA_EXCESSIVA")
return avisosDetalls que importen: fem servir les propietats _utc i comparem amb datetime.now(timezone.utc) (barrejar datetimes amb zona i sense zona llança TypeError); el SAN es detecta capturant ExtensionNotFound, no mirant None. El teu portal.crt de laboratori hauria de retornar []; molts certificats antics d'intranets retornen SENSE_SAN i VIDA_EXCESSIVA alhora.
Solució 3.
cd ~/medinube-lab/pki
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out mallory-ca.key
openssl req -x509 -new -key mallory-ca.key -days 1825 \
-subj "/CN=MalloryClinic CA" \
-addext "basicConstraints=critical,CA:TRUE" -out mallory-ca.crt
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out mallory-portal.key
openssl req -new -key mallory-portal.key \
-subj "/CN=portal.medinube.example" \
-addext "subjectAltName=DNS:portal.medinube.example" -out mallory-portal.csr
openssl x509 -req -in mallory-portal.csr -CA mallory-ca.crt -CAkey mallory-ca.key \
-CAcreateserial -days 90 -copy_extensions copy -out mallory-portal.crt
openssl verify -CAfile ca.crt mallory-portal.crt
# → error 20: unable to get local issuer certificate ← FALLA, com ha de ser
openssl verify -CAfile mallory-ca.crt mallory-portal.crt
# → OK ← només és vàlid per a qui confiï en la CA de MalloryRaonament: el contingut del certificat de Mallory és idèntic al legítim (mateix SAN, mateixa estructura); el que no pot falsificar és la signatura d'una arrel en què la víctima ja confia, perquè no té la seva clau privada. La confiança no és en el que el certificat diu, sinó en qui el signa — exactament la propietat de no falsificació de les signatures de 04-03, elevada a infraestructura.
Conclusió
L'esquerda que perseguia MediNube des de 04-01 té per fi un tancament tècnic: un certificat X.509 lliga clau pública i identitat amb la signatura verificable d'una CA, i la cadena de confiança (arrel offline al trust store → intermèdia → fulla) permet validar aquesta signatura sense haver intercanviat res en persona. Has après a llegir l'anatomia d'un certificat (amb el SAN com a camp que de debò mana), a inspeccionar-lo amb openssl x509 -text i amb cryptography.x509, a generar una CSR sense que la clau privada surti de casa, a distingir DV/OV/EV, i has muntat una mini-PKI de laboratori amb la qual has comprovat, a la teva pròpia terminal, que els certificats de MalloryClinic no són vàlids. També has vist que el model té esquerdes pròpies (DigiNotar) i vigilants (Certificate Transparency).
Però un certificat, quiet en un fitxer, no protegeix res. Falta el protocol que el posa en acció a cada connexió d'Ana Pérez amb el portal: el que presenta el certificat, acorda claus efímeres amb ECDH, deriva claus amb HKDF i xifra amb AEAD. Et sonaran totes les peces, perquè portes quatre mòduls construint-les. A la propera lliçó, 05-02: TLS a la pràctica, les veuràs encaixar en el protocol de seguretat més fet servir del món.
Curs de Criptografia Aplicada
Mòdul 1: Fonaments de la Criptografia
- Què és la criptografia i per a què serveix
- Codificació, ofuscació i xifratge
- Aleatorietat i entropia
- El principi de Kerckhoffs i les regles d'or
Mòdul 2: Criptografia Simètrica
- Xifratge simètric: AES i ChaCha20
- Modes d'operació
- Xifratge autenticat (AEAD)
- Derivació de claus (KDF)
Mòdul 3: Hashes, MAC i Contrasenyes
- Funcions hash criptogràfiques
- Autenticació de missatges amb HMAC
- Emmagatzematge segur de contrasenyes
Mòdul 4: Criptografia Asimètrica
- Fonaments de clau pública i RSA
- Criptografia de corba el·líptica
- Signatures digitals
- Intercanvi de claus: Diffie-Hellman
- Xifratge híbrid
Mòdul 5: PKI, Certificats i TLS
- Certificats X.509 i autoritats de certificació
- TLS a la pràctica
- Gestió del cicle de vida dels certificats
