CLIENT_CERT_CB(3ssl)

πŸ“¦ version 4.1.0, in opensuse-leap 16.0

✨ SSL_CTX_SET_CLIENT_CERT_CB πŸ’…

okay bestie, so this one is from the Library Functions Manual (the SSL_CTX_SET_CLIENT_CERT_(3) page, to be exact) and it's all about the client certificate callback function β€” the little hook that decides which cert your client sends when a server asks for one. it's giving "who am I today" energy and honestly it's iconic πŸŽ€


🌸 NAME 🌸

SSL_CTX_set_client_cert_cb, SSL_CTX_get_client_cert_cb β€” handle client certificate callback function 🫢


✨ SYNOPSIS ✨

#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);

like yes, that last one is a function pointer typedef-ish situation, we don't make the rules, we just slay within them πŸ’€


πŸ’– DESCRIPTION πŸ’–

so SSL_CTX_set_client_cert_cb() sets the client_cert_cb() callback β€” it's the function that gets called when a server requests a client certificate and no certificate was yet set for the SSL object. main character callback behavior, lowkey 🌟

when client_cert_cb is NULL, no callback function is used. nothing, nada, no vibe 🌈

SSL_CTX_get_client_cert_cb() returns a pointer to the currently set callback function. it's the "who's on aux right now" function, basically πŸ‘‘

and now the actual callback, client_cert_cb(), which is the application-defined one:

  • if it wants to set a certificate, a certificate/private key combination must be set using the x509 and pkey arguments, and 1 must be returned. the certificate will be installed into ssl ✨
  • if no certificate should be set, 0 has to be returned and no certificate will be sent πŸ™ˆ
  • a negative return value will suspend the handshake and the handshake function will return immediately. SSL_get_error(3) will return SSL_ERROR_WANT_X509_LOOKUP to indicate that the handshake was suspended. the next call to the handshake function will again lead to the call of client_cert_cb(). it is the job of the client_cert_cb() to store information about the state of the last call, if required to continue πŸ“Œ
bestie pls remember: if you return negative you gotta keep your own receipts, because the callback has to remember where it was in the process. that's your homework, not OpenSSL's πŸ“

okay so during a handshake (or renegotiation) a server may request a certificate from the client. a client certificate must only be sent when the server did send the request. no sending certs unprompted, that's not the vibe πŸ’…

when a certificate has been set using the SSL_CTX_use_certificate(3) family of functions, it will be sent to the server. 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 😭 (yes, really, that's what the page says, i'm not making it up). using the callback function it is possible to implement a proper selection routine or to allow a user interaction to choose the certificate to be sent β€” so like, you can do the matching yourself, cute and correct πŸ¦‹

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. thus it will permanently install the certificate and key for this SSL object. it will not be reset by calling SSL_clear(3). if the callback returns no certificate, the OpenSSL library will not send a certificate πŸŽ€


πŸ”₯ SEE ALSO πŸ”₯

go read them, they're all friends of this page fr fr πŸ“š


πŸ¦‹ 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. elder scrolls of TLS πŸ‘‘


πŸ’€ BUGS πŸ’€

okay this is the part where we hold hands and read carefully 🫢

client_cert_cb() cannot return a complete certificate chain β€” it can only return one client certificate. so 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). and this can be accomplished only by either:

  1. 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 😬
  2. or by 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 πŸ’€
so yes, the whole "pick from several certs" idea is a little cursed here. the page literally calls it questionable. i'm just the messenger 🌸

and one more thing, and this one is important πŸ’–: 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 🚨

like, actual mandatory. not "optional mandatory". if you want the old state back, SSL_free(3) + fresh object, periodt πŸ‘‘

and that's the page bestie!! 🌈 written from the Debian edition β€” March 27, 2018 β€” version SSL_CTX_SET_CLIENT_CERT_CB(3) πŸ’œ mwah, go forth and send only the certs you meant to send βœ¨πŸŽ€

πŸ“¦ where this page comes from