gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnurl] 08/150: SChannel/WinSSL: Implement public key pinni


From: gnunet
Subject: [GNUnet-SVN] [gnurl] 08/150: SChannel/WinSSL: Implement public key pinning
Date: Fri, 30 Mar 2018 16:47:42 +0200

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to branch master
in repository gnurl.

commit e178fbd40a896f2098278ae61e1166c88e7b31d0
Author: moparisthebest <address@hidden>
AuthorDate: Wed Apr 19 00:31:23 2017 -0400

    SChannel/WinSSL: Implement public key pinning
    
    Closes #1429
---
 docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 |   6 +-
 lib/vtls/schannel.c                         | 143 +++++++++++++++++++++++++++-
 tests/runtests.pl                           |   1 +
 3 files changed, 146 insertions(+), 4 deletions(-)

diff --git a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3 
b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
index 47646474e..dd8ed4ffa 100644
--- a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
+++ b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.3
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2018, Daniel Stenberg, <address@hidden>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -105,6 +105,8 @@ PEM/DER support:
 
   7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+
 
+  7.58.1: SChannel/WinSSL
+
 sha256 support:
 
   7.44.0: OpenSSL, GnuTLS, NSS and wolfSSL/CyaSSL
@@ -115,6 +117,8 @@ sha256 support:
 
   7.54.1: SecureTransport/DarwinSSL on macOS 10.7+/iOS 10+
 
+  7.58.1: SChannel/WinSSL Windows XP SP3+
+
 Other SSL backends not supported.
 .SH RETURN VALUE
 Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 85c64cf44..6ae834c72 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 2012 - 2016, Marc Hoersken, <address@hidden>
  * Copyright (C) 2012, Mark Salisbury, <address@hidden>
- * Copyright (C) 2012 - 2017, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 2012 - 2018, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -129,6 +129,10 @@
  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
  */
 
+#ifndef CALG_SHA_256
+#  define CALG_SHA_256 0x0000800c
+#endif
+
 /* Structs to store Schannel handles */
 struct curl_schannel_cred {
   CredHandle cred_handle;
@@ -165,6 +169,9 @@ struct ssl_backend_data {
 static Curl_recv schannel_recv;
 static Curl_send schannel_send;
 
+static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+                                    const char *pinnedpubkey);
+
 #ifdef _WIN32_WCE
 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
 #endif
@@ -542,6 +549,7 @@ schannel_connect_step2(struct connectdata *conn, int 
sockindex)
   bool doread;
   char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
+  const char *pubkey_ptr;
 
   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
 
@@ -761,6 +769,17 @@ schannel_connect_step2(struct connectdata *conn, int 
sockindex)
     infof(data, "schannel: SSL/TLS handshake complete\n");
   }
 
+  pubkey_ptr = SSL_IS_PROXY() ?
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+    data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+  if(pubkey_ptr) {
+    result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key!");
+      return result;
+    }
+  }
+
 #ifdef _WIN32_WCE
   /* Windows CE doesn't do any server certificate validation.
      We have to do it manually. */
@@ -1669,6 +1688,68 @@ static CURLcode Curl_schannel_random(struct Curl_easy 
*data UNUSED_PARAM,
   return CURLE_OK;
 }
 
