Or, yet another attempt at starting a discussion on this... :/ (I kinda lost track of the feature freeze date, if any has been decided for this release cycle, so apologies if this comes at the wrong moment).
I attached the patches that implement OCSP stapling for both GnuTLS and NSS backends, and the --cert-status option for curl. They also include documentation for both the libcurl and curl options. So, the GnuTLS and NSS backends are, AFAICT, fully functional. The failures I was seeing in the GnuTLS backend were caused by a bug in GnuTLS itself, which got fixed in the 3.3.11 release. You may still see failures due to a bug in libtasn1 (used by GnuTLS), which got fixed in the 4.2 release (for reference see [0] and [1]). As for the OpenSSL (which I left out for now) backend, I'm pretty sure OpenSSL's OCSP support is broken, since it requires the issuer certificate to be in the trust store (which basically means that e.g. an intermediate certificate needs to be in the store, even if it's itself signed by a CA certificate). Notably, this breaks pretty much all CloudFlare sites (or any sites that use intermediate certificates) unless those issuers are trusted with --capath/--cacert. I haven't looked into this yet, but I'll probably file a bug report at some point, and finish up the curl support if/when this gets fixed. Even without OpenSSL support (which can be added later on), I think this is ready to be merged. For testing, you can use the following websites that support OCSP stapling: https://yahoo.com https://mozilla.org https://tn123.org https://digitalocean.com (from CloudFlare) https://kuix.de:5148 https://kuix.de:5149 (this got its certificate revoked, so the check must fail) I've kept the patches separate to ease development and review, but I can merge them if needed. Cheers [0] https://bugs.debian.org/772055 [1] https://bugs.debian.org/759161
From 716621191cedb61c8972e68320a3d9aa99a7682c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Mon, 16 Jun 2014 13:20:47 +0200 Subject: [PATCH 1/4] url: add CURLOPT_SSL_VERIFYSTATUS option This option can be used to enable/disable certificate status verification. The certificate status can be obtained by using the "Certificate Status Request" TLS extension defined in RFC6066 section 8, or by using the OCSP protocol defined in RFC6960. This also adds the CURLE_SSL_INVALIDCERTSTATUS error, to be used when the certificate status verification fails. --- docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 | 52 ++++++++++++++++++++++++++++ include/curl/curl.h | 4 +++ lib/url.c | 6 ++++ lib/urldata.h | 1 + 4 files changed, 63 insertions(+) create mode 100644 docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 new file mode 100644 index 0000000..ffbbe96 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.3 @@ -0,0 +1,52 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at http://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH CURLOPT_SSL_VERIFYSTATUS 3 "04 Dec 2014" "libcurl 7.40.0" "curl_easy_setopt options" +.SH NAME +CURLOPT_SSL_VERIFYSTATUS \- verify the certificate's status +.SH SYNOPSIS +#include <curl/curl.h> + +CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYSTATUS, long verify); +.SH DESCRIPTION +Pass a long as parameter to enable or disable. + +This option determines whether libcurl verifies the status of the server cert +using the "Certificate Status Request" TLS extension (aka. OCSP stapling). + +Note that if this option is enabled but the server does not support the TLS +extension, the verification will fail. + +.SH DEFAULT +0 +.SH PROTOCOLS +All TLS based protocols: HTTPS, FTPS, IMAPS, POP3, SMTPS etc. +.SH EXAMPLE +TODO +.SH AVAILABILITY +This is currently only supported by the GnuTLS and NSS TLS backends. +.SH RETURN VALUE +Returns CURLE_OK if TLS is enabled, CURLE_UNKNOWN_OPTION if not. +.SH "SEE ALSO" +.BR CURLOPT_SSL_VERIFYHOST "(3), " +.BR CURLOPT_SSL_VERIFYPEER "(3), " +.BR CURLOPT_CAINFO "(3), " diff --git a/include/curl/curl.h b/include/curl/curl.h index 0915a20..d334087 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -523,6 +523,7 @@ typedef enum { session will be queued */ CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ CURL_LAST /* never use! */ } CURLcode; @@ -1622,6 +1623,9 @@ typedef enum { /* Path to UNIX domain socket */ CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/url.c b/lib/url.c index d191678..6762a6f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1996,6 +1996,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE; break; + case CURLOPT_SSL_VERIFYSTATUS: + /* + * Enable certificate status verifying. + */ + data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE; + break; case CURLOPT_SSL_CTX_FUNCTION: #ifdef have_curlssl_ssl_ctx /* diff --git a/lib/urldata.h b/lib/urldata.h index a2dc1c3..4efa466 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -366,6 +366,7 @@ struct ssl_config_data { bool verifypeer; /* set TRUE if this is desired */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */ + bool verifystatus; /* set TRUE if certificate status must be checked */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ const char *CRLfile; /* CRL to check certificate revocation */ -- 2.1.3
From 43039da0bb15885a5fc04430e5f065b4dbbeb5d9 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Mon, 16 Jun 2014 13:21:02 +0200 Subject: [PATCH 2/4] gtls: add support for the Certificate Status Request TLS extension Also known as "status_request" or OCSP stapling, defined in RFC6066 section 8. This requires GnuTLS 3.1.3 or higher to build, however it's recommended to use at least GnuTLS 3.3.11 since previous versions had a bug that caused the OCSP response verfication to fail even on valid responses. --- lib/vtls/gtls.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index a9c42c2..837f772 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -98,6 +98,14 @@ static bool gtls_inited = FALSE; # define HAS_ALPN # endif # endif + +# if (GNUTLS_VERSION_NUMBER >= 0x03020d) +# define HAS_OCSP +# endif +#endif + +#ifdef HAS_OCSP +# include <gnutls/ocsp.h> #endif /* @@ -663,6 +671,16 @@ gtls_connect_step1(struct connectdata *conn, /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); + if(rc != GNUTLS_E_SUCCESS) { + failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif + /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ @@ -822,6 +840,23 @@ gtls_connect_step3(struct connectdata *conn, else infof(data, "\t server certificate verification SKIPPED\n"); +#ifdef HAS_OCSP + if(data->set.ssl.verifystatus) { + if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { + if(verify_status & GNUTLS_CERT_REVOKED) + failf(data, "SSL server certificate was REVOKED\n"); + else + failf(data, "SSL server certificate status verification FAILED"); + + return CURLE_SSL_INVALIDCERTSTATUS; + } + else + infof(data, "SSL server certificate status verification OK\n"); + } + else + infof(data, "SSL server certificate status verification SKIPPED\n"); +#endif + /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); -- 2.1.3
From 9fc4ca255ec1198b0e5428b543b1242a7d9a197c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Tue, 24 Jun 2014 23:25:59 +0200 Subject: [PATCH 3/4] nss: add support for the Certificate Status Request TLS extension Also known as "status_request" or OCSP stapling, defined in RFC6066 section 8. This requires NSS 3.15 or higher. --- lib/vtls/nss.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index f26cba0..251c21f 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -638,6 +638,34 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, PRBool isServer) { struct connectdata *conn = (struct connectdata *)arg; + +#ifdef SSL_ENABLE_OCSP_STAPLING + if(conn->data->set.ssl.verifystatus) { + SECStatus cacheResult; + + const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); + if(!csa) { + failf(conn->data, "Invalid OCSP response"); + return SECFailure; + } + + if(csa->len == 0) { + failf(conn->data, "No OCSP response received"); + return SECFailure; + } + + cacheResult = CERT_CacheOCSPResponseFromSideChannel( + CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd), + PR_Now(), &csa->items[0], arg + ); + + if(cacheResult != SECSuccess) { + failf(conn->data, "Invalid OCSP response"); + return cacheResult; + } + } +#endif + if(!conn->data->set.ssl.verifypeer) { infof(conn->data, "skipping SSL peer certificate verification\n"); return SECSuccess; @@ -1609,6 +1637,13 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); } +#ifdef SSL_ENABLE_OCSP_STAPLING + if(data->set.ssl.verifystatus) { + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) + goto error; + } +#endif + #ifdef USE_NGHTTP2 if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { #ifdef SSL_ENABLE_NPN -- 2.1.3
From 2eafd6dddb0f8ca3571b602b3057d838826c365d Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini <[email protected]> Date: Mon, 16 Jun 2014 20:47:26 +0200 Subject: [PATCH 4/4] curl: add --cert-status option This enable the CURLOPT_SSL_VERIFYSTATUS functionality. --- docs/curl.1 | 10 ++++++++++ src/tool_cfgable.h | 1 + src/tool_getparam.c | 5 +++++ src/tool_operate.c | 3 +++ 4 files changed, 19 insertions(+) diff --git a/docs/curl.1 b/docs/curl.1 index 1f5389a..25a3739 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -552,6 +552,16 @@ This is currently only implemented in the OpenSSL, GnuTLS and GSKit backends. If this option is used several times, the last one will be used. (Added in 7.39.0) +.IP "--cert-status" +(SSL) Tells curl to verify the status of the server certificate by using the +Certificate Status Request (aka. OCSP stapling) TLS extension. + +If this option is enabled and the server sends an invalid (e.g. expired) +response, if the response suggests that the server certificate has been revoked, +or no response at all is received, the verification fails. + +This is currently only implemented in the GnuTLS and NSS backends. +(Added in 7.40.0) .IP "-f, --fail" (HTTP) Fail silently (no output at all) on server errors. This is mostly done to better enable scripts etc to better deal with failed attempts. In normal diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 2336016..2ab79f0 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -126,6 +126,7 @@ struct OperationConfig { bool globoff; bool use_httpget; bool insecure_ok; /* set TRUE to allow insecure SSL connects */ + bool verifystatus; bool create_dirs; bool ftp_create_dirs; bool ftp_skip_ip; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 3932ccb..ee198c3 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -217,6 +217,7 @@ static const struct LongShort aliases[]= { {"En", "ssl-allow-beast", FALSE}, {"Eo", "login-options", TRUE}, {"Ep", "pinnedpubkey", TRUE}, + {"Eq", "cert-status", FALSE}, {"f", "fail", FALSE}, {"F", "form", TRUE}, {"Fs", "form-string", TRUE}, @@ -1363,6 +1364,10 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ GetStr(&config->pinnedpubkey, nextarg); break; + case 'q': /* --cert-status */ + config->verifystatus = TRUE; + break; + default: /* certificate file */ { char *certname, *passphrase; diff --git a/src/tool_operate.c b/src/tool_operate.c index 3fa0db1..8d0a7ec 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -1038,6 +1038,9 @@ static CURLcode operate_do(struct GlobalConfig *global, /* libcurl default is strict verifyhost -> 2L */ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ } + + if(config->verifystatus) + my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); } if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { -- 2.1.3
signature.asc
Description: Digital signature
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
