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

Check does not work for certificates in DER and PKCS12 formats #254

Closed matteocorti closed 3 years ago

matteocorti commented 3 years ago

Hi There!

Your check is a very good idea, but i can't check certs with DER format, and P12. I get the message " SSL_CERT CRITICAL /cert path/cert name.p12: is not a valid certificate file " Please help me what is wrong. Thank you

_Originally posted by @szcsdev in https://github.com/matteocorti/check_ssl_cert/discussions/253_

szcsdev commented 3 years ago

sample_certs.zip

There is two certs, one of them a .p12, and the other is DER encoded.

I put in the client folder /var/opt/cn.p12 and /var/opt/cn.cer The command that i call in nagios: command[check_local_ssl4]=/usr/lib64/nagios/plugins/check_ssl_cert -H localhost -f /var/opt/cn.cer -c 30 -w 60 --ignore-sct

and i get the following error message: SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file

matteocorti commented 3 years ago

Did you provide a transport password for the PKCS #12 file?

szcsdev commented 3 years ago

The two format .cer and .p12 do not have a password. I downloaded the version 1.141 but nothing changed. How can i send you detailed information. Regards

szcsdev commented 3 years ago

I found the debug mode. Here is the output: [root@client ~]# /usr/lib64/nagios/plugins/check_ssl_cert -H localhost -f /var/opt/cn.cer -d [DBG] Command line arguments: -H localhost -f /var/opt/cn.cer -d [DBG] -c specified: 15 [DBG] ROOT_CA = [DBG] file version: file-5.33 [DBG] magic file from /etc/magic:/usr/share/misc/magic [DBG] cURL binary needed. SSL Labs = , OCSP = 1, CURL = [DBG] cURL binary not specified [DBG] cURL available: /usr/bin/curl [DBG] curl 7.61.1 (x86_64-redhat-linux-gnu) libcurl/7.61.1 OpenSSL/1.1.1g zlib/1.2.11 brotli/1.0.6 libidn2/2.2.0 libpsl/0.20.2 (+libidn2/2.2.0) libssh/0.9.4/openssl/zlib nghttp2/1.33.0 [DBG] Release-Date: 2018-09-05 [DBG] Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp [DBG] Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz brotli TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL Metalink [DBG] nmap binary not needed. No disallowed protocols expect available (/usr/bin/expect) timeout available (/usr/bin/timeout) [DBG] perl available: /usr/bin/perl [DBG] date available: /usr/bin/date [DBG] checking date version found GNU date with timestamp support: enabling date computations [DBG] check_ssl_cert version: 1.141.0 [DBG] OpenSSL binary: /usr/bin/openssl [DBG] OpenSSL version: OpenSSL 1.1.1g FIPS 21 Apr 2020 [DBG] OpenSSL configuration directory: /etc/pki/tls [DBG] 136 root certificates installed by default [DBG] System info: Linux client 4.18.0-240.10.1.el8_3.x86_64 #1 SMP Mon Jan 18 17:05:51 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux [DBG] Date computation: GNU [DBG] '/usr/bin/openssl s_client' supports '-servername': using -servername localhost [DBG] '/usr/bin/openssl s_client' supports '-name': using client [DBG] '/usr/bin/openssl s_client' supports '-xmpphost': using -xmpphost localhost [DBG] temporary file /tmp/vEcmQL created [DBG] temporary file /tmp/ra4V5u created [DBG] temporary file /tmp/EbaVww created [DBG] temporary file /tmp/L5VXGL created [DBG] temporary file /tmp/OYIjvX created [DBG] temporary file /tmp/RqLBXF created [DBG] temporary file /tmp/NqtR7q created downloading certificate to /tmp [DBG] localhost is not an IP address [DBG] check if we have to convert the file /var/opt/cn.cer to PEM [DBG] certificate type (1): data [DBG] storing the certificate to /tmp/vEcmQL [DBG] certificate type (2): data [DBG] storing a copy of the retrieved certificate in localhost.crt [DBG] Return value of the command = 0 [DBG] storing a copy of the retrieved certificate in /tmp/localhost-443.crt [DBG] storing a copy of the OpenSSL errors in /tmp/localhost-443.error Checking TLS renegotiation unable to load CRL 140510991931200:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149: 140510991931200:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:309:Type=X509_ALGOR 140510991931200:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=sig_alg, Type=X509_CRL_INFO 140510991931200:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=crl, Type=X509_CRL [DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [DBG] prepend_critical_message: new message = '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: HOST = localhost [DBG] prepend_critical_message: CN = [DBG] prepend_critical_message: SNI = [DBG] prepend_critical_message: FILE = /var/opt/cn.cer [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 /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 2 = \n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< parsing the certificate file Invalid command ''; type "help" for a list. unable to load certificate 140639392413504:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE Certificate without common name (CN), enabling altername names unable to load certificate 140502732044096:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE unable to load certificate 140199729223488:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE unable to load certificate 140687128213312:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE Invalid command ''; type "help" for a list. [DBG] Skipping 0 element of the chain [DBG] ISSUERS = [DBG] [DBG] ISSUERS = [DBG] Invalid command ''; type "help" for a list. Invalid command ''; type "help" for a list. [DBG] [DBG] CN = CN unavailable [DBG] CA = [DBG] SERIAL = [DBG] FINGERPRINT= [DBG] OCSP_URI = [DBG] ISSUER_URI = [DBG] Invalid command ''; type "help" for a list. [DBG] subjectAlternativeName = [DBG] Checking expiration date [DBG] Number of certificates in CA chain: 0 [DBG] Skipping 0 element of the chain [DBG] ------------------------------------------------------------------------------ [DBG] Checking Signed Certificate Timestamps (SCTs) unable to load certificate 140245425948480:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE [DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [DBG] prepend_critical_message: new message = Cannot find Signed Certificate Timestamps (SCT) [DBG] prepend_critical_message: HOST = localhost [DBG] prepend_critical_message: CN = CN unavailable [DBG] prepend_critical_message: SNI = [DBG] prepend_critical_message: FILE = /var/opt/cn.cer [DBG] prepend_critical_message: SHORTNAME = SSL_CERT [DBG] prepend_critical_message: MSG = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: CRITICAL_MSG = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 1 = \n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: MSG 2 = SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT) [DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 2 = \n SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT)\n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< [DBG] cleaning up temporary files [DBG] [DBG] /tmp/vEcmQL [DBG] /tmp/ra4V5u [DBG] /tmp/EbaVww [DBG] /tmp/L5VXGL [DBG] /tmp/OYIjvX [DBG] /tmp/RqLBXF [DBG] /tmp/NqtR7q [DBG] exiting with CRITICAL [DBG] ALL_MSG = \n SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT)\n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] number of errors = 2 SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file Error(s): SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT) SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [root@client ~]# /usr/lib64/nagios/plugins/check_ssl_cert -H localhost -f /var/opt/cn.cer -d [DBG] Command line arguments: -H localhost -f /var/opt/cn.cer -d [DBG] -c specified: 15 [DBG] ROOT_CA = [DBG] file version: file-5.33 [DBG] magic file from /etc/magic:/usr/share/misc/magic [DBG] cURL binary needed. SSL Labs = , OCSP = 1, CURL = [DBG] cURL binary not specified [DBG] cURL available: /usr/bin/curl [DBG] curl 7.61.1 (x86_64-redhat-linux-gnu) libcurl/7.61.1 OpenSSL/1.1.1g zlib/1.2.11 brotli/1.0.6 libidn2/2.2.0 libpsl/0.20.2 (+libidn2/2.2.0) libssh/0.9.4/openssl/zlib nghttp2/1.33.0 [DBG] Release-Date: 2018-09-05 [DBG] Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp [DBG] Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz brotli TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL Metalink [DBG] nmap binary not needed. No disallowed protocols expect available (/usr/bin/expect) timeout available (/usr/bin/timeout) [DBG] perl available: /usr/bin/perl [DBG] date available: /usr/bin/date [DBG] checking date version found GNU date with timestamp support: enabling date computations [DBG] check_ssl_cert version: 1.141.0 [DBG] OpenSSL binary: /usr/bin/openssl [DBG] OpenSSL version: OpenSSL 1.1.1g FIPS 21 Apr 2020 [DBG] OpenSSL configuration directory: /etc/pki/tls [DBG] 136 root certificates installed by default [DBG] System info: Linux client 4.18.0-240.10.1.el8_3.x86_64 #1 SMP Mon Jan 18 17:05:51 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux [DBG] Date computation: GNU [DBG] '/usr/bin/openssl s_client' supports '-servername': using -servername localhost [DBG] '/usr/bin/openssl s_client' supports '-name': using client [DBG] '/usr/bin/openssl s_client' supports '-xmpphost': using -xmpphost localhost [DBG] temporary file /tmp/76mi3k created [DBG] temporary file /tmp/nEsj06 created [DBG] temporary file /tmp/QqcnKv created [DBG] temporary file /tmp/lEvVoN created [DBG] temporary file /tmp/XTlTvW created [DBG] temporary file /tmp/1LMe6V created [DBG] temporary file /tmp/8YTAZa created downloading certificate to /tmp [DBG] localhost is not an IP address [DBG] check if we have to convert the file /var/opt/cn.cer to PEM [DBG] certificate type (1): data [DBG] storing the certificate to /tmp/76mi3k [DBG] certificate type (2): data [DBG] storing a copy of the retrieved certificate in localhost.crt [DBG] Return value of the command = 0 [DBG] storing a copy of the retrieved certificate in /tmp/localhost-443.crt [DBG] storing a copy of the OpenSSL errors in /tmp/localhost-443.error Checking TLS renegotiation unable to load CRL 139924215375680:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag:crypto/asn1/tasn_dec.c:1149: 139924215375680:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:309:Type=X509_ALGOR 139924215375680:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=sig_alg, Type=X509_CRL_INFO 139924215375680:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:646:Field=crl, Type=X509_CRL [DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [DBG] prepend_critical_message: new message = '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: HOST = localhost [DBG] prepend_critical_message: CN = [DBG] prepend_critical_message: SNI = [DBG] prepend_critical_message: FILE = /var/opt/cn.cer [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 /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 2 = \n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< parsing the certificate file Invalid command ''; type "help" for a list. unable to load certificate 140019819181888:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE Certificate without common name (CN), enabling altername names unable to load certificate 140368315512640:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE unable to load certificate 139836825110336:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE unable to load certificate 140388954416960:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE Invalid command ''; type "help" for a list. [DBG] Skipping 0 element of the chain [DBG] ISSUERS = [DBG] [DBG] ISSUERS = [DBG] Invalid command ''; type "help" for a list. Invalid command ''; type "help" for a list. [DBG] [DBG] CN = CN unavailable [DBG] CA = [DBG] SERIAL = [DBG] FINGERPRINT= [DBG] OCSP_URI = [DBG] ISSUER_URI = [DBG] Invalid command ''; type "help" for a list. [DBG] subjectAlternativeName = [DBG] Checking expiration date [DBG] Number of certificates in CA chain: 0 [DBG] Skipping 0 element of the chain [DBG] ------------------------------------------------------------------------------ [DBG] Checking Signed Certificate Timestamps (SCTs) unable to load certificate 140442121303872:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE [DBG] CRITICAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [DBG] prepend_critical_message: new message = Cannot find Signed Certificate Timestamps (SCT) [DBG] prepend_critical_message: HOST = localhost [DBG] prepend_critical_message: CN = CN unavailable [DBG] prepend_critical_message: SNI = [DBG] prepend_critical_message: FILE = /var/opt/cn.cer [DBG] prepend_critical_message: SHORTNAME = SSL_CERT [DBG] prepend_critical_message: MSG = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: CRITICAL_MSG = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 1 = \n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: MSG 2 = SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT) [DBG] prepend_critical_message: CRITICAL_MSG 2 = SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] prepend_critical_message: ALL_MSG 2 = \n SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT)\n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] CRITICAL <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< [DBG] cleaning up temporary files [DBG] [DBG] /tmp/76mi3k [DBG] /tmp/nEsj06 [DBG] /tmp/QqcnKv [DBG] /tmp/lEvVoN [DBG] /tmp/XTlTvW [DBG] /tmp/1LMe6V [DBG] /tmp/8YTAZa [DBG] exiting with CRITICAL [DBG] ALL_MSG = \n SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT)\n SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file [DBG] number of errors = 2 SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file Error(s): SSL_CERT CRITICAL CN unavailable: Cannot find Signed Certificate Timestamps (SCT) SSL_CERT CRITICAL /var/opt/cn.cer: '/var/opt/cn.cer' is not a valid certificate file

