R: Hooks to manipulate the SSL context for curl requests

ssl_ctx {openssl} | R Documentation

## Hooks to manipulate the SSL context for curl requests

### Description

These functions allow for manipulating the SSL context from inside the CURLOPT_SSL_CTX_FUNCTION callback using the curl R package. Note that this is not fully portable and will only work on installations that use matching versions of libssl (see details). It is recommended to only use this locally and if what you need cannot be accomplished using standard libcurl TLS options, e.g. those listed in `curl::curl_options('ssl')` or `curl::curl_options('tls')`.

### Usage

    ssl_ctx_add_cert_to_store(ssl_ctx, cert)

    ssl_ctx_set_verify_callback(ssl_ctx, cb)

    ssl_ctx_curl_version_match()

### Arguments

`ssl_ctx` | pointer object to the SSL context provided in the ssl_ctx_function callback.
`cert` | certificate object, e.g from read_cert or download_ssl_cert.
`cb` | callback function with 1 parameter (the server certificate) and which returns TRUE (for proceed) or FALSE (for abort).

### Details

Curl allows for setting an option called `ssl_ctx_function`: this is a callback function that is triggered during the TLS initiation, before any https connection has been made. This serves as a hook to let you manipulate the TLS configuration (called `SSL_CTX` for historical reasons), in order to control how to curl will validate the authenticity of server certificates for upcoming TLS connections.

Currently we provide 2 such functions: ssl_ctx_add_cert_to_store injects a custom certificate into the trust-store of the current TLS connection. But most flexibility is provided via ssl_ctx_set_verify_callback which allows you to override the function that is used by validate if a server certificate should be trusted. The callback will receive one argument `cert` and has to return `TRUE` or `FALSE` to decide if the cert should be trusted.

By default libcurl re-uses connections, hence the cert validation is only performed in the first request to a given host. Subsequent requests use the already established TLS connection. For testing, it can be useful to set `forbid_reuse` in order to make a new connection for each request, as done in the examples below.

### System compatibility

Passing the SSL_CTX between the curl and openssl R packages only works if they are linked to the same version of libssl. Use ssl_ctx_curl_version_match to test if this is the case. On Debian / Ubuntu you need to build the R curl package against `libcurl4-openssl-dev`, which is usually the case. On Windows you would need to set `CURL_SSL_BACKEND=openssl` in your `~/.Renviron` file. On MacOS things are complicated because it uses LibreSSL instead of OpenSSL by default. You can make it work by compiling the curl R package from source against the homebrew version of curl and then then set `CURL_SSL_BACKEND=openssl` in your `~/.Renviron` file. If your curl and openssl R packages use different versions of libssl, the examples may segfault due to ABI incompatibility of the SSL_CTX structure.

### Examples

    ## Not run:
    # Example 1: accept your local snakeoil https cert
    mycert <- openssl::download_ssl_cert('localhost')[[1]]

    # Setup the callback
    h <- curl::new_handle(ssl_ctx_function = function(ssl_ctx){
      ssl_ctx_add_cert_to_store(ssl_ctx, mycert)
    }, verbose = TRUE, forbid_reuse = TRUE)

    # Perform the request
    req <- curl::curl_fetch_memory('https://localhost', handle = h)

    # Example 2 using a custom verify function
    verify_cb <- function(cert){
      id <- cert$pubkey$fingerprint
      cat("Server cert from:", as.character(id), "\n")
      TRUE # always accept cert
    }

    h <- curl::new_handle(ssl_ctx_function = function(ssl_ctx){
      ssl_ctx_set_verify_callback(ssl_ctx, verify_cb)
    }, verbose = TRUE, forbid_reuse = TRUE)

    # Perform the request
    req <- curl::curl_fetch_memory('https://localhost', handle = h)

    ## End(Not run)

[Package openssl version 2.0.2 Index]