SSL_CTX_SET_...IENT_CALLBACK(3ossl)

okay bestie, sit down, grab a boba πŸ§‹, because we're reading the 3ossl manual page for SSL_CTX_SET_...IENT_CALLBACK and it's literally all about you (the client) telling OpenSSL "here's my identity, here's my pre-shared key, go off πŸ’…". PSK = pre-shared key, iykyk. no cap, this page is the whole blueprint.


✨ NAME ✨

SSL_psk_client_cb_func, SSL_psk_use_session_cb_func, SSL_CTX_set_psk_client_callback, SSL_set_psk_client_callback, SSL_CTX_set_psk_use_session_callback, SSL_set_psk_use_session_callback β€” set PSK client callback. that's the whole assignment, periodt. πŸŽ€


✨ SYNOPSIS ✨

#include <openssl/ssl.h>

typedef int (*SSL_psk_use_session_cb_func)(SSL *ssl, const EVP_MD *md,
                                           const unsigned char **id,
                                           size_t *idlen,
                                           SSL_SESSION **sess);

void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
                                          SSL_psk_use_session_cb_func cb);
void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb);

typedef unsigned int (*SSL_psk_client_cb_func)(SSL *ssl,
                                               const char *hint,
                                               char *identity,
                                               unsigned int max_identity_len,
                                               unsigned char *psk,
                                               unsigned int max_psk_len);

void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, SSL_psk_client_cb_func cb);
void SSL_set_psk_client_callback(SSL *ssl, SSL_psk_client_cb_func cb);

πŸ’– DESCRIPTION πŸ’–

πŸ¦‹ TLSv1.3 girlies, this one's for you

so if you're a client app and you wanna use TLSv1.3 PSKs, you should use either SSL_CTX_set_psk_use_session_callback() or SSL_set_psk_use_session_callback(), whichever one fits your situation bestie. these functions cannot be used for TLSv1.2 and below PSKs β€” different era, different callback, we'll get there. πŸ™ˆ

the callback function gets handed a pointer to the SSL connection in ssl. iconic.

the first time the callback gets called for a connection, the md parameter is NULL. but in some circumstances the callback will get called a second time 😭 β€” and in that case the server will have already specified a ciphersuite to use, so the PSK must be compatible with the digest for that ciphersuite. that digest shows up in md. and no stress, the PSK your callback returns is allowed to be different between the first and the second time it's called. main character flexibility. πŸ’…

πŸŽ€ what you gotta hand back

on successful completion, the callback must store a pointer to an identifier for the PSK in *id. the identifier length in bytes goes in *idlen. the memory pointed to by *id stays owned by the application, and the app should free it whenever it needs to β€” at any point after the handshake is complete. 🫢