matteocorti commented 3 years ago

Are you sure you are using the latest commit?

I see

[DBG] certificate type (1): data

and this should be caught by then next condition in the code.

I committed a new version with some more debugging output.

Can you please try again?

szcsdev commented 3 years ago

Hi There!

With the .cer file is ok but the p12 isn't good. It ask for password but isn't have password. When i hit enter, the debug goes further but i can't see how can i disable or where can i add the password if i need. Regards.

matteocorti commented 3 years ago

The p12 file you provided requires indeed a password. PKCS #12 files contain both the certificate and the password and are encrypted with a transport password.

Now: OpenSSL allows several methods to pass the password on the command line. Either you type the password when prompted (secure option) or you store the password somewhere so that a script can use it (unsecure).

I could try to allow the same options for the script ...

Do you really have a certificate in PCKS #12 without a key in it?

szcsdev commented 3 years ago

This is a sample certificate. But in real environment I think it will be a good thing that the check can use a password parameter that i can set up in the nrpe.cfg file, and nagios can show .p12 certificate expiry without user attraction.

Is this possible, or have any idea for it?

matteocorti commented 3 years ago

I can try but the question was if there is really a use case. Usually PKCS files are just used to transport the certificate and the key to another machine. They are (as far as I know) accessible.

Do you really have a server publishing a .p12 key? Or do you want to check local files before distributing them?

