From 6cabd78531f80d5c6cd942ed1aa97eaa5ec080df Mon Sep 17 00:00:00 2001 From: Andrew Kurushin Date: Wed, 1 Jun 2016 08:48:30 +0200 Subject: [PATCH] schannel: add CURLOPT_CERTINFO support Closes #822 --- CMakeLists.txt | 1 + docs/libcurl/opts/CURLINFO_CERTINFO.3 | 6 +++--- lib/vtls/schannel.c | 28 ++++++++++++++++++++++++++- lib/vtls/schannel.h | 3 +++ lib/x509asn1.c | 4 ++-- lib/x509asn1.h | 4 ++-- winbuild/MakefileBuild.vc | 1 + 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06f18cf59..9e6c42e8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -578,6 +578,7 @@ if(NOT UNIX) if(HAVE_SCHANNEL_H) set(USE_SCHANNEL ON) set(SSL_ENABLED ON) + check_library_exists_concat("crypt32" CertFreeCertificateContext HAVE_LIBCRYPT32) endif() endif() endif() diff --git a/docs/libcurl/opts/CURLINFO_CERTINFO.3 b/docs/libcurl/opts/CURLINFO_CERTINFO.3 index c76daa7a3..cb0bd8aa3 100644 --- a/docs/libcurl/opts/CURLINFO_CERTINFO.3 +++ b/docs/libcurl/opts/CURLINFO_CERTINFO.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -41,8 +41,8 @@ All TLS-based .SH EXAMPLE TODO .SH AVAILABILITY -This option is only working in libcurl built with OpenSSL, NSS or GSKit -support. +This option is only working in libcurl built with OpenSSL, NSS, schannel or +GSKit support. schannel support added in 7.50.0 Added in 7.19.1 .SH RETURN VALUE diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index b2e926563..3db5c362c 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -56,6 +56,7 @@ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" +#include "x509asn1.h" #include "curl_printf.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -600,8 +601,9 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct curl_schannel_cred *old_cred = NULL; -#ifdef HAS_ALPN SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; +#ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif bool incache; @@ -694,6 +696,30 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } } + if(data->set.ssl.certinfo) { + sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); + + if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { + failf(data, "schannel: failed to retrieve remote cert context"); + return CURLE_SSL_CONNECT_ERROR; + } + + result = Curl_ssl_init_certinfo(data, 1); + if(!result) { + if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (ccert_context->cbCertEncoded > 0)) { + + const char *beg = (const char *) ccert_context->pbCertEncoded; + const char *end = beg + ccert_context->cbCertEncoded; + result = Curl_extract_certinfo(conn, 0, beg, end); + } + } + CertFreeCertificateContext(ccert_context); + if(result) + return result; + } + connssl->connecting_state = ssl_connect_done; return CURLE_OK; diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index a314b34f9..8a4991ec8 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -97,6 +97,9 @@ int Curl_schannel_random(unsigned char *entropy, size_t length); /* Set the API backend definition to Schannel */ #define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + /* API setup for Schannel */ #define curlssl_init Curl_schannel_init #define curlssl_cleanup Curl_schannel_cleanup diff --git a/lib/x509asn1.c b/lib/x509asn1.c index c221ba075..fcff7f0b8 100644 --- a/lib/x509asn1.c +++ b/lib/x509asn1.c @@ -23,7 +23,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include #include "urldata.h" @@ -1025,7 +1025,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, return CURLE_OK; } -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #if defined(USE_GSKIT) diff --git a/lib/x509asn1.h b/lib/x509asn1.h index e6a1e2444..0f2b9304f 100644 --- a/lib/x509asn1.h +++ b/lib/x509asn1.h @@ -26,7 +26,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include "urldata.h" @@ -128,5 +128,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum, CURLcode Curl_verifyhost(struct connectdata * conn, const char * beg, const char * end); -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #endif /* HEADER_CURL_X509ASN1_H */ diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc index ee584a6fd..22b1e501f 100644 --- a/winbuild/MakefileBuild.vc +++ b/winbuild/MakefileBuild.vc @@ -232,6 +232,7 @@ USE_WINSSL = true !ERROR cannot build with WinSSL without SSPI !ENDIF SSPI_CFLAGS = $(SSPI_CFLAGS) /DUSE_SCHANNEL +WIN_LIBS = $(WIN_LIBS) Crypt32.lib !ENDIF