1---
2c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
3SPDX-License-Identifier: curl
4Title: CURLOPT_SSL_CTX_FUNCTION
5Section: 3
6Source: libcurl
7See-also:
8  - CURLOPT_CA_CACHE_TIMEOUT (3)
9  - CURLOPT_CAINFO (3)
10  - CURLOPT_CAINFO_BLOB (3)
11  - CURLOPT_SSL_CTX_DATA (3)
12  - CURLOPT_SSL_VERIFYHOST (3)
13  - CURLOPT_SSL_VERIFYPEER (3)
14Protocol:
15  - TLS
16TLS-backend:
17  - OpenSSL
18  - wolfSSL
19  - mbedTLS
20  - BearSSL
21Added-in: 7.10.6
22---
23
24# NAME
25
26CURLOPT_SSL_CTX_FUNCTION - SSL context callback
27
28# SYNOPSIS
29
30~~~c
31#include <curl/curl.h>
32
33CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *clientp);
34
35CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CTX_FUNCTION,
36                          ssl_ctx_callback);
37~~~
38
39# DESCRIPTION
40
41Pass a pointer to your callback function, which should match the prototype
42shown above.
43
44This callback function gets called by libcurl just before the initialization
45of an SSL connection after having processed all other SSL related options to
46give a last chance to an application to modify the behavior of the SSL
47initialization. The *ssl_ctx* parameter is a pointer to the SSL library's
48*SSL_CTX* for OpenSSL or wolfSSL, a pointer to *mbedtls_ssl_config* for
49mbedTLS or a pointer to *br_ssl_client_context* for BearSSL. If an error is
50returned from the callback no attempt to establish a connection is made and
51the perform operation returns the callback's error code. Set the *clientp*
52argument passed in to this callback with the CURLOPT_SSL_CTX_DATA(3) option.
53
54This function gets called for all new connections made to a server, during the
55SSL negotiation. While *ssl_ctx* points to a newly initialized object each
56time, the pointer may still be the same as in a prior call.
57
58To use this callback, a non-trivial amount of knowledge of your SSL library is
59necessary. For example, you can use this function to call library-specific
60callbacks to add additional validation code for certificates, and even to
61change the actual URI of an HTTPS request.
62
63For OpenSSL, asynchronous certificate verification via *SSL_set_retry_verify*
64is supported. (Added in 8.3.0)
65
66The CURLOPT_SSL_CTX_FUNCTION(3) callback allows the application to reach in
67and modify SSL details in the connection without libcurl itself knowing
68anything about it, which then subsequently can lead to libcurl unknowingly
69reusing SSL connections with different properties. To remedy this you may set
70CURLOPT_FORBID_REUSE(3) from the callback function.
71
72If you are using DNS-over-HTTPS (DoH) via CURLOPT_DOH_URL(3) then this
73callback is also called for those transfers and the curl handle is set to an
74internal handle. **This behavior is subject to change.** We recommend setting
75CURLOPT_PRIVATE(3) on your curl handle so you can identify it correctly in the
76context callback. If you have a reason to modify DoH SSL context please let us
77know on the curl-library mailing list because we are considering removing this
78capability.
79
80libcurl does not guarantee the lifetime of the passed in object once this
81callback function has returned. Your application must not assume that it can
82keep using the SSL context or data derived from it once this function is
83completed.
84
85For libcurl builds using TLS backends that support CA caching and
86CURLOPT_CA_CACHE_TIMEOUT(3) is not set to zero, multiple calls to this
87callback may be done with the same CA store in memory.
88
89# DEFAULT
90
91NULL
92
93# %PROTOCOLS%
94
95# EXAMPLE
96
97~~~c
98/* OpenSSL specific */
99
100#include <openssl/ssl.h>
101#include <curl/curl.h>
102#include <stdio.h>
103
104static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm)
105{
106  X509_STORE *store;
107  X509 *cert = NULL;
108  BIO *bio;
109  char *mypem = parm;
110  /* get a BIO */
111  bio = BIO_new_mem_buf(mypem, -1);
112  /* use it to read the PEM formatted certificate from memory into an
113   * X509 structure that SSL can use
114   */
115  PEM_read_bio_X509(bio, &cert, 0, NULL);
116  if(!cert)
117    printf("PEM_read_bio_X509 failed...\n");
118
119  /* get a pointer to the X509 certificate store (which may be empty) */
120  store = SSL_CTX_get_cert_store((SSL_CTX *)sslctx);
121
122  /* add our certificate to this store */
123  if(X509_STORE_add_cert(store, cert) == 0)
124    printf("error adding certificate\n");
125
126  /* decrease reference counts */
127  X509_free(cert);
128  BIO_free(bio);
129
130  /* all set to go */
131  return CURLE_OK;
132}
133
134int main(void)
135{
136  CURL *ch;
137  CURLcode rv;
138  char *mypem = /* example CA cert PEM - shortened */
139    "-----BEGIN CERTIFICATE-----\n"
140    "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"
141    "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"
142    "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"
143    "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"
144    "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"
145    "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"
146    "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"
147    "-----END CERTIFICATE-----\n";
148
149  curl_global_init(CURL_GLOBAL_ALL);
150  ch = curl_easy_init();
151
152  curl_easy_setopt(ch, CURLOPT_SSLCERTTYPE, "PEM");
153  curl_easy_setopt(ch, CURLOPT_SSL_VERIFYPEER, 1L);
154  curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/");
155
156  curl_easy_setopt(ch, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
157  curl_easy_setopt(ch, CURLOPT_SSL_CTX_DATA, mypem);
158  rv = curl_easy_perform(ch);
159  if(!rv)
160    printf("*** transfer succeeded ***\n");
161  else
162    printf("*** transfer failed ***\n");
163
164  curl_easy_cleanup(ch);
165  curl_global_cleanup();
166  return rv;
167}
168~~~
169
170# %AVAILABILITY%
171
172# RETURN VALUE
173
174CURLE_OK if supported; or an error such as:
175
176CURLE_NOT_BUILT_IN - Not supported by the SSL backend
177