3333#include < csignal>
3434#endif
3535
36- #ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
36+ #if defined(OLP_SDK_ENABLE_ENVELOPE_PKEY) || \
37+ defined (OLP_SDK_USE_MD5_CERT_LOOKUP )
3738#include < openssl/ssl.h>
39+ #endif
40+
41+ #ifdef OLP_SDK_ENABLE_ENVELOPE_PKEY
42+ #include < openssl/err.h>
43+ #endif
44+
45+ #ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
3846#include < openssl/x509_vfy.h>
3947#include < sys/stat.h>
4048#include < cstdio>
5058
5159namespace olp {
5260namespace http {
53-
5461namespace {
5562
5663const char * kLogTag = " CURL" ;
@@ -785,7 +792,18 @@ ErrorCode NetworkCurl::SendImplementation(
785792 }
786793
787794#ifdef OLP_SDK_CURL_HAS_SUPPORT_SSL_BLOBS
795+ #ifdef OLP_SDK_ENABLE_ENVELOPE_PKEY
796+ // In VSM/EVP_PKEY mode the private key is injected via the
797+ // InjectEnvelopeKey SSL_CTX_FUNCTION callback. Curl cannot combine
798+ // CURLOPT_SSLCERT_BLOB (cert-only PEM) with a missing CURLOPT_SSLKEY_BLOB:
799+ // it tries to extract the private key from the cert blob and fails with
800+ // "unable to set private key file: '(memory blob)' type PEM".
801+ // Therefore, skip the entire blob-based cert setup and let InjectEnvelopeKey
802+ // set both the client certificate and the EVP_PKEY via SSL_CTX_*.
803+ if (ssl_certificates_blobs_ && !certificate_settings_.pkey_handle ) {
804+ #else
788805 if (ssl_certificates_blobs_) {
806+ #endif
789807 curl_easy_setopt (
790808 curl_handle, CURLOPT_SSLCERT_BLOB ,
791809 olp::porting::get_ptr (ssl_certificates_blobs_->ssl_cert_blob ));
@@ -810,7 +828,13 @@ ErrorCode NetworkCurl::SendImplementation(
810828 curl_easy_setopt (curl_handle, CURLOPT_SSL_VERIFYPEER , 1L );
811829 curl_easy_setopt (curl_handle, CURLOPT_SSL_VERIFYHOST , 2L );
812830
813- #ifdef OLP_SDK_USE_MD5_CERT_LOOKUP
831+ #ifdef OLP_SDK_ENABLE_ENVELOPE_PKEY
832+ if (certificate_settings_.pkey_handle ) {
833+ curl_easy_setopt (curl_handle, CURLOPT_SSL_CTX_FUNCTION ,
834+ &NetworkCurl::InjectEnvelopeKey);
835+ curl_easy_setopt (curl_handle, CURLOPT_SSL_CTX_DATA , handle);
836+ }
837+ #elif defined(OLP_SDK_USE_MD5_CERT_LOOKUP)
814838 curl_easy_setopt (curl_handle, CURLOPT_SSL_CTX_FUNCTION ,
815839 &NetworkCurl::AddMd5LookupMethod);
816840 curl_easy_setopt (curl_handle, CURLOPT_SSL_CTX_DATA , handle);
@@ -1464,5 +1488,90 @@ CURLcode NetworkCurl::AddMd5LookupMethod(CURL*, SSL_CTX* ssl_ctx,
14641488}
14651489#endif
14661490
1491+ #ifdef OLP_SDK_ENABLE_ENVELOPE_PKEY
1492+ CURLcode NetworkCurl::InjectEnvelopeKey (CURL *, SSL_CTX * ssl_ctx,
1493+ RequestHandle* handle) {
1494+ auto self = handle->self .lock ();
1495+ if (!self) {
1496+ OLP_SDK_LOG_ERROR (kLogTag , " Unable to lock cURL handle" );
1497+ return CURLE_ABORTED_BY_CALLBACK ;
1498+ }
1499+
1500+ const auto & cert_blob = self->certificate_settings_ .client_cert_file_blob ;
1501+ if (!cert_blob.empty ()) {
1502+ BIO * bio =
1503+ BIO_new_mem_buf (cert_blob.data (), static_cast <int >(cert_blob.size ()));
1504+ if (!bio) {
1505+ OLP_SDK_LOG_ERROR (kLogTag , " InjectEnvelopeKey: BIO_new_mem_buf failed" );
1506+ return CURLE_SSL_CERTPROBLEM ;
1507+ }
1508+ X509 * cert = PEM_read_bio_X509 (bio, nullptr , nullptr , nullptr );
1509+ BIO_free (bio);
1510+ if (!cert) {
1511+ OLP_SDK_LOG_ERROR (kLogTag ,
1512+ " InjectEnvelopeKey: PEM_read_bio_X509 failed, error="
1513+ << ERR_lib_error_string (ERR_get_error ()));
1514+ return CURLE_SSL_CERTPROBLEM ;
1515+ }
1516+ int rc = SSL_CTX_use_certificate (ssl_ctx, cert);
1517+ X509_free (cert);
1518+ if (rc != 1 ) {
1519+ OLP_SDK_LOG_ERROR (
1520+ kLogTag , " InjectEnvelopeKey: SSL_CTX_use_certificate failed, error="
1521+ << ERR_lib_error_string (ERR_get_error ()));
1522+ return CURLE_SSL_CERTPROBLEM ;
1523+ }
1524+ }
1525+
1526+ const auto & ca_blob = self->certificate_settings_ .cert_file_blob ;
1527+ if (!ca_blob.empty ()) {
1528+ BIO * bio =
1529+ BIO_new_mem_buf (ca_blob.data (), static_cast <int >(ca_blob.size ()));
1530+ if (!bio) {
1531+ OLP_SDK_LOG_WARNING (
1532+ kLogTag ,
1533+ " InjectEnvelopeKey: BIO_new_mem_buf failed for CA blob"
1534+ " — falling back to system CA bundle" );
1535+ } else {
1536+ X509_STORE * store = SSL_CTX_get_cert_store (ssl_ctx);
1537+ int ca_count = 0 ;
1538+ X509 * ca = nullptr ;
1539+ while ((ca = PEM_read_bio_X509 (bio, nullptr , nullptr , nullptr )) !=
1540+ nullptr ) {
1541+ if (store) {
1542+ X509_STORE_add_cert (store, ca);
1543+ }
1544+ X509_free (ca);
1545+ ++ca_count;
1546+ }
1547+ BIO_free (bio);
1548+ // Clear EOF / "cert already in hash table" errors left by the loop
1549+ ERR_clear_error ();
1550+ if (ca_count == 0 ) {
1551+ OLP_SDK_LOG_WARNING (kLogTag ,
1552+ " InjectEnvelopeKey: no CA certificates parsed from"
1553+ " ca_blob — peer verification may fail" );
1554+ } else {
1555+ OLP_SDK_LOG_DEBUG (kLogTag , " InjectEnvelopeKey: added "
1556+ << ca_count
1557+ << " CA cert(s) to trust store" );
1558+ }
1559+ }
1560+ }
1561+
1562+ // Clear the error queue before calling SSL_CTX_use_PrivateKey so that
1563+ // ERR_get_error() in the error path below reflects the actual key error
1564+ ERR_clear_error ();
1565+ if (SSL_CTX_use_PrivateKey (ssl_ctx,
1566+ self->certificate_settings_ .pkey_handle ) != 1 ) {
1567+ OLP_SDK_LOG_ERROR (kLogTag , " Failed to use provided EVP_PKEY, error="
1568+ << ERR_lib_error_string (ERR_get_error ()));
1569+ return CURLE_SSL_CERTPROBLEM ;
1570+ }
1571+
1572+ return CURLE_OK ;
1573+ }
1574+ #endif
1575+
14671576} // namespace http
14681577} // namespace olp
0 commit comments