cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH] Implement SSL-backend independent API to access TLS internals, in particular the X509 certificate information.

From: Christian Grothoff <christian_at_grothoff.org>
Date: Sun, 17 Nov 2013 20:49:16 +0100

The new API returns an SSL-backend dependent pointer and
an enum on the backend type, as discussed on the mailinglist.
Sample use:

  struct curl_tlsinfo *tlsinfo;

  if (CURLE_OK !=
      curl_easy_getinfo (s5r->curl,
                         CURLINFO_TLS_SESSION,
                         &tlsinfo))
    return SYSERR;
  if (CURLSSLBACKEND_GNUTLS != tlsinfo->ssl_backend)
  {
    // error: Unsupported SSL backend
    return SYSERR;
  }
  ... = gnutls_certificate_get_peers (tlsinfo->internals, ...);

---
 docs/libcurl/curl_easy_getinfo.3 |   12 +++++++++++
 include/curl/curl.h              |   31 +++++++++++++++++++++++++---
 lib/getinfo.c                    |   42 ++++++++++++++++++++++++++++++++++++++
 lib/urldata.h                    |    2 ++
 4 files changed, 84 insertions(+), 3 deletions(-)
diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index db0f4d6..f7be3f6 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -221,6 +221,18 @@ provided in a series of data in the format "name:content" where the content is
 for the specific named data. See also the certinfo.c example. NOTE: this
 option is only available in libcurl built with OpenSSL, NSS, GSKit or QsoSSL
 support. (Added in 7.19.1)
+
+.IP CURLINFO_TLS_SESSION
+Pass a pointer to a 'struct curl_tlsinfo *'.  The pointer will be initialized
+to refer to a 'struct curl_tlsinfo *' which will contain the type of the SSL
+library used for the handshake, and the respective internal TLS session
+structure of this underlying SSL library.
+This can then be used to extract certificate information in a format
+convenient for further processing, such as manual validation. NOTE: this
+option may not be available for all SSL backends; unsupported SSL backends
+may return 'CURLSSLBACKEND_NONE' to indicate that they are not supported;
+this does not mean that no SSL backend was used.  (Added in 7.34.0)
+
 .IP CURLINFO_CONDITION_UNMET
 Pass a pointer to a long to receive the number 1 if the condition provided in
 the previous request didn't match (see \fICURLOPT_TIMECONDITION\fP). Alas, if
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 14ff7c7..735de4a 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1388,8 +1388,7 @@ typedef enum {
   CINIT(ADDRESS_SCOPE, LONG, 171),
 
   /* Collect certificate chain info and allow it to get retrievable with
-     CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only
-     working with OpenSSL-powered builds. */
+     CURLINFO_CERTINFO after the transfer is complete. */
   CINIT(CERTINFO, LONG, 172),
 
   /* "name" and "pwd" to use when fetching. */
@@ -1986,6 +1985,31 @@ struct curl_certinfo {
                                    format "name: value" */
 };
 
+
+/* enum for the different SSL backends supported by cURL. */
+typedef enum {
+  CURLSSLBACKEND_NONE = 0,
+  CURLSSLBACKEND_OPENSSL = 1,
+  CURLSSLBACKEND_GNUTLS = 2,
+  CURLSSLBACKEND_NSS = 3,
+  CURLSSLBACKEND_QSOSSL = 4,
+  CURLSSLBACKEND_GSKIT = 5,
+  CURLSSLBACKEND_POLARSSL = 6,
+  CURLSSLBACKEND_CYASSL = 7,
+  CURLSSLBACKEND_SCHANNEL = 8,
+  CURLSSLBACKEND_DARWINSSL = 9
+} curl_ssl_backend;
+
+
+/* info about the SSL library used, and the respective internal
+   SSL handle that can be used to extract further information about
+   the connection. Asked for with CURLINFO_TLS_SESSION. */
+struct curl_tlsinfo {
+  curl_ssl_backend ssl_backend;
+  void *internals;
+};
+
+
 #define CURLINFO_STRING   0x100000
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
@@ -2037,9 +2061,10 @@ typedef enum {
   CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
+  CURLINFO_TLS_SESSION      = CURLINFO_SLIST  + 43,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 42
+  CURLINFO_LASTONE          = 43
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 3d09dc6..fd519e2 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -277,7 +277,49 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
     ptr.to_certinfo = &data->info.certs;
     *param_slistp = ptr.to_slist;
     break;
+  case CURLINFO_TLS_SESSION:
+    {
+      struct curl_tlsinfo ** tlsinfop = (struct curl_tlsinfo **) param_slistp;
+      struct curl_tlsinfo * tlsinfo = &data->tlsinfo;
+      struct connectdata * conn;
+      unsigned int sockindex;
 
+      *tlsinfop = tlsinfo;
+      tlsinfo->ssl_backend = CURLSSLBACKEND_NONE;
+      conn = data->easy_conn;
+      sockindex = 0;
+      /* find active ("in use") SSL connection, if any */
+      while((sockindex < sizeof(conn->ssl)/sizeof(conn->ssl[0])) &&
+            (! conn->ssl[sockindex].use)) sockindex++;
+      if(sockindex == sizeof(conn->ssl)/sizeof(conn->ssl[0]))
+        break; /* no SSL session found */
+#ifdef USE_SSLEAY
+      tlsinfo->ssl_backend = CURLSSLBACKEND_OPENSSL;
+      tlsinfo->internals = conn->ssl[sockindex].ctx;
+#endif
+#ifdef USE_GNUTLS
+      tlsinfo->ssl_backend = CURLSSLBACKEND_GNUTLS;
+      tlsinfo->internals = conn->ssl[sockindex].session;
+#endif
+#ifdef USE_NSS
+      tlsinfo->ssl_backend = CURLSSLBACKEND_NSS;
+      tlsinfo->internals = conn->ssl[sockindex].handle;
+#endif
+#ifdef USE_QSOSSL
+      tlsinfo->ssl_backend = CURLSSLBACKEND_QSOSSL;
+      tlsinfo->internals = conn->ssl[sockindex].handle;
+#endif
+#ifdef USE_GSKIT
+      tlsinfo->ssl_backend = CURLSSLBACKEND_GSKIT;
+      tlsinfo->internals = conn->ssl[sockindex].handle;
+#endif
+      /* note: for other SSL backends, it is not immediately
+         clear what member(s) to return from 'struct ssl_connect_data';
+         thus, for now we keep the backend on CURLSSLBACKEND_NONE in
+         those cases, which should be interpreted as "not supported" */
+      break;
+    }
+    break;
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
diff --git a/lib/urldata.h b/lib/urldata.h
index 98686bb..f2c2b43 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1637,6 +1637,8 @@ struct SessionHandle {
                                   other dynamic purposes */
   struct WildcardData wildcard; /* wildcard download state info */
   struct PureInfo info;        /* stats, reports and info data */
+  struct curl_tlsinfo tlsinfo; /* information about TLS session, only
+                                  initialized after a client asked for it. */
 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
   iconv_t outbound_cd;         /* for translating to the network encoding */
   iconv_t inbound_cd;          /* for translating from the network encoding */
-- 
1.7.10.4
--------------070401000804020307090802
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
--------------070401000804020307090802--
Received on 2001-09-17