on top of that, the callback should store a pointer to an SSL_SESSION object in *sess. that's what gets used as the basis for the PSK, and at minimum it needs these fields set:

  • The master key β€” you can set this with a call to SSL_SESSION_set1_master_key(3).
  • A ciphersuite β€” only the handshake digest associated with the ciphersuite is actually relevant for the PSK (the server may go on to negotiate any ciphersuite that's compatible with the digest). the application can use any TLSv1.3 ciphersuite. if md is not NULL, then the handshake digest for the ciphersuite should be the same. you can set the ciphersuite with a call to SSL_SESSION_set_cipher(3). and you can check the handshake digest of an SSL_CIPHER object using SSL_CIPHER_get_handshake_digest(3). πŸ‘‘
  • The protocol version β€” set it with a call to SSL_SESSION_set_protocol_version(3), and it should be TLS1_3_VERSION.

also, the maximum early data value should be set via a call to SSL_SESSION_set_max_early_data(3) if the PSK is gonna be used for sending early data. ⭐

alternatively, an SSL_SESSION created from a previous non-PSK handshake can also be used as the basis for a PSK. lowkey flexible of them.

ownership of the SSL_SESSION object gets passed to the OpenSSL library, so it should not be freed by the application. hands off, it's not yours anymore. πŸ™ˆ

πŸ’€ the use-after-free jumpscare

so like I said above, the callback may be called a second time during a handshake. and since ownership of the SSL_SESSION is transferred to OpenSSL on each call, if your callback wants to return the same SSL_SESSION pointer on a subsequent invocation, it must first call SSL_SESSION_up_ref(3) to increment the reference count.

failure to do so will result in a use-after-free error. not cute. not slay. 🚨

alternatively, the callback can just return a different SSL_SESSION object on each call (e.g., by calling SSL_SESSION_dup(3)). problem solved, vibe preserved. ✨

🌸 "sike, no PSK actually"

it's also possible for the callback to succeed but not supply a PSK. in that case no PSK gets sent to the server, but the handshake keeps going. to pull this off, the callback should return successfully and make sure *sess is NULL. the contents of *id and *idlen get ignored. ghosting the server, but politely. 🧚

🌈 TLSv1.2 and below girlies

a client application wishing to use PSK ciphersuites for TLSv1.2 and below must provide a different callback function. this one gets called when the client is sending the ClientKeyExchange message to the server.

the whole purpose of the callback function is to select the PSK identity and the pre-shared key to use during the connection setup phase.

you set the callback using SSL_CTX_set_psk_client_callback() or SSL_set_psk_client_callback(). and here's what it gets handed:

  • the connection in parameter ssl
  • a NUL-terminated PSK identity hint sent by the server in parameter hint
  • a buffer identity of length max_identity_len bytes (including the NUL-terminator) where the resulting NUL-terminated identity is to be stored
  • a buffer psk of length max_psk_len bytes where the resulting pre-shared key is to be stored

πŸ”₯ the crossover episode

the callback for TLSv1.2 will also work in TLSv1.3, although it's recommended to use SSL_CTX_set_psk_use_session_callback() or SSL_set_psk_use_session_callback() for that purpose instead. if TLSv1.3 has been negotiated, then OpenSSL will first check whether a callback was set via SSL_CTX_set_psk_use_session_callback() or SSL_set_psk_use_session_callback() and it will use that one in preference. if no such callback is present, then it checks whether one was set via SSL_CTX_set_psk_client_callback() or SSL_set_psk_client_callback() and uses that instead. in that case, the hint value will always be NULL and the handshake digest will default to SHA-256 for any returned PSK.

and okay one more thing, super important: TLSv1.3 early data exchanges are possible in PSK connections only with the SSL_psk_use_session_cb_func callback, and are not possible with the SSL_psk_client_cb_func callback. so if early data is the dream, pick the right callback. 🌟


πŸ“ NOTES πŸ“

  • note that the parameter hint given to the callback may be NULL. bestie said "no comment" and meant it.
  • a connection established via a TLSv1.3 PSK will appear as if session resumption has occurred, so SSL_session_reused(3) will return true. plot twist, but a cute one. πŸŽ€
  • there are no known security issues with sharing the same PSK between TLSv1.2 (or below) and TLSv1.3. however, the RFC has this note of caution:
"While there is no known way in which the same PSK might produce related output in both versions, only limited analysis has been done. Implementations can ensure safety from cross-protocol related output by not reusing PSKs between TLS 1.3 and TLS 1.2."

read it twice, bestie. πŸ‘‘


πŸ’« RETURN VALUES πŸ’«

SSL_psk_client_cb_func

  • success (callback found a PSK identity and a pre-shared key to use) β†’ the length (> 0) of psk in bytes is returned. πŸŽ‰
  • otherwise, or on errors β†’ the callback should return 0. in this case the connection setup fails. 😭

SSL_psk_use_session_cb_func

  • should return 1 on success, or 0 on failure. in the event of failure, the connection setup fails.

🫢 SEE ALSO 🫢

ssl(7), SSL_CTX_set_psk_find_session_callback(3), SSL_set_psk_find_session_callback(3)


πŸ“œ HISTORY πŸ“œ

SSL_CTX_set_psk_use_session_callback() and SSL_set_psk_use_session_callback() were added in OpenSSL 1.1.1. throwback era. ⭐


Copyright 2006-2026 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


and that's the whole page bestie, we ate and left no crumbs πŸ’…βœ¨ this was OpenSSL 3.5.9, dated 2026-09-2, from the 3ossl manual β€” go forth and PSK responsibly, ily, bye πŸŽ€πŸ¦‹πŸ’–

πŸ“¦ where this page comes from