matteocorti / check_ssl_cert

A shell script (that can be used as a Nagios/Icinga plugin) to check an SSL/TLS connection.
GNU General Public License v3.0
363 stars 133 forks source link

Validate chain on Let's Encrypts default chain #319

Closed vrandr closed 2 years ago

vrandr commented 2 years ago

Describe the bug

Validate the expiration date on Let's Encrypt default compatibility chain fails.

To Reproduce

# (Re-)Add DST Root CA X3 to your local trust store (/etc/ssl/certs/ca-certificates.crt)
check_ssl_cert -H 161.35.218.92 --sni letsencrypt.org --crl --rootcert-file /etc/ssl/certs/ca-certificates.crt -w 20 -c 7 --ignore-host-cn --ignore-ocsp
Error(s):
    SSL_CERT CRITICAL lencr.org: certificate element 3 is revoked (CRL)
    SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)

Expected behavior

This fails for all LE certificates which use the default compatibility chain of:

  1. LE server certificate
  2. https://crt.sh/?id=3334561879
  3. https://crt.sh/?id=3958242236

The Root CA DST Root CA X3 expired today.

Is there a way to check the expiration for all certificates except for the DST Root CA X3? I've tried different combinations of --skip-element and --element without success.

System (please complete the following information):

Additional context/output

