Skip to content

Commit

Permalink
Merge pull request #492 from matteocorti/491-quic-support
Browse files Browse the repository at this point in the history
491 quic support
  • Loading branch information
matteocorti authored Nov 30, 2023
2 parents 7148888 + 4bfc7d2 commit 09eaf20
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 31 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2023-11-30 Matteo Corti <[email protected]>

* check_ssl_cert: Added QUIC support

2023-11-21 Matteo Corti <[email protected]>

* check_ssl_cert (main): Support for LibreSSL and IP addresses
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# News

* QUIC support
* OpenSSL 3.2.0 Support
* 2023-11-23 Version 2.77.0
* Added support for MQTTS
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,10 @@ Options:
integers, 2 otherwise
-P,--protocol protocol Use the specific protocol:
dns, ftp, ftps, http, https (default),
h2 (HTTP/2), imap, imaps, irc, ircs, ldap,
ldaps, mqtts, mysql, pop3, pop3s,
postgres, sieve, smtp, smtps, tds, xmpp,
xmpp-server.
h2 (HTTP/2), h3 (HTTP/3), imap, imaps,
irc, ircs, ldap, ldaps, mqtts, mysql,
pop3, pop3s, postgres, sieve, smtp, smtps,
tds, xmpp, xmpp-server.
ftp, imap, irc, ldap, pop3, postgres,
sieve, smtp: switch to TLS using StartTLS
--password source Password source for a local certificate,
Expand All @@ -213,6 +213,7 @@ Options:
--proxy proxy Set http_proxy and the s_client -proxy
option
--python-bin path Path of the python binary to be used
--quic Use QUIC
-q,--quiet Do not produce any output
-r,--rootcert path Root certificate or directory to be used
for certificate validation
Expand Down
3 changes: 2 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
OpenSSL 3.2.0 Support
* QUIC support
* OpenSSL 3.2.0 support
77 changes: 58 additions & 19 deletions check_ssl_cert
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fetch_http_headers() {
# -L (--location): follow redirects
# -k (--insecure): ignore TLS problems (we want to check the headers anyway)
# -o (--output): discard the output (we are only interested in the HTTP headers)
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_RESOLVE} ${CURL_PROXY_ARGUMENT} ${INETPROTO} -k -s -D- -A '${HTTP_USER_AGENT}' -o /dev/null -L https://${HOST}${path}" "${CACHED_HEADERS}"
exec_with_timeout "${CURL_BIN} ${CURL_QUIC} ${CURL_PROXY} ${CURL_RESOLVE} ${CURL_PROXY_ARGUMENT} ${INETPROTO} -k -s -D- -A '${HTTP_USER_AGENT}' -o /dev/null -L https://${HOST}${path}" "${CACHED_HEADERS}"
RET=$?