+static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
+                                    const char *pinnedpubkey)
+{
+  SECURITY_STATUS status;
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  CERT_CONTEXT *pCertContextServer = NULL;
+  const char *x509_der;
+  int x509_der_len;
+  curl_X509certificate x509_parsed;
+  curl_asn1Element *pubkey;
+
+  /* Result is returned to caller */
+  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+  /* if a path wasn't specified, don't pin */
+  if(!pinnedpubkey)
+    return CURLE_OK;
+
+  do {
+    status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+                                              SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                              &pCertContextServer);
+
+    if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+      failf(data, "schannel: Failed to read remote certificate context: %s",
+            Curl_sspi_strerror(conn, status));
+      break; /* failed */
+    }
+
+
+    if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+       (pCertContextServer->cbCertEncoded > 0)))
+      break;
+
+    x509_der = pCertContextServer->pbCertEncoded;
+    x509_der_len = pCertContextServer->cbCertEncoded;
+    memset(&x509_parsed, 0, sizeof x509_parsed);
+    if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+      break;
+
+    pubkey = &x509_parsed.subjectPublicKeyInfo;
+    if(!pubkey->header || pubkey->end <= pubkey->header) {
+      failf(data, "SSL: failed retrieving public key from server certificate");
+      break;
+    }
+
+    result = Curl_pin_peer_pubkey(data,
+                                  pinnedpubkey,
+                                  (const unsigned char *)pubkey->header,
+                                  (size_t)(pubkey->end - pubkey->header));
+    if(result) {
+      failf(data, "SSL: public key does not match pinned public key!");
+    }
+  } while(0);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
 #ifdef _WIN32_WCE
 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
 {
@@ -1809,6 +1890,62 @@ static CURLcode verify_certificate(struct connectdata 
*conn, int sockindex)
 }
 #endif /* _WIN32_WCE */
 
+static void Curl_schannel_checksum(const unsigned char *input,
+                      size_t inputlen,
+                      unsigned char *checksum,
+                      size_t checksumlen,
+                      const unsigned char *pszProvider,
+                      const unsigned int algId)
+{
+  HCRYPTPROV hProv = 0;
+  HCRYPTHASH hHash = 0;
+  size_t cbHashSize = 0, dwCount = sizeof(size_t);
+
+  /* since this can fail in multiple ways, zero memory first so we never
+   * return old data
+   */
+  memset(checksum, 0, checksumlen);
+
+  if(!CryptAcquireContext(&hProv, NULL, NULL, pszProvider,
+                          CRYPT_VERIFYCONTEXT))
+    return; /* failed */
+
+  do {
+    if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
+      break; /* failed */
+
+    if(!CryptHashData(hHash, (const BYTE*) input, inputlen, 0))
+      break; /* failed */
+
+    /* get hash size */
+    if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
+                          &dwCount, 0))
+      break; /* failed */
+
+    /* check hash size */
+    if(checksumlen < cbHashSize)
+      break; /* failed */
+
+    if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &checksumlen, 0))
+      break; /* failed */
+  } while(0);
+
+  if(hHash)
+    CryptDestroyHash(hHash);
+
+  if(hProv)
+    CryptReleaseContext(hProv, 0);
+}
+
+void Curl_schannel_sha256sum(unsigned char *input,
+                           size_t inputlen,
+                           unsigned char *sha256sum,
+                           size_t sha256len)
+{
+    Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
+                           PROV_RSA_AES, CALG_SHA_256);
+}
+
 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
                                          CURLINFO info UNUSED_PARAM)
 {
@@ -1821,7 +1958,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
 
   0, /* have_ca_path */
   1, /* have_certinfo */
-  0, /* have_pinnedpubkey */
+  1, /* have_pinnedpubkey */
   0, /* have_ssl_ctx */
   0, /* support_https_proxy */
 
@@ -1846,7 +1983,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
   Curl_none_engines_list,            /* engines_list */
   Curl_none_false_start,             /* false_start */
   Curl_none_md5sum,                  /* md5sum */
-  NULL                               /* sha256sum */
+  Curl_schannel_sha256sum            /* sha256sum */
 };
 
 #endif /* USE_SCHANNEL */
diff --git a/tests/runtests.pl b/tests/runtests.pl
index d68c20f19..d6aa5cac6 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -2772,6 +2772,7 @@ sub checksystem {
             }
            if ($libcurl =~ /winssl/i) {
                $has_winssl=1;
+               $has_sslpinning=1;
                $ssllib="WinSSL";
            }
            elsif ($libcurl =~ /openssl/i) {

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]