Hi!

Here's an improved patch that makes this (presumably) SSL-backend
independent.  I only tested it with GnuTLS though, and some SSL
backends are not supported by the patch.  The patch would need to
be applied on top of the 2nd patch I sent (#2 and #3 are independent
of the first patch).

I hope you like this more general evolution of the API.  While I
did test this using code very much like the one supplied in the
commit message, I cannot say what happens during SSL connection
shutdown --- again, the patch expects that if the SSL connection
is shut down, the "use" flag is cleared by libcurl and/or the
handle(s) are reset to NULL.

I toyed with the idea of returning a 'union' with the precise
types from the various SSL backends instead of returning a 'void *',
but that would have tied the public curl API to the various SSL
APIs, which would have been ugly, so I think 'void *' should do
nicely for now.

Happy hacking!

Christian

On 10/12/2013 11:55 PM, Daniel Stenberg wrote:
> On Fri, 20 Sep 2013, Christian Grothoff wrote:
> 
>> Here is another patch which adds the CURLINFO_GNUTLS_SESSION option to
>> curl_easy_getinfo.  It exposes the GnuTLS session to clients, which is
>> useful if clients need to inspect certificate chains or other
>> properties of the TLS connection.  Naturally, the option only works if
>> cURL was compiled with GnuTLS support (hence the GNUTLS in the name). 
>> This patch should be completely independent from my previous patch to
>> support CURLINFO_CERTINFO with GnuTLS, and I think it is generally
>> more useful as it allows applications to access certificates via the
>> nice GnuTLS X509 APIs instead of having to parse the strings.
> 
> Hi!
> 
> I can see why this option can be handy. I don't really like opening up
> the API for even more SSL-library specific things so I would prefer if
> you can think of a way that can return this information in an even more
> generic way that will include information for what SSL library the
> handle concerns so that we don't end up having to add a new such option
> for every SSL library we want to allow this "extraction" for.
> 
> Also, I found the code needing some comments to explain what the loop
> does and I'm also a bit concerned if this really works properly in all
> cases, like even if the SSL connection was completely shutdown previous
> to this curl_easy_getinfo() call. How much testing have you done on this?
> 
From 2f2859dc000ad845c74df1e0ee6e4dd95c064093 Mon Sep 17 00:00:00 2001
From: Christian Grothoff <[email protected]>
Date: Tue, 15 Oct 2013 15:17:43 +0200
Subject: [PATCH 3/3] Make the proposed certificate extraction API more
 SSL-backend independent by returning an enum on the backend type, as
 discussed on the mailinglist.  Sample use:

  struct curl_tlsinfo tlsinfo;
  union {
    struct curl_tlsinfo *tlsinfo;
    struct curl_slist   *to_slist;
  } gptr;

  memset (&tlsinfo, 0, sizeof (tlsinfo));
  gptr.tlsinfo = &tlsinfo;
  if (CURLE_OK !=
      curl_easy_getinfo (s5r->curl,
			 CURLINFO_TLS_SESSION,
			 &gptr))
    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 | 16 ++++++++------
 include/curl/curl.h              | 27 ++++++++++++++++++++++-
 lib/getinfo.c                    | 46 ++++++++++++++++++++++++++++------------
 3 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index c5a509c..b88a9fb 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -222,13 +222,15 @@ for the specific named data. See also the certinfo.c example. NOTE: this
 option is only available in libcurl built with OpenSSL support. (Added in
 7.19.1)
 
-.IP CURLINFO_GNUTLS_SESSION
-Pass a pointer to a 'gnutls_session' and you'll get it set to point to the
-respective GnuTLS session used by this request.  This can then be used to
-extract certificate information in a format convenient for further
-processing, such as manual validation. NOTE: this
-option is only available in libcurl built with GnuTLS support. (Added in
-7.33.0)
+.IP CURLINFO_TLS_SESSION
+Pass a pointer to a 'struct curl_tlsinfo *'.  The struct will be initialized
+to contain the type of the SSL library used for the handshake, and to 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
diff --git a/include/curl/curl.h b/include/curl/curl.h
index a63ee67..45fedf8 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1979,6 +1979,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
@@ -2030,7 +2055,7 @@ typedef enum {
   CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
-  CURLINFO_GNUTLS_SESSION   = CURLINFO_SLIST  + 43,
+  CURLINFO_TLS_SESSION      = CURLINFO_SLIST  + 43,
   /* Fill in new entries below here! */
 
   CURLINFO_LASTONE          = 43
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 36197c2..bc792b1 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -277,30 +277,48 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
     ptr.to_certinfo = &data->info.certs;
     *param_slistp = ptr.to_slist;
     break;
-#ifdef USE_GNUTLS
-  case CURLINFO_GNUTLS_SESSION:
+  case CURLINFO_TLS_SESSION:
     {
-      union {
-        gnutls_session session;
-        struct curl_slist    * to_slist;
-      } gptr;
-      struct connectdata *conn;
+      struct curl_tlsinfo * tlsinfo = (struct curl_tlsinfo *) *param_slistp;
+      struct connectdata * conn;
       unsigned int sockindex;
 
+      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])) {
-        *param_slistp = NULL;
-        break;
-      }
-      gptr.session = conn->ssl[sockindex].session;
-      *param_slistp = gptr.to_slist;
+      if((sockindex == sizeof(conn->ssl)/sizeof(conn->ssl[0])) ||
+         (NULL == conn->ssl[sockindex].session))
+        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;
-#endif
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
-- 
1.8.4.rc3

Attachment: 0x48426C7E.asc
Description: application/pgp-keys

Attachment: signature.asc
Description: OpenPGP digital signature

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

Reply via email to