OpenSSL: validar la cadena de confianza de un certificado (SSL/TLS)

Algo extremadamente útil que se debe conocer de OpenSSL, es que permite extraer toda la cadena de confianza del certificado asociado al host contra el que atacamos. De este modo podemos no sólo extraer el propio certificado del host al que conectamos, sino también sus certificados intermedios.

La sintaxis básica es la siguiente:

openssl s_client -showcerts -connect www.foo.com:443

En este ejemplo, estamos atacando a un servidor web (HTTPS/443), pero también se puede utilizar para cualquier otro servicio (IMAPS, POPS, FTPS…).

El parámetro que permite extraer toda esta información es -showcerts. s_client simplemente implementa un cliente genérico SSL/TLS para establecer una conexión transparente contra el host remoto con comunicación SSL/TLS, se suele utilizar únicamente para este tipo de conexiones de prueba. Finalmente -connect no creo que requiera mucha explicación, sirve para especificar el host remoto al que conectar.

Aquí tenéis un ejemplo de la salida que genera una conexión contra google.com:

bar@foo:[~]: openssl s_client -showcerts -connect google.com:443
CONNECTED(00000003)
depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
verify return:1
depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
verify return:1
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com
   i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
-----BEGIN CERTIFICATE-----
MIIIyDCCB7CgAwIBAgIQbBedCPn0eEy2TP0BtGXyjDANBgkqhkiG9w0BAQsFADBU
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw
IwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDMwMTA5
NDUyNVoXDTE5MDUyNDA5MjUwMFowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2ds
ZSBMTEMxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAL0gkMyD19mxMJ2uRFq9ZInHZQ710xQVXrlaHIp3NVpllHX9
BVTZqdgDOtb3s+cbxSoH/urPp/ljocwRCJOlAWHpcnYoHxYDIZA44hsypmJTNYDU
XVOB6Rod7SrGLZ5nInIZzqun2ZN9FlGWKS3+vGkxoMPcibaaW3Ue/G7BxKKIsAQW
bFJWqfS3AYwtWRnFnmHcJnN16fSaXOiWpopakBuX5V/GVNL4F7VcAdDosJm9UfVR
DigdXhShjVv4FRhRIJiuudQhPhgtp3L8ImaotE2TEkfLZvVUIl+heeBiAcEzfajv
Fua69IjvUhtBa2ZLMudln+MWHrejleGdJP3PqEMCAwEAAaOCBYIwggV+MBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMIIEVwYDVR0RBIIETjCCBEqCDCouZ29vZ2xlLmNvbYIN
Ki5hbmRyb2lkLmNvbYIWKi5hcHBlbmdpbmUuZ29vZ2xlLmNvbYISKi5jbG91ZC5n
b29nbGUuY29tghgqLmNyb3dkc291cmNlLmdvb2dsZS5jb22CBiouZy5jb4IOKi5n
Y3AuZ3Z0Mi5jb22CCiouZ2dwaHQuY26CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22C
CyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUuY28uaW6CDiouZ29v
Z2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUuY29tLmFygg8qLmdv
b2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29nbGUuY29tLmNvgg8q
Lmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnZu
ggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZyggsqLmdvb2ds
ZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5wbIILKi5n
b29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29nbGVhcGlzLmNughEq
Lmdvb2dsZWNuYXBwcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xl
dmlkZW8uY29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CEiouZ3N0YXRp
Y2NuYXBwcy5jboIKKi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIUKi5tZXRyaWMuZ3N0
YXRpYy5jb22CDCoudXJjaGluLmNvbYIQKi51cmwuZ29vZ2xlLmNvbYIWKi55b3V0
dWJlLW5vY29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0dWJlZWR1Y2F0
aW9uLmNvbYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyoueXRpbWcuY29t
ghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2RldmVs
b3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdvb2ds
ZS5jboIEZy5jb4IIZ2dwaHQuY26CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5j
b22CCmdvb2dsZS5jb22CD2dvb2dsZWNuYXBwcy5jboISZ29vZ2xlY29tbWVyY2Uu
Y29tghhzb3VyY2UuYW5kcm9pZC5nb29nbGUuY26CCnVyY2hpbi5jb22CCnd3dy5n
b28uZ2yCCHlvdXR1LmJlggt5b3V0dWJlLmNvbYIUeW91dHViZWVkdWNhdGlvbi5j
b22CD3lvdXR1YmVraWRzLmNvbYIFeXQuYmUwaAYIKwYBBQUHAQEEXDBaMC0GCCsG
AQUFBzAChiFodHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFNHSUFHMy5jcnQwKQYIKwYB
BQUHMAGGHWh0dHA6Ly9vY3NwLnBraS5nb29nL0dUU0dJQUczMB0GA1UdDgQWBBTz
//6rQAj0SI5K922pOxpB5nEJrjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFHfC
uFCaZ3Z2sS3ChtCDoH6mfrpLMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFAzAIBgZn
gQwBAgIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5wa2kuZ29vZy9HVFNH
SUFHMy5jcmwwDQYJKoZIhvcNAQELBQADggEBADJtlKyYiian4PXnHRsKNaatFBEV
FAZ+L8iReh2zglVocNEoCQrMItc6RIKKBqn9306aKaS6118dDpzJMft5UDN/xiIk
SdXnfT9Tbm1Wc2wYp1WAs9i3oVuXCcNnCUONr+jmD8n0mPud5xIH6LHsPlxBc16e
9muFqEhJakPy1Vf7fikEv6dTbXiYTLxwjT0QLpaulsSLQ2KiU2tbtO8hdOR3tvbT
lmNLUJuHyNbDqFsRsvZaGiNv0ObKSE84++J9wDGwx/s1mcspbthYsrt3kg7BG+qI
srmCICWC71QVjCabBunEaW55EDlYJ8s8fsA4zilYBQoPhDnVUSd+JGZfJoY=
-----END CERTIFICATE-----
 1 s:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
   i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
