From 6b9a68b4358ae47fd3bebd1ae7a9d57d965c4f9e Mon Sep 17 00:00:00 2001 From: eugene Date: Wed, 18 Dec 2024 19:11:47 -0500 Subject: [PATCH 1/5] load system CA on android from proper location --- src/openssl/engine.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openssl/engine.c b/src/openssl/engine.c index e98dc8e..a5cff91 100644 --- a/src/openssl/engine.c +++ b/src/openssl/engine.c @@ -376,16 +376,18 @@ static void init_ssl_context(struct openssl_ctx *c, const char *cabuf, size_t ca X509_STORE *ca = load_certs(cabuf, cabuf_len); c->ca_chains = process_chains(ca, &c->ca_chains_count); SSL_CTX_set0_verify_cert_store(ctx, ca); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_cb); } else { // try loading default CA stores #if _WIN32 X509_STORE *ca = load_system_certs(); SSL_CTX_set0_verify_cert_store(ctx, ca); +#elif defined(ANDROID) || defined(__ANDROID__) + SSL_CTX_load_verify_locations(ctx, NULL, "/system/etc/security/cacerts"); #else SSL_CTX_set_default_verify_paths(ctx); #endif } - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_cb); SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); @@ -854,7 +856,7 @@ tls_continue_hs(tlsuv_engine_t self) { if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { return TLS_HS_CONTINUE; } else { // something else is wrong - eng->error = ERR_get_error(); + eng->error = err; UM_LOG(ERR, "openssl: handshake was terminated: %s", tls_error(eng->error)); return TLS_HS_ERROR; } From 193cf393022362e48110e518ed1ca836b61fcd6b Mon Sep 17 00:00:00 2001 From: eugene Date: Mon, 23 Dec 2024 13:34:37 -0500 Subject: [PATCH 2/5] android system CA store is hashed with old(md5) method --- src/openssl/engine.c | 61 +++++++++++++++++++++++++++++++++++++++++--- tests/http_tests.cpp | 39 +++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/openssl/engine.c b/src/openssl/engine.c index a5cff91..52de067 100644 --- a/src/openssl/engine.c +++ b/src/openssl/engine.c @@ -109,7 +109,6 @@ static void tls_set_cert_verify(tls_context *ctx, static int parse_pkcs7_certs(tlsuv_certificate_t *chain, const char *pkcs7, size_t pkcs7len); -static int write_cert_pem(tlsuv_certificate_t cert, int full_chain, char **pem, size_t *pemlen); static int load_cert(tlsuv_certificate_t *cert, const char *buf, size_t buflen); static int generate_csr(tlsuv_private_key_t key, char **pem, size_t *pemlen, ...); @@ -121,6 +120,7 @@ static int tls_set_partial_vfy(tls_context *ctx, int allow); static BIO_METHOD *BIO_s_engine(void); +static X509_LOOKUP_METHOD * old_hash_lookup(void); #if _WIN32 static X509_STORE *load_system_certs(); @@ -203,6 +203,10 @@ static X509_STORE * load_certs(const char *buf, size_t buf_len) { if (!X509_STORE_load_locations(certs, buf, NULL)) { UM_LOG(ERR, "failed to load certs from [%s]", buf); } + } if (fstat.st_mode & S_IFDIR) { + X509_STORE_load_path(certs, buf); + X509_LOOKUP *lu = X509_STORE_add_lookup(certs, old_hash_lookup()); + X509_LOOKUP_set_method_data(lu, (void*)buf); } else { UM_LOG(ERR, "cert bundle[%s] is not a regular file", buf); } @@ -358,6 +362,54 @@ static X509_STORE** process_chains(X509_STORE *store, int *count) { return stores; } +static int by_subj_old_hash(X509_LOOKUP *lu, X509_LOOKUP_TYPE t, const X509_NAME *name, X509_OBJECT *obj){ + if (t != X509_LU_X509) return 0; + + const char *dir = X509_LOOKUP_get_method_data(lu); + if (dir == NULL) return 0; + + char path[PATH_MAX]; + unsigned long h[] = { + X509_NAME_hash_old(name), + X509_NAME_hash(name), + }; + int count = 0; + for (int i = 0; i < sizeof(h)/sizeof(h[0]); i++) { + for (int idx = 0; ; idx ++) { + snprintf(path, sizeof(path), "%s/%08lx.%d", dir, h[i], idx); + struct stat s; + if (stat(path, &s) != 0) break; + if ((s.st_mode & S_IFREG) == 0) { + continue; + } + + if (X509_load_cert_file(lu, path, X509_FILETYPE_PEM) == 0) break; + count++; + } + } + if (count == 0) return 0; + + X509_STORE *store = X509_LOOKUP_get_store(lu); + STACK_OF(X509_OBJECT) *objs = X509_STORE_get1_objects(store); + X509_OBJECT *res = X509_OBJECT_retrieve_by_subject(objs, X509_LU_X509, name); + sk_X509_OBJECT_free(objs); + if (res) { + X509_OBJECT_set1_X509(obj, X509_OBJECT_get0_X509(res)); + return 1; + } else { + return 0; + } +} + +static X509_LOOKUP_METHOD * old_hash_lookup(void) { + static X509_LOOKUP_METHOD *method = NULL; + if (method == NULL) { + method = X509_LOOKUP_meth_new("old-hash-lookup"); + X509_LOOKUP_meth_set_get_by_subject(method, by_subj_old_hash); + } + return method; +} + static void init_ssl_context(struct openssl_ctx *c, const char *cabuf, size_t cabuf_len) { SSL_library_init(); @@ -376,17 +428,20 @@ static void init_ssl_context(struct openssl_ctx *c, const char *cabuf, size_t ca X509_STORE *ca = load_certs(cabuf, cabuf_len); c->ca_chains = process_chains(ca, &c->ca_chains_count); SSL_CTX_set0_verify_cert_store(ctx, ca); - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_cb); + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_peer_cb); } else { // try loading default CA stores #if _WIN32 X509_STORE *ca = load_system_certs(); SSL_CTX_set0_verify_cert_store(ctx, ca); #elif defined(ANDROID) || defined(__ANDROID__) - SSL_CTX_load_verify_locations(ctx, NULL, "/system/etc/security/cacerts"); + X509_STORE *ca = SSL_CTX_get_cert_store(ctx); + X509_LOOKUP *lu = X509_STORE_add_lookup(ca, old_hash_lookup()); + X509_LOOKUP_set_method_data(lu, (void*)"/etc/security/cacerts"); #else SSL_CTX_set_default_verify_paths(ctx); #endif + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); } SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); diff --git a/tests/http_tests.cpp b/tests/http_tests.cpp index ff2387b..61ba413 100644 --- a/tests/http_tests.cpp +++ b/tests/http_tests.cpp @@ -1223,7 +1223,7 @@ sQIwJonMaAFi54mrfhfoFNZEfuNMSQ6/bIBiNLiyoX46FohQvKeIoJ99cx7sUkFN tlsuv_http_set_ssl(&clt, tls); struct result_t { - int code; + int code{0}; std::string msg; } result; tlsuv_http_req(&clt, "GET", "/version", @@ -1257,4 +1257,41 @@ sQIwJonMaAFi54mrfhfoFNZEfuNMSQ6/bIBiNLiyoX46FohQvKeIoJ99cx7sUkFN tlsuv_http_close(&clt, nullptr); uv_run(loop, UV_RUN_DEFAULT); +} + +// test for exercising CA store that's +// hashing certs with X509_NAME_hash_old()/MD5 +// e.g. on Android +TEST_CASE("old-ca-store", "[http]") { + auto ca_dir = getenv("TLSUV_TEST_OLD_CA_DIR"); + if (ca_dir == nullptr) { + SKIP("TLSUV_TEST_OLD_CA_DIR is not set"); + return; + } + auto loop = uv_loop_new(); + tlsuv_http_t clt{}; + tlsuv_http_init(loop, &clt, "https://google.com"); + auto tls = default_tls_context(ca_dir, 0); + tlsuv_http_set_ssl(&clt, tls); + + struct result_t { + int code{0}; + std::string msg; + } result; + tlsuv_http_req(&clt, "GET", "/", + [](tlsuv_http_resp_t *resp, void *res){ + auto r = (result_t*)res; + r->code = resp->code; + r->msg = resp->status; + }, + &result); + uv_run(loop, UV_RUN_DEFAULT); + + // should get HTTP response here + INFO(result.msg); + CHECK(result.code >= 200); + + tlsuv_http_close(&clt, nullptr); + uv_run(loop, UV_RUN_DEFAULT); + uv_loop_delete(loop); } \ No newline at end of file From 5fd7dc93952fc70d58b7e08bc821cfbd706afa9d Mon Sep 17 00:00:00 2001 From: eugene Date: Mon, 23 Dec 2024 13:57:35 -0500 Subject: [PATCH 3/5] win32 path_max fix --- src/openssl/engine.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openssl/engine.c b/src/openssl/engine.c index 52de067..fc1dee8 100644 --- a/src/openssl/engine.c +++ b/src/openssl/engine.c @@ -33,6 +33,15 @@ #include "keys.h" #include "../keychain.h" +#if _WIN32 +#include +#include +#pragma comment (lib, "crypt32.lib") +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif +#endif + // inspired by https://golang.org/src/crypto/x509/root_linux.go // Possible certificate files; stop after finding one. @@ -1106,8 +1115,6 @@ goto on_error; \ } #if _WIN32 -#include -#pragma comment (lib, "crypt32.lib") static X509_STORE *load_system_certs() { X509_STORE *store = X509_STORE_new(); From 578f07847874f75a410fe1c78d9fdff36836ab56 Mon Sep 17 00:00:00 2001 From: eugene Date: Mon, 23 Dec 2024 14:39:26 -0500 Subject: [PATCH 4/5] win32 path_max fix --- src/openssl/engine.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openssl/engine.c b/src/openssl/engine.c index fc1dee8..a0e3381 100644 --- a/src/openssl/engine.c +++ b/src/openssl/engine.c @@ -16,6 +16,7 @@ #error "USE_OPENSSL must be set to compile this file" #endif +#include #include #include #include @@ -25,10 +26,10 @@ #include "../um_debug.h" #include +#include #include #include -#include -#include +#include #include "keys.h" #include "../keychain.h" From 3d09519cabeed882c3b7e9cc25b4ba9f6e6debb4 Mon Sep 17 00:00:00 2001 From: eugene Date: Mon, 23 Dec 2024 14:58:05 -0500 Subject: [PATCH 5/5] win32 path_max fix --- src/openssl/engine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openssl/engine.c b/src/openssl/engine.c index a0e3381..001a665 100644 --- a/src/openssl/engine.c +++ b/src/openssl/engine.c @@ -36,8 +36,6 @@ #if _WIN32 #include -#include -#pragma comment (lib, "crypt32.lib") #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif @@ -1116,6 +1114,8 @@ goto on_error; \ } #if _WIN32 +#include +#pragma comment (lib, "crypt32.lib") static X509_STORE *load_system_certs() { X509_STORE *store = X509_STORE_new();