LIBRESSL-SSL_CTX_SET_CLIENT_CERT_CB(3)

πŸ“¦ version 4.4.0, in alpine 3.24, arch rolling

πŸ’… SSL_CTX_SET_CLIENT_CERT_CB(3) β€” the libssl-flavored glow-up ✨

okay so this page is from the libssl / libcrypto corner of the universe (Library Functions Manual energy, we love her), and it's all about the ✨client certificate callback✨. yes bestie, the callback that decides which cert your client hands over when a server comes asking. let's get into it πŸŽ€


🌸 NAME 🌸

SSL_CTX_set_client_cert_cb, SSL_CTX_get_client_cert_cb β€” handle the client certificate callback function, aka the girl who picks which ID you show at the door πŸ’…


✨ SYNOPSIS ✨

she lives in libssl and libcrypto, and bestie you gotta bring the header:

#include <openssl/ssl.h>
void
SSL_CTX_set_client_cert_cb(SSL_CTX *ctx,
    int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey));

int
(*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509,
    EVP_PKEY **pkey);

int
(*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);

πŸ¦‹ DESCRIPTION πŸ¦‹

So SSL_CTX_set_client_cert_cb() sets the client_cert_cb() callback β€” and this callback gets rung up when a server asks for a client certificate and no certificate was already set for the SSL object. it's giving "you got a sec? we need an ID" πŸ“ž

When client_cert_cb is NULL, no callback function is used. simple as that, no cap.

SSL_CTX_get_client_cert_cb() hands you back a pointer to whichever callback function is currently set. the "who's on duty" check πŸ”

client_cert_cb() is your application-defined callback, bestie β€” you write this one. here's the vibe check on what she returns:

  • if it wants to set a certificate: a certificate/private key combo must be set using the x509 and pkey arguments, and you must return 1. the certificate gets installed into ssl πŸ”₯
  • if no certificate should be set: return 0 and no certificate will be sent πŸ’€
  • if you return a negative value: the handshake gets suspended and the handshake function returns immediately. SSL_get_error(3) will return SSL_ERROR_WANT_X509_LOOKUP to tell you the handshake was suspended (iykyk). the next call to the handshake function leads to client_cert_cb() getting called again. and it is literally the job of client_cert_cb() to store information about the state of the last call if it needs to continue 😭

okay so during a handshake (or renegotiation) a server may request a certificate from the client. and a client certificate must only be sent when the server actually did send the request. periodt 🚫

When a certificate has been set using the SSL_CTX_use_certificate(3) family of functions, it will be sent to the server. now here's the tea: the TLS standard requires that only a certificate is sent if it matches the list of acceptable CAs sent by the server. this constraint is violated by the default behavior of the OpenSSL library 😬. using the callback function it's possible to implement a proper selection routine, or to allow user interaction to choose the certificate to be sent. iconic, honestly ✨

If a callback function is defined and no certificate was yet defined for the SSL object, the callback function will be called. if the callback function returns a certificate, the OpenSSL library will try to load the private key and certificate data into the SSL object using the SSL_use_certificate() and SSL_use_private_key() functions. so it will permanently install the certificate and key for this SSL object β€” like, it will not be reset by calling SSL_clear(3) 🫢. if the callback returns no certificate, the OpenSSL library will not send a certificate. that's it, that's the whole deal.


πŸŽ€ SEE ALSO πŸŽ€

go read those too, bestie, they're all in the group chat πŸ’–


πŸ‘‘ HISTORY πŸ‘‘

SSL_CTX_set_client_cert_cb() and SSL_CTX_get_client_cert_cb() first appeared in SSLeay 0.6.6 and have been available since OpenBSD 2.4. vintage. retro. we stan a legacy function 🌈⭐


πŸ’€ BUGS πŸ’€

ugh okay, gather round, because this is the messy part πŸ™ˆ

client_cert_cb() cannot return a complete certificate chain β€” it can only return one client certificate. if the chain only has a length of 2, the root CA certificate may be omitted according to the TLS standard, and thus a standard conforming answer can be sent to the server. πŸŽ€ but for a longer chain, the client must send the complete chain (with the option to leave out the root CA certificate). this can be accomplished only by either:

  • adding the intermediate CA certificates into the trusted certificate store for the SSL_CTX object β€” which results in having to add CA certificates that otherwise maybe would not be trusted 😬, or
  • adding the chain certificates using the SSL_CTX_add_extra_chain_cert(3) function β€” which is only available for the SSL_CTX object as a whole, and that therefore probably can only apply for one client certificate, making the concept of the callback function (to allow the choice from several certificates) questionable πŸ’€
🚨 also, once the SSL object has been used in conjunction with the callback function, the certificate will be set for the SSL object and will not be cleared even when SSL_clear(3) is called. it is therefore mandatory to destroy the SSL object using SSL_free(3) and create a new one to return to the previous state. not optional, bestie. mandatory. fr fr 😭

and that's the page!! πŸ’– brought to you by the Debian girlies, dated June 8, 2025, filed under SSL_CTX_SET_CLIENT_CERT_CB(3) β€” mwah, go set some certs responsibly πŸ§šβ€β™€οΈπŸŒΈπŸ“πŸ’œ

πŸ“¦ where this page comes from