[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.
- [gnurl] 174/264: schannel: Fix blocking timeout logic, (continued)
- [gnurl] 174/264: schannel: Fix blocking timeout logic, gnunet, 2020/04/30
- [gnurl] 123/264: test1566: verify --etag-compare that gets a 304 back, gnunet, 2020/04/30
- [gnurl] 158/264: test1148: tolerate progress updates better (again), gnunet, 2020/04/30
- [gnurl] 149/264: github actions: run when pushed to master or */ci + PRs, gnunet, 2020/04/30
- [gnurl] 185/264: tests: add four MQTT tests 1190 - 1193, gnunet, 2020/04/30
- [gnurl] 189/264: scripts/release-notes: fix duplicate output header, gnunet, 2020/04/30
- [gnurl] 121/264: curl: allow both --etag-compare and --etag-save with same file name, gnunet, 2020/04/30
- [gnurl] 146/264: tests: verify split initial HTTP requests with CURL_SMALLREQSEND, gnunet, 2020/04/30
- [gnurl] 212/264: test1245: make it work with dynamic FTP server port, gnunet, 2020/04/30
- [gnurl] 245/264: test1154: set a proper name, gnunet, 2020/04/30
- [gnurl] 147/264: schannel: support .P12 or .PFX client certificates,
gnunet <=
- [gnurl] 163/264: tests: fix conflict between Cygwin/msys and Windows PIDs, gnunet, 2020/04/30
- [gnurl] 155/264: appveyor: ignore failing 'connect to non-listening proxy' tests, gnunet, 2020/04/30
- [gnurl] 160/264: Revert "file: on Windows, refuse paths that start with \\", gnunet, 2020/04/30
- [gnurl] 192/264: test2043: use revoked.badssl.com instead of revoked.grc.com, gnunet, 2020/04/30
- [gnurl] 170/264: tests/server: add hidden window to gracefully handle WM_CLOSE, gnunet, 2020/04/30
- [gnurl] 22/264: TODO: TLS-PSK with OpenSSL, gnunet, 2020/04/30
- [gnurl] 40/264: multi: Improve parameter check for curl_multi_remove_handle, gnunet, 2020/04/30
- [gnurl] 56/264: test2100: fix static port instead of dynamic value being used, gnunet, 2020/04/30
- [gnurl] 68/264: cirrus: move the sanitizer build from freebsd 13 to freebsd 12, gnunet, 2020/04/30
- [gnurl] 72/264: nghttp2: 1.12.0 required, gnunet, 2020/04/30