]> granicus.if.org Git - transmission/commitdiff
Load CA certs from system store on Windows / OpenSSL
authorMike Gelfand <mikedld@mikedld.com>
Sat, 22 Jun 2019 13:02:17 +0000 (16:02 +0300)
committerMike Gelfand <mikedld@mikedld.com>
Sun, 23 Jun 2019 08:59:53 +0000 (11:59 +0300)
Fixes: #446
Transmission.xcodeproj/project.pbxproj
libtransmission/CMakeLists.txt
libtransmission/crypto-test-ref.h
libtransmission/crypto-utils-cyassl.c
libtransmission/crypto-utils-fallback.c
libtransmission/crypto-utils-openssl.c
libtransmission/crypto-utils-polarssl.c
libtransmission/crypto-utils.h
libtransmission/web.c

index 9f40e412f86eb328cd3a4294c2d109cc33be23db..fc28a7e1aee64549acae136546f5ad0544f7c2ad 100644 (file)
                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 */; };
                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>"; };
                                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 */,
                        );
                                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 */,
                                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;
                };
                                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 */,
                        );
                                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 */,
                        );
                A2F35BBA15C5A0A100EBF632 /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               C139E3B022BE70FA0007870C /* libssl.dylib */,
                                A2F35BBB15C5A0A100EBF632 /* QuickLook.framework */,
                                A2F35BE215C5A7F900EBF632 /* Foundation.framework */,
                                A2F35BE015C5A7ED00EBF632 /* Cocoa.framework */,
index d0ee87da04c90ac33043a37d63cb5ec95b46dd26..4c69aae52b7e40670628826f569ac57fe333ac16 100644 (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)
index 8cf10567498b6cdf0620fa700aed93d8fdb1fa3d..d809ebb0b93fc2646a975a3850a1b17f6b946c9f 100644 (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_
 #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
 #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
 #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
 #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
index 5627c1520029e27e161f5ad95919daa7bbd206f7..60659ff8515dc274cf471fcd97d9a65db26cf3b2 100644 (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
index f9dc97cde2b53699b4370f6931de8e13e1d2512c..c17b54e25065e3744875fefb04a56fe7385fbb2b 100644 (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 */
index 07f9d9fcfabd4ef0995abe13a117cde649afcd11..3c2891647ddb3f90dd13487632de7c6c31204f41 100644 (file)
 #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);
index cebe36a08b92b49984d622efe33085a1ada94c54..889332a3a3d3e6b162038c61de21ee4c3a1500d1 100644 (file)
@@ -34,6 +34,7 @@
 #include "utils.h"
 
 #define TR_CRYPTO_DH_SECRET_FALLBACK
+#define TR_CRYPTO_X509_FALLBACK
 #include "crypto-utils-fallback.c"
 
 /***
index 04d0966636552f2e0c0b05baaf7715fa5740cfdf..7ae3cee869e1940a9617d07f24fb822c8a1e457a 100644 (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).
  */
index bbf9073169bd1057c7f65f3f30a44e05edb87b9c..744f5766a95c9fedcffccfbfff762a7ebdb9de61 100644 (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
     {