[DBG] Command line arguments: -H 161.35.218.92 --sni letsencrypt.org --crl --rootcert-file /etc/ssl/certs/ca-certificates.crt -w 20 -c 7 --ignore-host-cn --ignore-ocsp -d -v
[DBG] SNI       = letsencrypt.org
[DBG] HOST_NAME = 161.35.218.92
[DBG] HOST_ADDR = 161.35.218.92
[DBG] COMMON_NAME =
[DBG] -c specified: 7
[DBG] ROOT_CA =  -CAfile /etc/ssl/certs/ca-certificates.crt
[DBG] file version: file-5.32
[DBG] magic file from /etc/magic:/usr/share/misc/magic
[DBG] cURL binary needed. SSL Labs = , OCSP = , CURL = 1
[DBG] cURL binary not specified
[DBG] cURL available: /usr/bin/curl
[DBG] curl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3
[DBG] Release-Date: 2018-01-24
[DBG] Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
[DBG] Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
[DBG] nmap binary not needed. No disallowed protocols
[DBG] perl available: /usr/bin/perl
[DBG] date available: /bin/date
[DBG] checking date version
[DBG] check_ssl_cert version: 2.1.0
[DBG] OpenSSL binary: /usr/bin/openssl
[DBG] OpenSSL info:
[DBG]OpenSSL 1.1.1  11 Sep 2018
[DBG]built on: Mon Aug 23 17:02:39 2021 UTC
[DBG]platform: debian-amd64
[DBG]options:  bn(64,64) rc4(16x,int) des(int) blowfish(ptr)
[DBG]compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-Flav1L/openssl-1.1.1=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPADLOCK_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
[DBG]OPENSSLDIR: "/usr/lib/ssl"
[DBG]ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1"
[DBG]Seeding source: os-specific
[DBG] OpenSSL configuration directory: /usr/lib/ssl
[DBG] 0 root certificates installed by default
[DBG] Date computation: GNU
[DBG] '/usr/bin/openssl s_client' supports '-servername': using -servername letsencrypt.org
[DBG] '/usr/bin/openssl s_client' supports '-xmpphost': using -xmpphost 161.35.218.92
[DBG] temporary file /tmp/PxvY2J created
[DBG] temporary file /tmp/TJZWB8 created
[DBG] temporary file /tmp/6yJndY created
[DBG] temporary file /tmp/TAlYfs created
[DBG] temporary file /tmp/B3Ltxa created
downloading certificate to /tmp
[DBG] 161.35.218.92 is an IPv4 address
[DBG] Adding -ign_eof to the options
[DBG] executing with timeout (120s): printf 'HEAD / HTTP/1.1
[DBG] Host: letsencrypt.org
[DBG] User-Agent: check_ssl_cert/2.1.0
[DBG] Connection: close
[DBG]
[DBG] ' | /usr/bin/openssl s_client    -crlf -ign_eof  -connect 161.35.218.92:443 -servername letsencrypt.org   -showcerts -verify 6  -CAfile /etc/ssl/certs/ca-certificates.crt      2> /tmp/TJZWB8 1> /tmp/PxvY2J
[DBG]   start time = 1633013609
[DBG] /usr/bin/timeout 120 /bin/sh -c "printf 'HEAD / HTTP/1.1
[DBG] Host: letsencrypt.org
[DBG] User-Agent: check_ssl_cert/2.1.0
[DBG] Connection: close
[DBG]
[DBG] ' | /usr/bin/openssl s_client    -crlf -ign_eof  -connect 161.35.218.92:443 -servername letsencrypt.org   -showcerts -verify 6  -CAfile /etc/ssl/certs/ca-certificates.crt      2> /tmp/TJZWB8 1> /tmp/PxvY2J"
[DBG]   end time = 1633013609
[DBG]   new timeout = 120
[DBG] storing a copy of the retrieved certificate in 161.35.218.92.crt
[DBG] storing a copy of the OpenSSL errors in 161.35.218.92.error
[DBG] Return value of the command = 0
checking TLS renegotiation
[DBG] executing with timeout (120s): printf 'R
[DBG] ' | openssl s_client -connect 161.35.218.92:443 2>&1 | grep -F -q err
[DBG]   start time = 1633013609
[DBG] /usr/bin/timeout 120 /bin/sh -c "printf 'R
[DBG] ' | openssl s_client -connect 161.35.218.92:443 2>&1 | grep -F -q err"
[DBG]   end time = 1633013609
[DBG]   new timeout = 120
parsing the x509 certificate file
[DBG] Skipping 0 element of the chain
[DBG] ISSUERS =
[DBG] issuer=C = US, O = Let's Encrypt, CN = R3
[DBG] issuer=C = US, O = Internet Security Research Group, CN = ISRG Root X1
[DBG] issuer=O = Digital Signature Trust Co., CN = DST Root CA X3
[DBG] ISSUERS =
[DBG] O = Let's Encrypt
[DBG] CN = R3
[DBG] O = Internet Security Research Group
[DBG] CN = ISRG Root X1
[DBG] O = Digital Signature Trust Co.
[DBG] CN = DST Root CA X3
[DBG] subject=CN = lencr.org
[DBG] CN         = lencr.org
[DBG] CA         = O = Let's Encrypt
[DBG] CA         = CN = R3
[DBG] CA         = O = Internet Security Research Group
[DBG] CA         = CN = ISRG Root X1
[DBG] CA         = O = Digital Signature Trust Co.
[DBG] CA         = CN = DST Root CA X3
[DBG] SERIAL     = 04C7DFD804B953B98DF7BD408640EEB3AAF9
[DBG] FINGERPRINT= 23:99:BF:E8:6F:B0:6E:6E:D2:D2:D0:31:B2:A1:B7:F4:12:FF:DF:A2
[DBG] OCSP_URI   = http://r3.o.lencr.org
[DBG] ISSUER_URI = http://r3.i.lencr.org/
[DBG]         Signature Algorithm: sha256WithRSAEncryption
[DBG] subjectAlternativeName = lencr.org letsencrypt.com letsencrypt.org www.lencr.org www.letsencrypt.com www.letsencrypt.org
[DBG] Checking expiration date
[DBG] Number of certificates in CA chain: 3
[DBG] Skipping 0 element of the chain
[DBG] ------------------------------------------------------------------------------
[DBG] Checking expiration date of element 1
[DBG] Validity date on cert element 1 is Nov  4 01:03:51 2021 GMT
[DBG] Date computations: GNU
[DBG] Computing number of hours until 'Nov  4 01:03:51 2021 GMT'
[DBG] Hours until Nov  4 01:03:51 2021 GMT: 826
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 0 on cert element 1
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 604800 on cert element 1
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 1728000 on cert element 1
[DBG] ------------------------------------------------------------------------------
[DBG] Checking OCSP status of element 1
[DBG] temporary file /tmp/p3WsHO created
[DBG] Storing the chain element in /tmp/p3WsHO
[DBG] ------------------------------------------------------------------------------
[DBG] temporary file /tmp/surmmH created
[DBG] Storing the chain element in /tmp/surmmH
[DBG] Checking CRL status of element 1
[DBG] Certificate revokation list not available
[DBG] ------------------------------------------------------------------------------
[DBG] Checking expiration date of element 2
[DBG] Validity date on cert element 2 is Sep 15 16:00:00 2025 GMT
[DBG] Date computations: GNU
[DBG] Computing number of hours until 'Sep 15 16:00:00 2025 GMT'
[DBG] Hours until Sep 15 16:00:00 2025 GMT: 34705
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 0 on cert element 2
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 604800 on cert element 2
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 1728000 on cert element 2
[DBG] ------------------------------------------------------------------------------
[DBG] Checking OCSP status of element 2
[DBG] temporary file /tmp/AFAh3C created
[DBG] Storing the chain element in /tmp/AFAh3C
[DBG] ------------------------------------------------------------------------------
[DBG] temporary file /tmp/f8EnUk created
[DBG] Storing the chain element in /tmp/f8EnUk
[DBG] Checking CRL status of element 2
[DBG] Certificate revokation list available (http://x1.c.lencr.org/)
[DBG] CRL: fetching CRL http://x1.c.lencr.org/ to /tmp/6yJndY
[DBG] executing with timeout (120s): /usr/bin/curl    --silent --location \"http://x1.c.lencr.org/\" > /tmp/6yJndY
[DBG]   start time = 1633013609
[DBG] /usr/bin/timeout 120 /bin/sh -c "/usr/bin/curl    --silent --location \"http://x1.c.lencr.org/\" > /tmp/6yJndY"
[DBG]   end time = 1633013609
[DBG]   new timeout = 120
[DBG] Converting /tmp/6yJndY (DER) to /tmp/TAlYfs (PEM)
[DBG] Combining the certificate, the CRL and the root cert
[DBG] cat /tmp/TAlYfs /tmp/PxvY2J /etc/ssl/certs/ca-certificates.crt > /tmp/B3Ltxa
[DBG] /usr/bin/openssl verify -crl_check -CRLfile /tmp/TAlYfs /tmp/f8EnUk
[DBG]   result: certificate has expired
[DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[DBG] prepend_critical_message: new message    = certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: HOST_NAME      = 161.35.218.92
[DBG] prepend_critical_message: HOST_ADDR      = 161.35.218.92
[DBG] prepend_critical_message: CN             = lencr.org
[DBG] prepend_critical_message: SNI            = letsencrypt.org
[DBG] prepend_critical_message: FILE           =
[DBG] prepend_critical_message: SHORTNAME      = SSL_CERT
[DBG] prepend_critical_message: MSG            =
[DBG] prepend_critical_message: CRITICAL_MSG   =
[DBG] prepend_critical_message: ALL_MSG 1      =
[DBG] prepend_critical_message: MSG 2          = SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: ALL_MSG 2      =
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[DBG] ------------------------------------------------------------------------------
[DBG] Checking expiration date of element 3
[DBG] Validity date on cert element 3 is Sep 30 18:14:03 2024 GMT
[DBG] Date computations: GNU
[DBG] Computing number of hours until 'Sep 30 18:14:03 2024 GMT'
[DBG] Hours until Sep 30 18:14:03 2024 GMT: 26307
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 0 on cert element 3
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 604800 on cert element 3
[DBG] executing: /usr/bin/openssl x509 -noout -checkend 1728000 on cert element 3
[DBG] ------------------------------------------------------------------------------
[DBG] Checking OCSP status of element 3
[DBG] temporary file /tmp/al7PHx created
[DBG] Storing the chain element in /tmp/al7PHx
[DBG] ------------------------------------------------------------------------------
[DBG] temporary file /tmp/pEMPbV created
[DBG] Storing the chain element in /tmp/pEMPbV
[DBG] Checking CRL status of element 3
[DBG] Certificate revokation list available (http://crl.identrust.com/DSTROOTCAX3CRL.crl)
[DBG] CRL: fetching CRL http://crl.identrust.com/DSTROOTCAX3CRL.crl to /tmp/6yJndY
[DBG] executing with timeout (120s): /usr/bin/curl    --silent --location \"http://crl.identrust.com/DSTROOTCAX3CRL.crl\" > /tmp/6yJndY
[DBG]   start time = 1633013609
[DBG] /usr/bin/timeout 120 /bin/sh -c "/usr/bin/curl    --silent --location \"http://crl.identrust.com/DSTROOTCAX3CRL.crl\" > /tmp/6yJndY"
[DBG]   end time = 1633013609
[DBG]   new timeout = 120
[DBG] Converting /tmp/6yJndY (DER) to /tmp/TAlYfs (PEM)
[DBG] Combining the certificate, the CRL and the root cert
[DBG] cat /tmp/TAlYfs /tmp/PxvY2J /etc/ssl/certs/ca-certificates.crt > /tmp/B3Ltxa
[DBG] /usr/bin/openssl verify -crl_check -CRLfile /tmp/TAlYfs /tmp/pEMPbV
[DBG]   result: certificate has expired
[DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[DBG] prepend_critical_message: new message    = certificate element 3 is revoked (CRL)
[DBG] prepend_critical_message: HOST_NAME      = 161.35.218.92
[DBG] prepend_critical_message: HOST_ADDR      = 161.35.218.92
[DBG] prepend_critical_message: CN             = lencr.org
[DBG] prepend_critical_message: SNI            = letsencrypt.org
[DBG] prepend_critical_message: FILE           =
[DBG] prepend_critical_message: SHORTNAME      = SSL_CERT
[DBG] prepend_critical_message: MSG            = SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: CRITICAL_MSG   = SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: ALL_MSG 1      =
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: MSG 2          = SSL_CERT CRITICAL lencr.org: certificate element 3 is revoked (CRL)
[DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] prepend_critical_message: ALL_MSG 2      =
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 3 is revoked (CRL)
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[DBG] openssl_version 1.1.0
[DBG] Checking if OpenSSL version is at least 1.1.0 ( '1' '1' '0' ':0' )
[DBG] openssl version: OpenSSL 1.1.1  11 Sep 2018
[DBG] Current version 1.1.1 ( '1' '1' '1' ':0' )
[DBG]   true
[DBG] Checking Signed Certificate Timestamps (SCTs)
[DBG] cleaning up temporary files
[DBG]
[DBG] /tmp/PxvY2J
[DBG] /tmp/TJZWB8
[DBG] /tmp/6yJndY
[DBG] /tmp/TAlYfs
[DBG] /tmp/B3Ltxa
[DBG] /tmp/p3WsHO
[DBG] /tmp/surmmH
[DBG] /tmp/AFAh3C
[DBG] /tmp/f8EnUk
[DBG] /tmp/al7PHx
[DBG] /tmp/pEMPbV
[DBG] exiting with CRITICAL
[DBG] ALL_MSG =
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 3 is revoked (CRL)
[DBG]     SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
[DBG] number of errors = 2
SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)|days_chain_elem1=34;20;7;; days_chain_elem2=1446;20;7;; days_chain_elem3=1096;20;7;;
Error(s):
    SSL_CERT CRITICAL lencr.org: certificate element 3 is revoked (CRL)
    SSL_CERT CRITICAL lencr.org: certificate element 2 is revoked (CRL)
matteocorti commented 2 years ago

I just committed a new version where --skip-element skips a single element and can be specified multiple times