Load CA certs from system store on Windows / OpenSSL

Fixes: #446
This commit is contained in:
Mike Gelfand 2019-06-22 16:02:17 +03:00
parent 3538eb93c3
commit f3968b7708
9 changed files with 212 additions and 3 deletions

View File

@ -345,6 +345,11 @@
C12F19791E1AE3C30005E93F /* upnperrors.c in Sources */ = {isa = PBXBuildFile; fileRef = C12F19771E1AE3C30005E93F /* upnperrors.c */; };
C12F197B1E1AE4460005E93F /* upnperrors.h in Headers */ = {isa = PBXBuildFile; fileRef = C12F197A1E1AE4460005E93F /* upnperrors.h */; };
C1305EBE186A13B100F03351 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = C1305EB8186A134000F03351 /* file.c */; };
C139E3B122BE70FB0007870C /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C139E3B022BE70FA0007870C /* libssl.dylib */; };
C139E3B222BE71030007870C /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C139E3B022BE70FA0007870C /* libssl.dylib */; };
C139E3B322BE71180007870C /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C139E3B022BE70FA0007870C /* libssl.dylib */; };
C139E3B422BE71250007870C /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C139E3B022BE70FA0007870C /* libssl.dylib */; };
C139E3B522BE712C0007870C /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C139E3B022BE70FA0007870C /* libssl.dylib */; };
C1425B351EE9C5F5001DB85F /* tr-assert.c in Sources */ = {isa = PBXBuildFile; fileRef = C1425B321EE9C5EA001DB85F /* tr-assert.c */; };
C1425B361EE9C605001DB85F /* tr-assert.h in Headers */ = {isa = PBXBuildFile; fileRef = C1425B331EE9C5EA001DB85F /* tr-assert.h */; };
C1425B371EE9C705001DB85F /* tr-macros.h in Headers */ = {isa = PBXBuildFile; fileRef = C1425B341EE9C5EA001DB85F /* tr-macros.h */; };
@ -994,6 +999,7 @@
C12F19771E1AE3C30005E93F /* upnperrors.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = upnperrors.c; path = "third-party/miniupnpc/upnperrors.c"; sourceTree = "<group>"; };
C12F197A1E1AE4460005E93F /* upnperrors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = upnperrors.h; path = "third-party/miniupnpc/upnperrors.h"; sourceTree = "<group>"; };
C1305EB8186A134000F03351 /* file.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = file.c; path = libtransmission/file.c; sourceTree = "<group>"; };
C139E3B022BE70FA0007870C /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = "third-party/openssl/lib/libssl.dylib"; sourceTree = "<group>"; };
C1425B321EE9C5EA001DB85F /* tr-assert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "tr-assert.c"; path = "libtransmission/tr-assert.c"; sourceTree = "<group>"; };
C1425B331EE9C5EA001DB85F /* tr-assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tr-assert.h"; path = "libtransmission/tr-assert.h"; sourceTree = "<group>"; };
C1425B341EE9C5EA001DB85F /* tr-macros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "tr-macros.h"; path = "libtransmission/tr-macros.h"; sourceTree = "<group>"; };
@ -1035,6 +1041,7 @@
A296EF3C11E560BD004A2781 /* libiconv.dylib in Frameworks */,
A2290D1E14421CC100B95A09 /* libcrypto.dylib in Frameworks */,
A2290D2F1442B23200B95A09 /* libcurl.4.dylib in Frameworks */,
C139E3B322BE71180007870C /* libssl.dylib in Frameworks */,
A2B6141E1395B0EC000E0975 /* libz.dylib in Frameworks */,
A2B3FB4C0E59023000FF78FB /* Cocoa.framework in Frameworks */,
);
@ -1051,6 +1058,7 @@
A296EF3B11E560A7004A2781 /* libiconv.dylib in Frameworks */,
A2290D2514421D1A00B95A09 /* libcrypto.dylib in Frameworks */,
A2290D2E1442B23200B95A09 /* libcurl.4.dylib in Frameworks */,
C139E3B122BE70FB0007870C /* libssl.dylib in Frameworks */,
A2B6141F1395B0F5000E0975 /* libz.dylib in Frameworks */,
A2E669790F5B8E5A00B4251A /* Security.framework in Frameworks */,
A22CFB820FB66EF30009BD3E /* Carbon.framework in Frameworks */,
@ -1082,9 +1090,10 @@
A2F35BE315C5A7F900EBF632 /* Foundation.framework in Frameworks */,
A2F35BD415C5A19A00EBF632 /* libtransmission.a in Frameworks */,
A2F35BDB15C5A4A000EBF632 /* libiconv.dylib in Frameworks */,
A2F35BDA15C5A49200EBF632 /* libz.dylib in Frameworks */,
A2F35BD715C5A46D00EBF632 /* libcrypto.dylib in Frameworks */,
A2AB76EA15D8130B009EFC95 /* libcurl.4.dylib in Frameworks */,
C139E3B222BE71030007870C /* libssl.dylib in Frameworks */,
A2F35BDA15C5A49200EBF632 /* libz.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1123,6 +1132,7 @@
A296EF3D11E560C3004A2781 /* libiconv.dylib in Frameworks */,
A2290D2014421CD000B95A09 /* libcrypto.dylib in Frameworks */,
A2290D301442B23200B95A09 /* libcurl.4.dylib in Frameworks */,
C139E3B422BE71250007870C /* libssl.dylib in Frameworks */,
A2B6141D1395B0E3000E0975 /* libz.dylib in Frameworks */,
A2B3FB530E59027100FF78FB /* Cocoa.framework in Frameworks */,
);
@ -1136,6 +1146,7 @@
A296EF3E11E560D1004A2781 /* libiconv.dylib in Frameworks */,
A2290D2214421CD800B95A09 /* libcrypto.dylib in Frameworks */,
A2290D311442B23200B95A09 /* libcurl.4.dylib in Frameworks */,
C139E3B522BE712C0007870C /* libssl.dylib in Frameworks */,
A2B6141C1395ADE9000E0975 /* libz.dylib in Frameworks */,
A25E03D90E4015100086C225 /* Cocoa.framework in Frameworks */,
);
@ -1586,6 +1597,7 @@
A2F35BBA15C5A0A100EBF632 /* Frameworks */ = {
isa = PBXGroup;
children = (
C139E3B022BE70FA0007870C /* libssl.dylib */,
A2F35BBB15C5A0A100EBF632 /* QuickLook.framework */,
A2F35BE215C5A7F900EBF632 /* Foundation.framework */,
A2F35BE015C5A7ED00EBF632 /* Cocoa.framework */,

View File

@ -269,7 +269,7 @@ if(ICONV_FOUND)
endif()
if(WIN32)
target_link_libraries(${TR_NAME} shlwapi)
target_link_libraries(${TR_NAME} crypt32 shlwapi)
endif()
if(ENABLE_TESTS)

View File

@ -19,6 +19,9 @@
#define tr_rc4_ctx_t tr_rc4_ctx_t_
#define tr_dh_ctx_t tr_dh_ctx_t_
#define tr_dh_secret_t tr_dh_secret_t_
#define tr_ssl_ctx_t tr_ssl_ctx_t_
#define tr_x509_store_t tr_x509_store_t_
#define tr_x509_cert_t tr_x509_cert_t_
#define tr_crypto tr_crypto_
#define tr_cryptoConstruct tr_cryptoConstruct_
#define tr_cryptoDestruct tr_cryptoDestruct_
@ -47,6 +50,10 @@
#define tr_dh_secret_derive tr_dh_secret_derive_
#define tr_dh_secret_free tr_dh_secret_free_
#define tr_dh_align_key tr_dh_align_key_
#define tr_ssl_get_x509_store tr_ssl_get_x509_store_
#define tr_x509_store_add tr_x509_store_add_
#define tr_x509_cert_new tr_x509_cert_new_
#define tr_x509_cert_free tr_x509_cert_free_
#define tr_rand_int tr_rand_int_
#define tr_rand_int_weak tr_rand_int_weak_
#define tr_rand_buffer tr_rand_buffer_
@ -76,6 +83,9 @@
#undef tr_rc4_ctx_t
#undef tr_dh_ctx_t
#undef tr_dh_secret_t
#undef tr_ssl_ctx_t
#undef tr_x509_store_t
#undef tr_x509_cert_t
#undef tr_crypto
#undef tr_cryptoConstruct
#undef tr_cryptoDestruct
@ -104,6 +114,10 @@
#undef tr_dh_secret_derive
#undef tr_dh_secret_free
#undef tr_dh_align_key
#undef tr_ssl_get_x509_store
#undef tr_x509_store_add
#undef tr_x509_cert_new
#undef tr_x509_cert_free
#undef tr_rand_int
#undef tr_rand_int_weak
#undef tr_rand_buffer
@ -126,6 +140,9 @@
#define tr_rc4_ctx_t_ tr_rc4_ctx_t
#define tr_dh_ctx_t_ tr_dh_ctx_t
#define tr_dh_secret_t_ tr_dh_secret_t
#define tr_ssl_ctx_t_ tr_ssl_ctx_t
#define tr_x509_store_t_ tr_x509_store_t
#define tr_x509_cert_t_ tr_x509_cert_t
#define tr_crypto_ tr_crypto
#define tr_cryptoConstruct_ tr_cryptoConstruct
#define tr_cryptoDestruct_ tr_cryptoDestruct
@ -154,6 +171,10 @@
#define tr_dh_secret_derive_ tr_dh_secret_derive
#define tr_dh_secret_free_ tr_dh_secret_free
#define tr_dh_align_key_ tr_dh_align_key
#define tr_ssl_get_x509_store_ tr_ssl_get_x509_store
#define tr_x509_store_add_ tr_x509_store_add
#define tr_x509_cert_new_ tr_x509_cert_new
#define tr_x509_cert_free_ tr_x509_cert_free
#define tr_rand_int_ tr_rand_int
#define tr_rand_int_weak_ tr_rand_int_weak
#define tr_rand_buffer_ tr_rand_buffer

View File

@ -35,6 +35,7 @@
#include "utils.h"
#define TR_CRYPTO_DH_SECRET_FALLBACK
#define TR_CRYPTO_X509_FALLBACK
#include "crypto-utils-fallback.c"
struct tr_dh_ctx

View File

@ -60,3 +60,35 @@ void tr_dh_secret_free(tr_dh_secret_t handle)
}
#endif /* TR_CRYPTO_DH_SECRET_FALLBACK */
#ifdef TR_CRYPTO_X509_FALLBACK
tr_x509_store_t tr_ssl_get_x509_store(tr_ssl_ctx_t handle)
{
(void)handle;
return NULL;
}
bool tr_x509_store_add(tr_x509_store_t handle, tr_x509_cert_t cert)
{
(void)handle;
(void)cert;
return false;
}
tr_x509_cert_t tr_x509_cert_new(void const* der, size_t der_length)
{
(void)der;
(void)der_length;
return NULL;
}
void tr_x509_cert_free(tr_x509_cert_t handle)
{
(void)handle;
}
#endif /* TR_CRYPTO_X509_FALLBACK */

View File

@ -16,8 +16,10 @@
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "transmission.h"
#include "crypto-utils.h"
@ -400,6 +402,52 @@ tr_dh_secret_t tr_dh_agree(tr_dh_ctx_t handle, uint8_t const* other_public_key,
****
***/
tr_x509_store_t tr_ssl_get_x509_store(tr_ssl_ctx_t handle)
{
if (handle == NULL)
{
return NULL;
}
return SSL_CTX_get_cert_store(handle);
}
bool tr_x509_store_add(tr_x509_store_t handle, tr_x509_cert_t cert)
{
TR_ASSERT(handle != NULL);
TR_ASSERT(cert != NULL);
return check_result(X509_STORE_add_cert(handle, cert));
}
tr_x509_cert_t tr_x509_cert_new(void const* der, size_t der_length)
{
TR_ASSERT(der != NULL);
X509* const ret = d2i_X509(NULL, (unsigned char const**)&der, der_length);
if (ret == NULL)
{
log_error();
}
return ret;
}
void tr_x509_cert_free(tr_x509_cert_t handle)
{
if (handle == NULL)
{
return;
}
X509_free(handle);
}
/***
****
***/
bool tr_rand_buffer(void* buffer, size_t length)
{
TR_ASSERT(buffer != NULL);

View File

@ -34,6 +34,7 @@
#include "utils.h"
#define TR_CRYPTO_DH_SECRET_FALLBACK
#define TR_CRYPTO_X509_FALLBACK
#include "crypto-utils-fallback.c"
/***

View File

@ -33,6 +33,12 @@ typedef void* tr_rc4_ctx_t;
typedef void* tr_dh_ctx_t;
/** @brief Opaque DH secret key type. */
typedef void* tr_dh_secret_t;
/** @brief Opaque SSL context type. */
typedef void* tr_ssl_ctx_t;
/** @brief Opaque X509 certificate store type. */
typedef void* tr_x509_store_t;
/** @brief Opaque X509 certificate type. */
typedef void* tr_x509_cert_t;
/**
* @brief Generate a SHA1 hash from one or more chunks of memory.
@ -112,6 +118,26 @@ void tr_dh_secret_free(tr_dh_secret_t handle);
*/
void tr_dh_align_key(uint8_t* key_buffer, size_t key_size, size_t buffer_size);
/**
* @brief Get X509 certificate store from SSL context.
*/
tr_x509_store_t tr_ssl_get_x509_store(tr_ssl_ctx_t handle);
/**
* @brief Add certificate to X509 certificate store.
*/
bool tr_x509_store_add(tr_x509_store_t handle, tr_x509_cert_t cert);
/**
* @brief Allocate and initialize new X509 certificate from DER-encoded buffer.
*/
tr_x509_cert_t tr_x509_cert_new(void const* der_data, size_t der_data_size);
/**
* @brief Free X509 certificate returned by @ref tr_x509_cert_new.
*/
void tr_x509_cert_free(tr_x509_cert_t handle);
/**
* @brief Returns a random number in the range of [0...upper_bound).
*/

View File

@ -9,6 +9,8 @@
#include <string.h> /* strlen(), strstr() */
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#include <ws2tcpip.h>
#else
#include <sys/select.h>
@ -19,6 +21,7 @@
#include <event2/buffer.h>
#include "transmission.h"
#include "crypto-utils.h"
#include "file.h"
#include "list.h"
#include "log.h"
@ -149,6 +152,67 @@ static int sockoptfunction(void* vtask, curl_socket_t fd, curlsocktype purpose U
#endif
static CURLcode ssl_context_func(CURL* curl, void* ssl_ctx, void* user_data)
{
(void)curl;
(void)user_data;
tr_x509_store_t const cert_store = tr_ssl_get_x509_store(ssl_ctx);
if (cert_store == NULL)
{
return CURLE_OK;
}
#ifdef _WIN32
curl_version_info_data const* const curl_ver = curl_version_info(CURLVERSION_NOW);
if (curl_ver->age >= 0 && strncmp(curl_ver->ssl_version, "Schannel", 8) == 0)
{
return CURLE_OK;
}
static LPCWSTR const sys_store_names[] =
{
L"CA",
L"ROOT"
};
for (size_t i = 0; i < TR_N_ELEMENTS(sys_store_names); ++i)
{
HCERTSTORE const sys_cert_store = CertOpenSystemStoreW(0, sys_store_names[i]);
if (sys_cert_store == NULL)
{
continue;
}
PCCERT_CONTEXT sys_cert = NULL;
while (true)
{
sys_cert = CertFindCertificateInStore(sys_cert_store, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, sys_cert);
if (sys_cert == NULL)
{
break;
}
tr_x509_cert_t const cert = tr_x509_cert_new(sys_cert->pbCertEncoded, sys_cert->cbCertEncoded);
if (cert == NULL)
{
continue;
}
tr_x509_store_add(cert_store, cert);
tr_x509_cert_free(cert);
}
CertCloseStore(sys_cert_store, 0);
}
#endif
return CURLE_OK;
}
static long getTimeoutFromURL(struct tr_web_task const* task)
{
long timeout;
@ -201,6 +265,10 @@ static CURL* createEasy(tr_session* s, struct tr_web* web, struct tr_web_task* t
{
curl_easy_setopt(e, CURLOPT_CAINFO, web->curl_ca_bundle);
}
else
{
curl_easy_setopt(e, CURLOPT_SSL_CTX_FUNCTION, ssl_context_func);
}
}
else
{