if [ "${RET}" -ne 0 ]; then
Expand Down Expand Up @@ -463,10 +463,10 @@ usage() {
echo " integers, 2 otherwise"
echo " -P,--protocol protocol Use the specific protocol:"
echo " dns, ftp, ftps, http, https (default),"
echo " h2 (HTTP/2), imap, imaps, irc, ircs, ldap,"
echo " ldaps, mqtts, mysql, pop3, pop3s,"
echo " postgres, sieve, smtp, smtps, tds, xmpp,"
echo " xmpp-server."
echo " h2 (HTTP/2), h3 (HTTP/3), imap, imaps,"
echo " irc, ircs, ldap, ldaps, mqtts, mysql,"
echo " pop3, pop3s, postgres, sieve, smtp, smtps,"
echo " tds, xmpp, xmpp-server."
echo " ftp, imap, irc, ldap, pop3, postgres,"
echo " sieve, smtp: switch to TLS using StartTLS"
echo " --password source Password source for a local certificate,"
Expand All @@ -477,6 +477,7 @@ usage() {
echo " option"
echo " --python-bin path Path of the python binary to be used"
# Delimiter at 78 chars ############################################################
echo " --quic Use QUIC"
echo " -q,--quiet Do not produce any output"
# Delimiter at 78 chars ############################################################
echo " -r,--rootcert path Root certificate or directory to be used"
Expand Down Expand Up @@ -1904,9 +1905,9 @@ check_crl() {

TIMEOUT_REASON="fetching CRL"
if [ -n "${HTTP_USER_AGENT}" ]; then
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${CRL_URI}\\\" > ${CRL_TMP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${CRL_URI}\\\" > ${CRL_TMP}"
else
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --location \\\"${CRL_URI}\\\" > ${CRL_TMP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --location \\\"${CRL_URI}\\\" > ${CRL_TMP}"
fi
unset TIMEOUT_REASON

Expand Down Expand Up @@ -2033,9 +2034,9 @@ check_ocsp() {

TIMEOUT_REASON="OCSP: fetching issuer ${ELEMENT_ISSUER_URI}"
if [ -n "${HTTP_USER_AGENT}" ]; then
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${ELEMENT_ISSUER_URI}\\\" > ${ISSUER_CERT_TMP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${ELEMENT_ISSUER_URI}\\\" > ${ISSUER_CERT_TMP}"
else
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --location \\\"${ELEMENT_ISSUER_URI}\\\" > ${ISSUER_CERT_TMP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --location \\\"${ELEMENT_ISSUER_URI}\\\" > ${ISSUER_CERT_TMP}"
fi
unset TIMEOUT_REASON

Expand Down Expand Up @@ -2590,7 +2591,11 @@ fetch_certificate() {
fi

# Check if a protocol was specified (if not HTTP switch to TLS)
if [ -n "${PROTOCOL}" ] && [ "${PROTOCOL}" != 'http' ] && [ "${PROTOCOL}" != 'https' ] && [ "${PROTOCOL}" != 'h2' ]; then
if [ -n "${PROTOCOL}" ] &&
[ "${PROTOCOL}" != 'http' ] &&
[ "${PROTOCOL}" != 'https' ] &&
[ "${PROTOCOL}" != 'h2' ] &&
[ "${PROTOCOL}" != 'h3' ]; then

case "${PROTOCOL}" in
pop3 | ftp)
Expand Down Expand Up @@ -2787,9 +2792,11 @@ fetch_certificate() {

if [ "${PROTOCOL}" = 'h2' ]; then
ALPN="-alpn h2"
elif [ "${PROTOCOL}" = 'h3' ]; then
ALPN="-alpn h3"
fi

exec_with_timeout "printf '${HTTP_REQUEST}' | ${OPENSSL} s_client ${SECURITY_LEVEL} ${INETPROTO} ${CLIENT} ${CLIENTPASS} -crlf ${ALPN} -connect ${HOST_ADDR}:${PORT} ${SERVERNAME} ${SCLIENT_PROXY} ${SCLIENT_PROXY_ARGUMENT} -showcerts -verify 6 ${ROOT_CA} ${SSL_VERSION} ${SSL_VERSION_DISABLED} ${SSL_AU} ${STATUS} ${DANE} ${RENEGOTIATION} 2> ${ERROR} 1> ${CERT}"
exec_with_timeout "printf '${HTTP_REQUEST}' | ${OPENSSL} s_client ${QUIC} ${SECURITY_LEVEL} ${INETPROTO} ${CLIENT} ${CLIENTPASS} -crlf ${ALPN} -connect ${HOST_ADDR}:${PORT} ${SERVERNAME} ${SCLIENT_PROXY} ${SCLIENT_PROXY_ARGUMENT} -showcerts -verify 6 ${ROOT_CA} ${SSL_VERSION} ${SSL_VERSION_DISABLED} ${SSL_AU} ${STATUS} ${DANE} ${RENEGOTIATION} 2> ${ERROR} 1> ${CERT}"
RET=$?

fi
Expand Down Expand Up @@ -2877,6 +2884,10 @@ fetch_certificate() {
prepend_critical_message 'Self signed certificate'
fi

elif ascii_grep 'quic_do_handshake' "${ERROR}"; then

prepend_critical_message 'QUIC not supported'

elif ascii_grep 'dh[ ]key[ ]too[ ]small' "${ERROR}"; then

prepend_critical_message 'DH with a key too small'
Expand Down Expand Up @@ -3008,6 +3019,10 @@ fetch_certificate() {
if ! "${GREP_BIN}" -q -F 'ALPN protocol: h2' "${CERT}"; then
prepend_critical_message 'The server does not support HTTP/2'
fi
elif [ "${PROTOCOL}" = 'h3' ]; then
if ! "${GREP_BIN}" -q -F 'ALPN protocol: h3' "${CERT}"; then
prepend_critical_message 'The server does not support HTTP/3'
fi
fi

fi
Expand Down Expand Up @@ -3325,6 +3340,10 @@ parse_command_line_options() {
PROMETHEUS=1
shift
;;
--quic)
QUIC='-quic'
shift
;;
-q | --quiet)
QUIET=1
shift
Expand Down Expand Up @@ -4221,7 +4240,7 @@ main() {
http)
PORT=80
;;
https | h2)
https | h2 | h3)
PORT=443
;;
mqtts)
Expand Down Expand Up @@ -4378,6 +4397,26 @@ main() {
check_required_prog "${OPENSSL}"
OPENSSL=${PROG}

if [ -n "${QUIC}" ] ; then

require_s_client_option '-quic'

# QUIC requires HTTP/2
if [ -n "${PROTOCOL}" ] && [ "${PROTOCOL}" != 'h3' ]; then
critical 'QUIC only works with HTTP/2'
else
verboselog '--quic specified enabling HTTP/3'
PROTOCOL='h3'
fi

# check if curl supports HTTP/3
if curl --help all | grep -q -- --http3 ; then
debuglog 'curl supports HTTP/3'
CURL_QUIC='--http3'
fi

fi

##############################################################################
# custom grep
if [ -z "${GREP_BIN}" ]; then
Expand Down Expand Up @@ -4618,7 +4657,7 @@ main() {
DNS_OVER_HTTP=${TEMPFILE}

TIMEOUT_REASON="Resolving over HTTP with ${RESOLVE_OVER_HTTP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' -H 'Content-Type: application/dns-json' https://${RESOLVE_OVER_HTTP}/resolve?name=${HOST}\\&type=A" "${DNS_OVER_HTTP}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' -H 'Content-Type: application/dns-json' https://${RESOLVE_OVER_HTTP}/resolve?name=${HOST}\\&type=A" "${DNS_OVER_HTTP}"

if [ "${DEBUG}" -ge 1 ]; then
jq < "${DNS_OVER_HTTP}" | sed 's/^/[DBG] /' 1>&2
Expand Down Expand Up @@ -4888,9 +4927,9 @@ main() {

TIMEOUT_REASON="fetching certificate file"
if [ -n "${HTTP_USER_AGENT}" ]; then
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${FILE_URI}\\\" > ${FILE}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --user-agent '${HTTP_USER_AGENT}' --location \\\"${FILE_URI}\\\" > ${FILE}"
else
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent --location \\\"${FILE_URI}\\\" > ${FILE}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent --location \\\"${FILE_URI}\\\" > ${FILE}"
fi
unset TIMEOUT_REASON

Expand Down Expand Up @@ -5366,7 +5405,7 @@ main() {
# Check if curl is needed and if it supports the -4 and -6 options
if [ -z "${CURL_BIN}" ]; then
if [ -n "${SSL_LAB_CRIT_ASSESSMENT}" ] || [ -n "${OCSP}" ]; then
if ! "${CURL_BIN}" --manual | "${GREP_BIN}" -F -q -- -6 && [ -n "${INETPROTO}" ]; then
if ! "${CURL_BIN}" --help all | "${GREP_BIN}" -F -q -- -6 && [ -n "${INETPROTO}" ]; then
unknown "curl does not support the ${INETPROTO} option"
fi
fi
Expand Down Expand Up @@ -6640,13 +6679,13 @@ ${WARNING}"
debuglog "http_proxy = ${http_proxy}"
debuglog "HTTPS_PROXY = ${HTTPS_PROXY}"
debuglog "executing ${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent \"https://api.ssllabs.com/api/v2/analyze?host=${HOST_NAME}${IGNORE_SSL_LABS_CACHE}\""
debuglog "executing ${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent \"https://api.ssllabs.com/api/v2/analyze?host=${HOST_NAME}${IGNORE_SSL_LABS_CACHE}\""
if [ -n "${SNI}" ]; then
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent \\\"https://api.ssllabs.com/api/v2/analyze?host=${SNI}${IGNORE_SSL_LABS_CACHE}\\\" > ${JSON}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent \\\"https://api.ssllabs.com/api/v2/analyze?host=${SNI}${IGNORE_SSL_LABS_CACHE}\\\" > ${JSON}"
CURL_RETURN_CODE=$?
else
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${INETPROTO} --silent \\\"https://api.ssllabs.com/api/v2/analyze?host=${HOST_NAME}${IGNORE_SSL_LABS_CACHE}\\\" > ${JSON}"
exec_with_timeout "${CURL_BIN} ${CURL_PROXY} ${CURL_PROXY_ARGUMENT} ${CURL_QUIC} ${INETPROTO} --silent \\\"https://api.ssllabs.com/api/v2/analyze?host=${HOST_NAME}${IGNORE_SSL_LABS_CACHE}\\\" > ${JSON}"
CURL_RETURN_CODE=$?
fi
Expand Down
5 changes: 4 additions & 1 deletion check_ssl_cert.1
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ TCP port (default 443)
Number of decimal places for durations: defaults to 0 if critical or warning are integers, 2 otherwise
.TP
.BR "-P,--protocol" " protocol"
Use the specific protocol: dns, ftp, ftps, http, https (default), h2 (HTTP/2), imap, imaps, irc, ircs, ldap, ldaps, mqtts, mysql, pop3, pop3s, postgres, sieve, smtp, smtps, tds, xmpp, xmpp-server, ftp, imap, irc, ldap, pop3, postgres, sieve, smtp: switch to TLS using StartTLS.
Use the specific protocol: dns, ftp, ftps, http, https (default), h2 (HTTP/2), h3 (HTTP/3), imap, imaps, irc, ircs, ldap, ldaps, mqtts, mysql, pop3, pop3s, postgres, sieve, smtp, smtps, tds, xmpp, xmpp-server, ftp, imap, irc, ldap, pop3, postgres, sieve, smtp: switch to TLS using StartTLS.
.BR
These protocols switch to TLS using StartTLS: ftp, imap, irc, ldap, mysql, pop3, smtp.
.TP
Expand All @@ -349,6 +349,9 @@ Set http_proxy and the s_client -proxy option
.BR " --python-bin" " path"
Path of the python binary to be used
.TP
.BR " --quic"
Use QUIC
.TP
.BR "-q,--quiet"
Do not produce any output
.TP
Expand Down
2 changes: 1 addition & 1 deletion check_ssl_cert.completion
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ _check_ssl_cert() {
# only the autocompletion with long options is implemented: long options are more readable and quick to enter since we are
# using autocompletion.
#
opts="--file --host --noauth --all --all-local --allow-empty-san --clientcert --configuration --critical --check-chain --check-ciphers --check-ciphers-warnings --check-http-headers --check-ssl-labs --check-ssl-labs-warn --clientpass --crl --curl-bin --user-agent --custom-http-header --dane --date --debug-cert --debug-file --debug-headers --debug-time --default-format --dig-bin --do-not-resolve --dtls --dtls1 --dtls1_2 --ecdsa --element --file-bin --fingerprint --first-element-only --force-dconv-date --force-perl-date --format --grep-bin --http-headers-path --http-use-get --ignore-altnames --jks-alias --ignore-connection-problems --ignore-exp --ignore-http-headers --ignore-host-cn --ignore-incomplete-chain --ignore-maximum-validity --ignore-ocsp --ignore-ocsp-errors --ignore-ocsp-timeout --ignore-sct --ignore-sig-alg --ignore-ssl-labs-cache --ignore-tls-renegotiation --inetproto protocol --info --init-host-cache --issuer-cert-cache --long-output --match --maximum-validity --nmap-bin --no-perf --no-proxy --no-proxy-curl --no-proxy-s_client --no-ssl2 --no-ssl3 --no-tls1 --no-tls1_1 --no-tls1_2 --no-tls1_3 --not-issued-by --not-valid-longer-than --ocsp-critical --ocsp-warning --openssl --password --path --precision --prometheus --proxy --require-client-cert --require-dnssec --require-http-header --require-no-http-header --require-no-ssl2 --require-no-ssl3 --require-no-tls1 --require-no-tls1_1 --require-ocsp-stapling --require-purpose --require-purpose-critical --resolve --resolve-over-http --rootcert-dir --rootcert-file --rsa --serial --security-level --skip-element --sni --ssl2 --ssl3 --temp --terse --tls1 --tls1_1 --tls1_2 --tls1_3 --xmpphost -4 -6 --clientkey --protocol --version --debug --email --help --issuer --cn --org --port port --rootcert --quiet --selfsigned --timeout --url --verbose --warning --python-bin"
opts="--file --host --noauth --all --all-local --allow-empty-san --clientcert --configuration --critical --check-chain --check-ciphers --check-ciphers-warnings --check-http-headers --check-ssl-labs --check-ssl-labs-warn --clientpass --crl --curl-bin --user-agent --custom-http-header --dane --date --debug-cert --debug-file --debug-headers --debug-time --default-format --dig-bin --do-not-resolve --dtls --dtls1 --dtls1_2 --ecdsa --element --file-bin --fingerprint --first-element-only --force-dconv-date --force-perl-date --format --grep-bin --http-headers-path --http-use-get --ignore-altnames --jks-alias --ignore-connection-problems --ignore-exp --ignore-http-headers --ignore-host-cn --ignore-incomplete-chain --ignore-maximum-validity --ignore-ocsp --ignore-ocsp-errors --ignore-ocsp-timeout --ignore-sct --ignore-sig-alg --ignore-ssl-labs-cache --ignore-tls-renegotiation --inetproto protocol --info --init-host-cache --issuer-cert-cache --long-output --match --maximum-validity --nmap-bin --no-perf --no-proxy --no-proxy-curl --no-proxy-s_client --no-ssl2 --no-ssl3 --no-tls1 --no-tls1_1 --no-tls1_2 --no-tls1_3 --not-issued-by --not-valid-longer-than --ocsp-critical --ocsp-warning --openssl --password --path --precision --prometheus --proxy --require-client-cert --require-dnssec --require-http-header --require-no-http-header --require-no-ssl2 --require-no-ssl3 --require-no-tls1 --require-no-tls1_1 --require-ocsp-stapling --require-purpose --require-purpose-critical --resolve --resolve-over-http --rootcert-dir --rootcert-file --rsa --serial --security-level --skip-element --sni --ssl2 --ssl3 --temp --terse --tls1 --tls1_1 --tls1_2 --tls1_3 --xmpphost -4 -6 --clientkey --protocol --version --debug --email --help --issuer --cn --org --port port --rootcert --quic --quiet --selfsigned --timeout --url --verbose --warning --python-bin"

if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]]; then
# shellcheck disable=2207
Expand Down
7 changes: 6 additions & 1 deletion check_ssl_cert_icinga2.conf
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,12 @@ object CheckCommand "ssl_cert_extended" {
description = "Path of the python binary to be used"
}

"--quiet" = {
"--quic" = {
set_if = "$ssl_cert_extended_quic$"
description = "Use QUIC"
}

"--quiet" = {
set_if = "$ssl_cert_extended_quiet$"
description = "Do not produce any output"
}
Expand Down
1 change: 0 additions & 1 deletion test/derlink.cer

This file was deleted.

Binary file added test/derlink.cer
Binary file not shown.
20 changes: 20 additions & 0 deletions test/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,26 @@ testMQTTS() {
assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}"
}

testQUIC() {

if [ -n "${http_proxy}" ] ; then

echo "Skipping: no proxy support for QUIC"

elif "${OPENSSL}" s_client -help 2>&1 | grep -q -- -quic ; then

# shellcheck disable=SC2086
${SCRIPT} ${TEST_DEBUG} --host www.google.com --quic
EXIT_CODE=$?
assertEquals "wrong exit code" "${NAGIOS_OK}" "${EXIT_CODE}"

else

echo "Skipping: OpenSSL does not support QUIC"

fi
}

testDNS() {

# shellcheck disable=SC2086
Expand Down
Loading

0 comments on commit 09eaf20

Please sign in to comment.