Skip to content

Commit 363244f

Browse files
Add custom lookup method for cURL (#1320)
Android certificates are stored using MD5 hash function, but OpenSSL is using SHA-1 for certificates lookup. So add custom lookup method for Android to use MD5. Relates-To: OAM-1458 Signed-off-by: Andrey Kashcheev <[email protected]>
1 parent fb7840e commit 363244f

File tree

3 files changed

+144
-50
lines changed

3 files changed

+144
-50
lines changed

external/curl/CMakeLists.txt.curl.in

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,6 @@ if(NOT TARGET zlib AND NOT ZLIB_FOUND)
3737
)
3838
endif()
3939

40-
#find_package(OpenSSL QUIET)
41-
#message(FATAL_ERROR OPENSSL_FOUND=${OPENSSL_FOUND} " " OpenSSL=${OpenSSL})
42-
4340
if(NOT TARGET OpenSSL AND NOT OPENSSL_FOUND)
4441
ExternalProject_Add(OpenSSL
4542
SOURCE_DIR ${OPENSSL_SOURCE_DIR}
@@ -50,8 +47,6 @@ if(NOT TARGET OpenSSL AND NOT OPENSSL_FOUND)
5047
UPDATE_COMMAND ""
5148
# Add our own cmake files as OpenSSL doesn't provide any.
5249
PATCH_COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/openssl" "${CMAKE_CURRENT_BINARY_DIR}/download/OpenSSL-prefix/src/OpenSSL"
53-
# Make openssl 1.1.1 to us MD5 hash instead of SHA-1 for certificate file names.
54-
COMMAND sed -i "s/h = X509_NAME_hash(name)/h = X509_NAME_hash_old(name)/g" ${CMAKE_CURRENT_BINARY_DIR}/download/OpenSSL-prefix/src/OpenSSL/crypto/x509/by_dir.c
5550
CMAKE_ARGS
5651
@COMMON_PLATFORM_FLAGS@
5752
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>

olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp

Lines changed: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2020 HERE Europe B.V.
2+
* Copyright (C) 2019-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,30 +22,26 @@
2222
#include <algorithm>
2323
#include <cstring>
2424

25-
#include <errno.h>
2625
#include <fcntl.h>
27-
#include <sys/stat.h>
2826
#include <unistd.h>
27+
#include <cerrno>
2928

3029
#if defined(HAVE_SIGNAL_H)
3130
#include <signal.h>
3231
#endif
3332

34-
#ifdef OLP_SDK_NETWORK_HAS_OPENSSL
35-
#include <openssl/crypto.h>
36-
#endif
37-
#ifdef NETWORK_USE_TIMEPROVIDER
33+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
3834
#include <openssl/ssl.h>
35+
#include <openssl/x509_vfy.h>
36+
#include <sys/stat.h>
37+
#include <cstdio>
38+
#elif OLP_SDK_NETWORK_HAS_OPENSSL
39+
#include "olp/core/utils/Dir.h"
3940
#endif
4041

41-
#ifdef NETWORK_USE_TIMEPROVIDER
42-
#include "timeprovider/TimeProvider.h"
43-
#endif
4442
#include "olp/core/http/HttpStatusCode.h"
4543
#include "olp/core/http/NetworkUtils.h"
4644
#include "olp/core/logging/Log.h"
47-
#include "olp/core/porting/platform.h"
48-
#include "olp/core/utils/Dir.h"
4945

5046
namespace olp {
5147
namespace http {
@@ -56,10 +52,56 @@ const char* kLogTag = "CURL";
5652

5753
#ifdef OLP_SDK_ENABLE_ANDROID_CURL
5854
const auto kCurlAndroidCaBundleFolder = "/system/etc/security/cacerts";
59-
#endif
6055

61-
#ifdef OLP_SDK_NETWORK_HAS_OPENSSL
56+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
57+
const char* kLookupMethodName = "DataSDKMd5Lookup";
58+
59+
int Md5LookupCtrl(X509_LOOKUP* ctx, int, const char*, long, char**) {
60+
const auto* cert_path = kCurlAndroidCaBundleFolder;
61+
X509_LOOKUP_set_method_data(ctx, const_cast<char*>(cert_path));
62+
return 1;
63+
}
64+
65+
int Md5LookupGetBySubject(X509_LOOKUP* ctx, X509_LOOKUP_TYPE type,
66+
X509_NAME* name, X509_OBJECT* ret) {
67+
if (type != X509_LU_X509) {
68+
OLP_SDK_LOG_ERROR_F(kLogTag, "Unsupported lookup type, type=%d", type);
69+
return 0;
70+
}
71+
72+
const char* base_path =
73+
static_cast<const char*>(X509_LOOKUP_get_method_data(ctx));
74+
const auto name_hash = X509_NAME_hash_old(name);
75+
76+
char buf[256];
77+
for (auto idx = 0;; ++idx) {
78+
snprintf(buf, sizeof(buf), "%s/%08lx.%d", base_path, name_hash, idx);
79+
80+
struct stat st {};
81+
if (stat(buf, &st) < 0) {
82+
// There is no such certificate
83+
break;
84+
}
85+
86+
// `X509_load_cert_file` returns number of loaded objects
87+
const auto load_cert_ret = X509_load_cert_file(ctx, buf, X509_FILETYPE_PEM);
88+
if (load_cert_ret == 0) {
89+
OLP_SDK_LOG_ERROR_F(kLogTag, "Failed to load certificate file, buf=%s",
90+
buf);
91+
return 0;
92+
}
93+
}
6294

95+
// Update return result
96+
auto* x509_data = X509_new();
97+
X509_set_subject_name(x509_data, name);
98+
X509_OBJECT_set1_X509(ret, x509_data);
99+
100+
return 1;
101+
}
102+
#endif
103+
104+
#elif OLP_SDK_NETWORK_HAS_OPENSSL
63105
const auto kCurlCaBundleName = "ca-bundle.crt";
64106

65107
std::string DefaultCaBundlePath() { return kCurlCaBundleName; }
@@ -155,26 +197,6 @@ int ConvertErrorCode(CURLcode curl_code) {
155197
}
156198
}
157199

158-
#ifdef OLP_SDK_NETWORK_HAS_OPENSSL
159-
#ifdef NETWORK_USE_TIMEPROVIDER
160-
static curl_code SslctxFunction(CURL* curl, void* sslctx, void*) {
161-
// get the current time in seconds since epoch
162-
std::uint64_t time = static_cast<std::uint64_t>(
163-
TimeProvider::getClock()->timeSinceEpochMs() / 1000);
164-
#if OPENSSL_VERSION_NUMBER < 0x10100000L
165-
X509_STORE* store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
166-
X509_VERIFY_PARAM_set_time(store->param, time_t(time));
167-
#else
168-
X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
169-
X509_VERIFY_PARAM_set_time(param, time_t(time));
170-
SSL_CTX_set1_param(static_cast<SSL_CTX*>(sslctx), param);
171-
X509_VERIFY_PARAM_free(param);
172-
#endif
173-
return CURLE_OK;
174-
}
175-
#endif
176-
#endif
177-
178200
/**
179201
* @brief CURL get upload/download data.
180202
* @param[in] handle CURL easy handle.
@@ -210,7 +232,11 @@ void GetTrafficData(CURL* handle, uint64_t& upload_bytes,
210232

211233
CURLcode SetCaBundlePaths(CURL* handle) {
212234
OLP_SDK_CORE_UNUSED(handle);
235+
213236
#ifdef OLP_SDK_ENABLE_ANDROID_CURL
237+
// FIXME: We could disable this lookup as it won't work on most devices
238+
// (probably all of them) since OpenSSL still will be trying to find
239+
// certificate with SHA1 lookup
214240
return curl_easy_setopt(handle, CURLOPT_CAPATH, kCurlAndroidCaBundleFolder);
215241
#elif OLP_SDK_NETWORK_HAS_OPENSSL
216242
const auto curl_ca_bundle = CaBundlePath();
@@ -227,7 +253,6 @@ int64_t GetElapsedTime(std::chrono::steady_clock::time_point start) {
227253
std::chrono::steady_clock::now() - start)
228254
.count();
229255
}
230-
231256
} // anonymous namespace
232257

233258
NetworkCurl::NetworkCurl(size_t max_requests_count)
@@ -300,12 +325,23 @@ bool NetworkCurl::Initialize() {
300325
return false;
301326
}
302327

328+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
329+
md5_lookup_method_ = X509_LOOKUP_meth_new(kLookupMethodName);
330+
331+
X509_LOOKUP_meth_set_ctrl(md5_lookup_method_, Md5LookupCtrl);
332+
X509_LOOKUP_meth_set_get_by_subject(md5_lookup_method_,
333+
Md5LookupGetBySubject);
334+
#endif
335+
303336
// handles setup
304337
std::shared_ptr<NetworkCurl> that = shared_from_this();
305338
for (auto& handle : handles_) {
306339
handle.handle = nullptr;
307340
handle.in_use = false;
308341
handle.self = that;
342+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
343+
handle.md5_lookup_method = md5_lookup_method_;
344+
#endif
309345
}
310346

311347
std::unique_lock<std::mutex> lock(event_mutex_);
@@ -320,6 +356,11 @@ bool NetworkCurl::Initialize() {
320356

321357
void NetworkCurl::Deinitialize() {
322358
std::lock_guard<std::mutex> init_lock(init_mutex_);
359+
360+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
361+
X509_LOOKUP_meth_free(md5_lookup_method_);
362+
#endif
363+
323364
// Stop worker thread
324365
if (!IsStarted()) {
325366
OLP_SDK_LOG_DEBUG(kLogTag, "Already deinitialized, this=" << this);
@@ -467,8 +508,9 @@ ErrorCode NetworkCurl::SendImplementation(
467508

468509
const auto& config = request.GetSettings();
469510

470-
RequestHandle* handle = GetHandle(id, callback, header_callback,
471-
data_callback, payload, request.GetBody());
511+
RequestHandle* handle =
512+
GetHandle(id, std::move(callback), std::move(header_callback),
513+
std::move(data_callback), payload, request.GetBody());
472514
if (!handle) {
473515
return ErrorCode::NETWORK_OVERLOAD_ERROR;
474516
}
@@ -572,8 +614,11 @@ ErrorCode NetworkCurl::SendImplementation(
572614

573615
curl_easy_setopt(handle->handle, CURLOPT_SSL_VERIFYPEER, 1L);
574616
curl_easy_setopt(handle->handle, CURLOPT_SSL_VERIFYHOST, 2L);
575-
#ifdef NETWORK_USE_TIMEPROVIDER
576-
curl_easy_setopt(handle->handle, CURLOPT_SSL_CTX_FUNCTION, SslctxFunction);
617+
618+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
619+
curl_easy_setopt(handle->handle, CURLOPT_SSL_CTX_FUNCTION,
620+
&NetworkCurl::AddMd5LookupMethod);
621+
curl_easy_setopt(handle->handle, CURLOPT_SSL_CTX_DATA, handle);
577622
#endif
578623

579624
curl_easy_setopt(handle->handle, CURLOPT_FOLLOWLOCATION, 1L);
@@ -671,9 +716,9 @@ NetworkCurl::RequestHandle* NetworkCurl::GetHandle(
671716
curl_easy_setopt(handle.handle, CURLOPT_NOSIGNAL, 1L);
672717
}
673718
handle.in_use = true;
674-
handle.callback = callback;
675-
handle.header_callback = header_callback;
676-
handle.data_callback = data_callback;
719+
handle.callback = std::move(callback);
720+
handle.header_callback = std::move(header_callback);
721+
handle.data_callback = std::move(data_callback);
677722
handle.id = id;
678723
handle.count = 0u;
679724
handle.offset = 0u;
@@ -1105,5 +1150,27 @@ void NetworkCurl::Run() {
11051150
OLP_SDK_LOG_DEBUG(kLogTag, "Thread exit, this=" << this);
11061151
}
11071152

1153+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
1154+
CURLcode NetworkCurl::AddMd5LookupMethod(CURL*, SSL_CTX* ssl_ctx,
1155+
RequestHandle* handle) {
1156+
auto self = handle->self.lock();
1157+
if (!self) {
1158+
OLP_SDK_LOG_ERROR(kLogTag, "Unable to lock cURL handle");
1159+
return CURLE_ABORTED_BY_CALLBACK;
1160+
}
1161+
1162+
auto* cert_store = SSL_CTX_get_cert_store(ssl_ctx);
1163+
auto* lookup = X509_STORE_add_lookup(cert_store, handle->md5_lookup_method);
1164+
if (lookup) {
1165+
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_PEM);
1166+
} else {
1167+
OLP_SDK_LOG_ERROR(kLogTag, "Failed to add lookup method");
1168+
return CURLE_ABORTED_BY_CALLBACK;
1169+
}
1170+
1171+
return CURLE_OK;
1172+
}
1173+
#endif
1174+
11081175
} // namespace http
11091176
} // namespace olp

olp-cpp-sdk-core/src/http/curl/NetworkCurl.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2019-2020 HERE Europe B.V.
2+
* Copyright (C) 2019-2022 HERE Europe B.V.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,14 +30,25 @@
3030

3131
#include <curl/curl.h>
3232

33+
#ifdef OLP_SDK_ENABLE_ANDROID_CURL
3334
#ifdef OLP_SDK_NETWORK_HAS_OPENSSL
34-
#include <openssl/crypto.h>
35+
#include <openssl/ossl_typ.h>
36+
37+
#ifdef OPENSSL_NO_MD5
38+
#error cURL enabled network implementation for Android requires MD5 from OpenSSL
39+
#endif
40+
41+
// Android uses MD5 to encode certificates name, but OpenSSL uses SHA1 for
42+
// certificates lookup -> so OpenSSL won't be able to get appropriate
43+
// certificate as it won't be able to locate one. We need to add our custom
44+
// lookup method that uses MD5. Old SHA1 lookup will be left as is.
45+
#define OLP_SDK_USE_MD5_CERT_LOOKUP
46+
#endif
3547
#endif
3648

3749
#include <olp/core/http/Network.h>
3850
#include <olp/core/http/NetworkRequest.h>
3951

40-
4152
namespace olp {
4253
namespace http {
4354

@@ -113,6 +124,9 @@ class NetworkCurl : public olp::http::Network,
113124
bool cancelled{};
114125
bool skip_content{};
115126
char error_text[CURL_ERROR_SIZE]{};
127+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
128+
X509_LOOKUP_METHOD* md5_lookup_method{nullptr};
129+
#endif
116130
};
117131

118132
/**
@@ -271,6 +285,19 @@ class NetworkCurl : public olp::http::Network,
271285
*/
272286
inline bool IsStarted() const;
273287

288+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
289+
/**
290+
* @brief Adds new lookup method for certificates search routine.
291+
*
292+
* @param[in] curl cURL instance.
293+
* @param[in] ssl_ctx OpenSSL context.
294+
* @param[in] handle Related RequestHandle.
295+
* @return An error code for the operation.
296+
*/
297+
static CURLcode AddMd5LookupMethod(CURL* curl, SSL_CTX* ssl_ctx,
298+
RequestHandle* handle);
299+
#endif
300+
274301
/// Contexts for every network request.
275302
std::vector<RequestHandle> handles_;
276303

@@ -326,6 +353,11 @@ class NetworkCurl : public olp::http::Network,
326353
std::unique_ptr<std::mutex[]> ssl_mutexes_{};
327354
#endif
328355

356+
#ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
357+
/// Additional lookup method.
358+
X509_LOOKUP_METHOD* md5_lookup_method_{nullptr};
359+
#endif
360+
329361
/// Stores value if `curl_global_init()` was successful on construction.
330362
bool curl_initialized_;
331363
};

0 commit comments

Comments
 (0)