gnunet-svn
[Top][All Lists]
Advanced

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

[gnurl] 147/264: schannel: support .P12 or .PFX client certificates


From: gnunet
Subject: [gnurl] 147/264: schannel: support .P12 or .PFX client certificates
Date: Thu, 30 Apr 2020 16:07:30 +0200

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

nikita pushed a commit to branch master
in repository gnurl.

commit 0fdf96512613574591f501d63fe49495ba40e1d5
Author: Gilles Vollant <address@hidden>
AuthorDate: Sun Sep 15 14:37:36 2019 +0200

    schannel: support .P12 or .PFX client certificates
    
    Used with curl command line option like this: --cert
    <filename>:<password> --cert-type p12
    
    Closes #5193
---
 lib/vtls/schannel.c | 158 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 124 insertions(+), 34 deletions(-)

diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 64719fe70..8bf598c07 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -585,11 +585,12 @@ schannel_connect_step1(struct connectdata *conn, int 
sockindex)
     /* client certificate */
     if(data->set.ssl.cert) {
       DWORD cert_store_name;
-      TCHAR *cert_store_path;
+      TCHAR *cert_store_path = NULL;
       TCHAR *cert_thumbprint_str;
       CRYPT_HASH_BLOB cert_thumbprint;
       BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
       HCERTSTORE cert_store;
+      FILE *fInCert = NULL;
 
       TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
       if(!cert_path)
@@ -597,54 +598,143 @@ schannel_connect_step1(struct connectdata *conn, int 
sockindex)
 
       result = get_cert_location(cert_path, &cert_store_name,
                                  &cert_store_path, &cert_thumbprint_str);
-      if(result != CURLE_OK) {
-        failf(data, "schannel: Failed to get certificate location for %s",
-              cert_path);
+      if((result != CURLE_OK) && (data->set.ssl.cert[0]!='\0'))
+        fInCert = fopen(data->set.ssl.cert, "rb");
+
+      if((result != CURLE_OK) && (fInCert == NULL)) {
+        failf(data, "schannel: Failed to get certificate location"
+              " or file for %s",
+              data->set.ssl.cert);
         Curl_unicodefree(cert_path);
         return result;
       }
 
-      cert_store =
-        CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
-                      (HCRYPTPROV)NULL,
-                      CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
-                      cert_store_path);
-      if(!cert_store) {
-        failf(data, "schannel: Failed to open cert store %x %s, "
-              "last error is %x",
-              cert_store_name, cert_store_path, GetLastError());
-        free(cert_store_path);
+      if(fInCert) {
+        /* Reading a .P12 or .pfx file, like the example at bottom of
+           https://social.msdn.microsoft.com/Forums/windowsdesktop/
+           en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
+        */
+        void *certdata = NULL;
+        long filesize = 0;
+        CRYPT_DATA_BLOB datablob;
+        WCHAR* pszPassword;
+        size_t pwd_len = 0;
+        int str_w_len = 0;
+        int continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
+        if(continue_reading)
+          filesize = ftell(fInCert);
+        if(filesize < 0)
+          continue_reading = 0;
+        if(continue_reading)
+          continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
+        if(continue_reading)
+          certdata = malloc(((size_t)filesize) + 1);
+        if((certdata == NULL) ||
+           ((int) fread(certdata, (size_t)filesize, 1, fInCert) != 1))
+          continue_reading = 0;
+        fclose(fInCert);
         Curl_unicodefree(cert_path);
-        return CURLE_SSL_CERTPROBLEM;
-      }
-      free(cert_store_path);
 
-      cert_thumbprint.pbData = cert_thumbprint_data;
-      cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+        if(!continue_reading) {
+          failf(data, "schannel: Failed to read cert file %s",
+                data->set.ssl.cert);
+          free(certdata);
+          return CURLE_SSL_CERTPROBLEM;
+        }
 
-      if(!CryptStringToBinary(cert_thumbprint_str, CERT_THUMBPRINT_STR_LEN,
-                              CRYPT_STRING_HEX,
-                              cert_thumbprint_data, &cert_thumbprint.cbData,
-                              NULL, NULL)) {
-        Curl_unicodefree(cert_path);
-        return CURLE_SSL_CERTPROBLEM;
-      }
+        /* Convert key-pair data to the in-memory certificate store */
+        datablob.pbData = (BYTE*)certdata;
+        datablob.cbData = (DWORD)filesize;
+
+        if(data->set.ssl.key_passwd != NULL)
+          pwd_len = strlen(data->set.ssl.key_passwd);
+        pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
+        if(pwd_len > 0)
+          str_w_len =
+            MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+                                data->set.ssl.key_passwd, (int)pwd_len,
+                                pszPassword, (int)(pwd_len + 1));
+
+        if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
+          pszPassword[str_w_len] = 0;
+        else
+          pszPassword[0] = 0;
+
+        cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
+        free(pszPassword);
+        free(certdata);
+        if(cert_store == NULL) {
+          DWORD errorcode = GetLastError();
+          if(errorcode == ERROR_INVALID_PASSWORD)
+            failf(data, "schannel: Failed to import cert file %s, "
+                  "password is bad", data->set.ssl.cert);
+          else
+            failf(data, "schannel: Failed to import cert file %s, "
+                  "last error is 0x%x", data->set.ssl.cert, errorcode);
+          return CURLE_SSL_CERTPROBLEM;
+        }
 
-      client_certs[0] = CertFindCertificateInStore(
-        cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
-        CERT_FIND_HASH, &cert_thumbprint, NULL);
+        client_certs[0] = CertFindCertificateInStore(
+            cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+            CERT_FIND_ANY, NULL, NULL);
 
-      Curl_unicodefree(cert_path);
+        if(client_certs[0] == NULL) {
+          failf(data, "schannel: Failed to get certificat from file %s"
+                ", last error is 0x%x",
+                data->set.ssl.cert, GetLastError());
+          CertCloseStore(cert_store, 0);
+          return CURLE_SSL_CERTPROBLEM;
+        }
 
-      if(client_certs[0]) {
         schannel_cred.cCreds = 1;
         schannel_cred.paCred = client_certs;
       }
       else {
-        /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
-        return CURLE_SSL_CERTPROBLEM;
-      }
+        cert_store =
+          CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
+                        (HCRYPTPROV)NULL,
+                        CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
+                        cert_store_path);
+        if(!cert_store) {
+          failf(data, "schannel: Failed to open cert store %x %s, "
+                "last error is 0x%x",
+                cert_store_name, cert_store_path, GetLastError());
+          free(cert_store_path);
+          Curl_unicodefree(cert_path);
+          return CURLE_SSL_CERTPROBLEM;
+        }
+        free(cert_store_path);
+
+        cert_thumbprint.pbData = cert_thumbprint_data;
+        cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+
+        if(!CryptStringToBinary(cert_thumbprint_str,
+                                CERT_THUMBPRINT_STR_LEN,
+                                CRYPT_STRING_HEX,
+                                cert_thumbprint_data,
+                                &cert_thumbprint.cbData,
+                                NULL, NULL)) {
+          Curl_unicodefree(cert_path);
+          CertCloseStore(cert_store, 0);
+          return CURLE_SSL_CERTPROBLEM;
+        }
+
+        client_certs[0] = CertFindCertificateInStore(
+          cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+          CERT_FIND_HASH, &cert_thumbprint, NULL);
+
+        Curl_unicodefree(cert_path);
 
+        if(client_certs[0]) {
+          schannel_cred.cCreds = 1;
+          schannel_cred.paCred = client_certs;
+        }
+        else {
+          /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
+          CertCloseStore(cert_store, 0);
+          return CURLE_SSL_CERTPROBLEM;
+        }
+      }
       CertCloseStore(cert_store, 0);
     }
 #else

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



reply via email to

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