szcsdev commented 3 years ago

So the problem is, i have a timestamp server which have a client certificate in .p12 format and have a password. The problem is, we always forget to renew the certificate in time. Thatways i want to check the .p12 cert with nagios to have an alert when it expire. Usually your check works well, - i checked with the real .p12 - but don't want to write in a password to a console, or popup, i want to store in the nrpe.cfg file like a parameter. I found a shell script that do same with java keystores - there is a --password parameter, and the keytool open the file, and scan the certs inside.

matteocorti commented 3 years ago

I see, the use case makes perfectly sense.

OpenSSL offers the following

   Pass Phrase Options
       Several commands accept password arguments, typically using -passin and -passout for input and output passwords
       respectively. These allow the password to be obtained from a variety of sources. Both of these options take a
       single argument whose format is described below. If no password argument is given and a password is required then
       the user is prompted to enter one: this will typically be read from the current terminal with echoing turned off.

       Note that character encoding may be relevant, please see passphrase-encoding(7).

       pass:password
           The actual password is password. Since the password is visible to utilities (like 'ps' under Unix) this form
           should only be used where security is not important.

       env:var
           Obtain the password from the environment variable var. Since the environment of other processes is visible on
           certain platforms (e.g. ps under certain Unix OSes) this option should be used with caution.

       file:pathname
           The first line of pathname is the password. If the same pathname argument is supplied to -passin and -passout
           arguments then the first line will be used for the input password and the next line for the output password.
           pathname need not refer to a regular file: it could for example refer to a device or named pipe.

       fd:number
           Read the password from the file descriptor number. This can be used to send the data via a pipe for example.

       stdin
           Read the password from standard input.

I could add a command line option that passes the parameter to OpenSSL (just for the local file checks)

szcsdev commented 3 years ago

that sounds great!

matteocorti commented 3 years ago

Should work now.

Example with your file

$ export PASS=
$ ./check_ssl_cert -H localhost -f ./test/client.p12 --password env:PASS --ignore-sct
SSL_CERT OK - x509 certificate 'CN' from 'CN' valid until Mar  3 19:41:39 2022 GMT (expires in 358 days)|days_chain_elem1=358;20;15;;