curl/curl
TLS backends
Active contributors: Daniel Stenberg, Stefan Eissing, Viktor Szakats, Jay Satiro
Purpose
curl supports multiple TLS implementations behind a uniform internal API called "vtls". Pick one (or several) at build time. The shared abstraction lives in lib/vtls/vtls.c and lib/vtls/vtls.h; each backend is a separate .c file in lib/vtls/ plus its Curl_ssl vtable.
Supported backends
| Backend | Source | Notes |
|---|---|---|
| OpenSSL / LibreSSL / BoringSSL / AWS-LC / quictls | lib/vtls/openssl.c (~171 KB) |
The reference and most-tested backend |
| GnuTLS | lib/vtls/gtls.c (~74 KB) |
Common on Linux distros that avoid OpenSSL |
| mbedTLS | lib/vtls/mbedtls.c (~51 KB) |
Popular for embedded |
| Schannel | lib/vtls/schannel.c (~99 KB), lib/vtls/schannel_verify.c |
Native Windows, uses the OS cert store |
| wolfSSL | lib/vtls/wolfssl.c (~74 KB) |
Embedded-focused, FIPS variants |
| Rustls | lib/vtls/rustls.c (~45 KB) |
Memory-safe, increasingly popular |
| Apple SecTrust | lib/vtls/apple.c (~9 KB) |
Replacement for SecureTransport, uses the system trust store |
Removed since 2024: NSS, BearSSL, MesaLink, Hyper, msh3, GSKit, Heimdal-only paths. SecureTransport itself was deprecated in 2025.
Key abstractions
| Symbol | File | Description |
|---|---|---|
struct Curl_ssl |
lib/vtls/vtls.h |
The vtable each backend exports — connect, send, recv, shutdown, info, … |
struct ssl_connect_data |
lib/vtls/vtls_int.h |
Per-connection TLS state (handshake state, peer info, certs) |
struct ssl_primary_config |
lib/urldata.h |
The user-visible options that affect TLS connection identity |
Curl_ssl_cfilter_add() |
lib/vtls/vtls.c |
Pushes the TLS cfilter onto a connection |
Curl_ssl_cfilter_for_proxy_add() |
lib/vtls/vtls.c |
Same, for HTTPS-proxy CONNECT TLS |
Curl_ssl_scache_* |
lib/vtls/vtls_scache.c |
TLS-session cache (PSK reuse, ticket reuse) |
Curl_ssl_cipher_suite_* |
lib/vtls/cipher_suite.c |
Curl's portable cipher-suite naming |
Curl_x509asn1_* |
lib/vtls/x509asn1.c |
Backend-independent ASN.1 + X.509 parser used for getinfo queries |
keylog_* |
lib/vtls/keylog.c |
Single shared SSLKEYLOGFILE writer |
How it works
The TLS layer is a connection filter. When a connection should use TLS, Curl_ssl_cfilter_add (or its proxy sibling) pushes a Curl_cftype whose do_connect drives the TLS handshake of the active backend.
sequenceDiagram
participant Conn as connectdata
participant CF as cf_tls
participant SSL as Curl_ssl vtable
participant Lib as backend (e.g. OpenSSL)
Conn->>CF: connect()
CF->>SSL: connect_blocking
SSL->>Lib: SSL_connect / mbedtls_handshake / ...
Lib-->>SSL: WANT_READ / WANT_WRITE / OK
SSL-->>CF: CURLE_AGAIN or CURLE_OK
CF-->>Conn: handshake done
Conn->>CF: send/recv
CF->>SSL: encrypt / decrypt
SSL->>Lib: SSL_write / SSL_readEach backend's Curl_ssl vtable implements the same shape:
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" },
/* features */ SSLSUPP_..., size_of_per_connection_state,
ossl_init, ossl_cleanup, ossl_version,
ossl_data_pending, ossl_random,
ossl_cert_status_request, ossl_connect, ossl_connect_nonblocking,
/* … */
};lib/vtls/vtls.c picks at runtime among the backends compiled in (multiSSL: a build can include several and choose one via CURLOPT_SSL_OPTIONS / --ssl-backend).
Session cache
lib/vtls/vtls_scache.c is a backend-agnostic cache of TLS session tickets / PSKs keyed on origin. It lets a TLS-resumed handshake skip a round trip on reconnect. The cache is shareable via CURL_LOCK_DATA_SSL_SESSION on a share handle.
Cipher suite naming
To let users specify cipher suites portably, curl maintains its own naming layer in lib/vtls/cipher_suite.c. --ciphers and --tls13-ciphers accept curl's spelling and the backend translates it into native names.
Trust roots
By default each backend uses its own trust source:
- OpenSSL/GnuTLS/mbedTLS/wolfSSL/Rustls — use a CA bundle (
/etc/ssl/...,CURLOPT_CAINFO,--cacert) or a CA path - Schannel/Apple — use the OS trust store
- All — pinning via
CURLOPT_PINNEDPUBLICKEYand--pinnedpubkey
The CA bundle generator is scripts/mk-ca-bundle.pl — it reads Mozilla's certdata.txt and produces a PEM file. Trust details: docs/SSLCERTS.md.
ECH (Encrypted Client Hello)
Experimental ECH support exists for OpenSSL forks that have it (BoringSSL, AWS-LC, OpenSSL with the relevant patches). Helpers live in the OpenSSL backend; docs/ECH.md documents the user-visible interface.
Integration points
- Connection filters: TLS is a cfilter; the rest of curl never sees the encryption details. See Connection filters.
- Connection cache:
ssl_primary_configparticipates in the connection key — two requests with mismatched TLS options never share a connection. - HTTP/2 and HTTP/3: ALPN runs as part of the handshake; the result drives whether the next filter pushed is HTTP/2 or fallback HTTP/1.1. See HTTP/2 and HTTP/3.
- Proxies: there can be two TLS filters in the stack (one to the proxy, one to the origin). See Proxies.
Entry points for modification
- New backend → copy
lib/vtls/openssl.cshape, implementCurl_sslvtable, register inlib/vtls/vtls.c, wire build flags intoconfigure.acandCMakeLists.txt. - New TLS option → extend
struct ssl_primary_configandstruct ssl_general_config(lib/urldata.h), add aCURLOPT_*ininclude/curl/curl.h, dispatch inlib/setopt.c, then wire each backend's connect-config code. - New cipher suite name →
lib/vtls/cipher_suite.c.
Related pages
- HTTP/2 and HTTP/3 — ALPN drives the next filter
- Connection filters
- Proxies
- Security
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.