-----BEGIN CERTIFICATE-----
MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAw
HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFs
U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEy
MTUwMDAwNDJaMFQxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3Qg
U2VydmljZXMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKUkvqHv/OJGuo2nIYaNVW
XQ5IWi01CXZaz6TIHLGp/lOJ+600/4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK
71G4nzKMfHCGUksW/mona+Y2emJQ2N+aicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9
RUk2T0HNouB2VzxoMXlkyW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1z
ouAqYGVQMc/7sy+/EYhALrVJEA8KbtyX+r8snwU5C1hUrwaW6MWOARa8qBpNQcWT
kaIeoYvy/sGIJEmjR0vFEwHdp1cSaWIr6/4g72n7OqXwfinu7ZYW97EfoOSQJeAz
AgMBAAGjggEzMIIBLzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUH
AwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCa
Z3Z2sS3ChtCDoH6mfrpLMB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd/cGYYu
MDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdv
b2cvZ3NyMjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dz
cjIvZ3NyMi5jcmwwPwYDVR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYc
aHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEA
HLeJluRT7bvs26gyAZ8so81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2e
ux9LSD+PAj2LIYRFHW31/6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt+nlPq
wnb8Oa2I/maSJukcxDjNSfpDh/Bd1lZNgdd/8cLdsE3+wypufJ9uXO1iQpnh9zbu
FIwsIONGl1p3A8CgxkqI/UAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy
7a8IVk6wuy6pm+T7HT4LY8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZV
c7o835DLAFshEWfC7TIe3g==
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com
issuer=/C=US/O=Google Trust Services/CN=Google Internet Authority G3
---
No client certificate CA names sent
Peer signing digest: SHA256
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4048 bytes and written 309 bytes
Verification: OK
---
New, TLSv1.2, Cipher is ECDHE-RSA-CHACHA20-POLY1305
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-CHACHA20-POLY1305
    Session-ID: F1A52150D5EA323DB6D8CCA9CFDCB0C700DF884C3A909B2680C3EA65E292E2BC
    Session-ID-ctx: 
    Master-Key: 7FA6EA18D222D688D338D44C1BC7320F3E7565170B700D3244D9B3963B821C549F61E1094A15699926ADD8C6437DD44E
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 100800 (seconds)
    TLS session ticket:
    0000 - 00 b2 4f cc b5 1a 0c 4d-37 85 19 75 b0 86 ee c2   ..O....M7..u....
    0010 - ae 03 24 42 db c2 c8 c4-fa 36 cc 43 82 95 73 c0   ..$B.....6.C..s.
    0020 - c6 bb 1b 17 26 ff d0 a8-a9 a7 80 8d 6c 2d 3e 50   ....&.......l->P
    0030 - a5 c4 5a 41 59 bd fc 31-c8 e4 a7 09 0b 23 73 30   ..ZAY..1.....#s0
    0040 - c5 31 c1 4f 61 80 6f 46-8c 6f 21 bf 1d 49 2c ec   .1.Oa.oF.o!..I,.
    0050 - 5e 45 7a e7 65 de 1b 85-b2 14 cc 4c ad 6a bc be   ^Ez.e......L.j..
    0060 - 58 ec 96 6a dc a9 e8 5a-8b 5b 21 fa 8a d9 c2 e2   X..j...Z.[!.....
    0070 - 92 52 70 ab 0f bb 4c 38-af e2 3b e8 b8 7d 05 f3   .Rp...L8..;..}..
    0080 - 09 1d b4 32 33 97 2e 58-d8 09 ad c7 94 a2 cf 98   ...23..X........
    0090 - 5c e3 be 22 26 37 43 d8-56 12 bd ea 60 aa 54 8f   \.."&7C.V...`.T.
    00a0 - 01 2c 02 ad e9 fb 72 9d-f1 62 68 86 46 3a d6 02   .,....r..bh.F:..
    00b0 - 26 01 88 a8 ac 0d 53 51-a1 eb af 29 24 b5 69 2a   &.....SQ...)$.i*
    00c0 - 5e 29 dd 55 1c f0 3e 71-e6 08 d1 fa 58 b7 61 73   ^).U..>q....X.as
    00d0 - 06 09 da cf 6b ec 79 2f-64 e5                     ....k.y/d.

    Start Time: 1555173234
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
-/(--
^C

Como podéis observar, la cantidad de información que aparece puede llegar a ser abrumadora, pero es realmente útil cuando estamos haciendo diagnóstico de conexiones SSL/TLS. En este caso, lo que nos interesa es recuperar toda la cadena de confianza, es decir, todos los certificados que aparecen entre:

-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

Normalmente aparecerá el certificado raíz (el del FQDN al que conectamos) así como todos los certificados intermedios (CA). Para localizar y organizar los certificados, tened en cuenta la información de los «subject» de cada uno.