| 1 | |
|---|---|
| 2 | #include "cpr/ssl_ctx.h" |
| 3 | |
| 4 | #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION |
| 5 | |
| 6 | #ifdef OPENSSL_BACKEND_USED |
| 7 | |
| 8 | #include <openssl/err.h> |
| 9 | #include <openssl/safestack.h> |
| 10 | #include <openssl/ssl.h> |
| 11 | |
| 12 | namespace cpr { |
| 13 | |
| 14 | /** |
| 15 | * The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL. |
| 16 | * If an error is returned from the callback no attempt to establish a connection is made and |
| 17 | * the perform operation will return the callback's error code. |
| 18 | * |
| 19 | * Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html |
| 20 | * https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html |
| 21 | */ |
| 22 | CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) { |
| 23 | // Check arguments |
| 24 | if (raw_cert_buf == nullptr || sslctx == nullptr) { |
| 25 | printf(format: "Invalid callback arguments\n"); |
| 26 | return CURLE_ABORTED_BY_CALLBACK; |
| 27 | } |
| 28 | |
| 29 | // Setup pointer |
| 30 | X509_STORE* store = nullptr; |
| 31 | X509* cert = nullptr; |
| 32 | BIO* bio = nullptr; |
| 33 | char* cert_buf = static_cast<char*>(raw_cert_buf); |
| 34 | |
| 35 | // Create a memory BIO using the data of cert_buf. |
| 36 | // Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen. |
| 37 | bio = BIO_new_mem_buf(buf: cert_buf, len: -1); |
| 38 | |
| 39 | // Load the PEM formatted certicifate into an X509 structure which OpenSSL can use. |
| 40 | PEM_read_bio_X509(out: bio, x: &cert, cb: nullptr, u: nullptr); |
| 41 | if (cert == nullptr) { |
| 42 | printf(format: "PEM_read_bio_X509 failed\n"); |
| 43 | return CURLE_ABORTED_BY_CALLBACK; |
| 44 | } |
| 45 | |
| 46 | // Get a pointer to the current certificate verification storage |
| 47 | store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx)); |
| 48 | |
| 49 | // Add the loaded certificate to the verification storage |
| 50 | const int status = X509_STORE_add_cert(ctx: store, x: cert); |
| 51 | if (status == 0) { |
| 52 | printf(format: "Error adding certificate\n"); |
| 53 | return CURLE_ABORTED_BY_CALLBACK; |
| 54 | } |
| 55 | |
| 56 | // Decrement the reference count of the X509 structure cert and frees it up |
| 57 | X509_free(a: cert); |
| 58 | |
| 59 | // Free the entire bio chain |
| 60 | BIO_free(a: bio); |
| 61 | |
| 62 | // The CA certificate was loaded successfully into the verification storage |
| 63 | return CURLE_OK; |
| 64 | } |
| 65 | |
| 66 | } // namespace cpr |
| 67 | |
| 68 | #endif // OPENSSL_BACKEND_USED |
| 69 | |
| 70 | #endif // SUPPORT_CURLOPT_SSL_CTX_FUNCTION |