Here I am again :)

The only difference from [0] is that I fixed the NSS patch to shorten the line
longer than 79 chars like Kamil suggested. I also fixed some typos in the commit
messages.

Unfortunately I haven't had much time to look into the OpenSSL problem yet. For
those interested my current patch is at [1] (in the status_request_openssl
branch).

I'm including my original mail below, for context:

> 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)
> 
> [0] https://bugs.debian.org/772055
> [1] https://bugs.debian.org/759161

Cheers

[0] http://curl.haxx.se/mail/lib-2014-12/0107.html
[1] https://github.com/ghedo/curl/tree/status_request_openssl
From 8515ef2c4f6e1429abd923865f712e4ad87aa08c 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 44b1b7e..32fc48b 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 d3bb5e0..a7c35ad 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1997,6 +1997,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 5f77470..50a745f 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.4

From 312afc84c7b39868401f1bc4705ce048569f11ea 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 5d4e48a..3d77148 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.4

From bf1766e1f4c35129dbe34da0014245216b2ad876 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 | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index dd83a9d..2ccd5b1 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -639,6 +639,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;
@@ -1618,6 +1646,14 @@ 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.4

From d02e074fdab4f0f69cce678dd7b213c4bdab4d0a 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 enables 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 0b9971c..aa4ceb9 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 cf8d563..4008cd0 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 a21bbca..04fd59b 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.4

Attachment: signature.asc
Description: Digital signature

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to