LIBRESSL-EVP_PKEY_CTX_SET_TLS1_PRF_MD(3)

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

πŸ’… EVP_PKEY_CTX_SET_TLS1_PRF_MD(3) β€” the TLS PRF key derivation girlies ✨

okay so bestie, this is a page from the libcrypto manual and honestly? it's a little niche but it slaps once you get it. we're talking TLS PRF key derivation β€” the thing that turns your secret into actual key material. no cap, it's kind of the whole vibe behind TLS 1.0/1.1 keying. πŸŽ€


✨ NAME ✨

EVP_PKEY_CTX_set_tls1_prf_md, EVP_PKEY_CTX_set1_tls1_prf_secret, EVP_PKEY_CTX_add1_tls1_prf_seed β€” the TLS PRF key derivation algorithm, aka the three functions you need to make it happen πŸ¦‹


🌸 SYNOPSIS 🌸

first up, the library and the headers you gotta pull in (yes both of them, don't @ me):

library β€œlibcrypto”
#include <openssl/evp.h>
#include <openssl/kdf.h>

and here are the three icons themselves, exactly as they are:

int
EVP_PKEY_CTX_set_tls1_prf_md(EVP_PKEY_CTX *pctx, const EVP_MD *md);

int
EVP_PKEY_CTX_set1_tls1_prf_secret(EVP_PKEY_CTX *pctx,
    unsigned char *sec, int seclen);

int
EVP_PKEY_CTX_add1_tls1_prf_seed(EVP_PKEY_CTX *pctx, unsigned char *seed,
    int seedlen);

πŸ’œ DESCRIPTION πŸ’œ

So the EVP_PKEY_TLS1_PRF algorithm implements the PRF key derivation function for TLS. It's giving "no thoughts head empty" in the best way β€” it has no associated private key and only implements key derivation using EVP_PKEY_derive(3). That's it. That's the whole job. πŸ‘‘

EVP_PKEY_set_tls1_prf_md() sets the message digest associated with the TLS PRF. And here's the cute special case: EVP_md5_sha1(3) gets treated specially β€” it uses the PRF algorithm with both MD5 and SHA-1, exactly like TLS 1.0 and 1.1 did. iconic behavior, honestly. 🌈

EVP_PKEY_CTX_set_tls1_prf_secret() sets the secret value of the TLS PRF to seclen bytes of the buffer sec. Heads up: any existing secret value is replaced, and any seed is reset. so it's a clean slate moment, periodt. πŸ’…

EVP_PKEY_CTX_add1_tls1_prf_seed() sets the seed to seedlen bytes of seed. And if a seed is already set? it gets appended to the existing value. it's additive, it's generous, it's main character energy. 🫢


πŸŽ€ STRING CTRLS πŸŽ€

the TLS PRF also supports string based control operations using EVP_PKEY_CTX_ctrl_str(3). here's the rundown of the type params, bestie:

  • the type parameter "md" uses the supplied value as the name of the digest algorithm to use.
  • the type parameters "secret" and "seed" use the supplied value parameter as a secret or seed value.
  • the names "hexsecret" and "hexseed" are similar, except they take a hex string which gets converted to binary. hex girlies rise 🧚

πŸ”₯ NOTES πŸ”₯

  • All these functions are implemented as macros. (yes, macros. don't come for me, that's just how it is.)
  • A context for the TLS PRF can be obtained by calling:
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
  • The digest, secret value and seed must be set before a key is derived, or an error occurs. no skipping steps, babe 😭
  • The total length of all seeds cannot exceed 1024 bytes in length β€” and like, that should be more than enough for any normal use of the TLS PRF. fr fr.
  • The output length of the PRF is specified by the length parameter in the EVP_PKEY_derive(3) function. Since the output length is variable, setting the buffer to NULL is not meaningful for the TLS PRF. so don't do that πŸ™ˆ

⭐ RETURN VALUES ⭐

All these functions return 1 for success and 0 or a negative value for failure. And specifically: a return value of -2 indicates the operation is not supported by the public key algorithm. ok so -2 is the "this isn't my thing" number, noted. πŸ’€


🌸 EXAMPLES 🌸

this example derives 10 bytes using SHA-256 with the secret key "secret" and seed value "seed". look at her go:

EVP_PKEY_CTX *pctx;
unsigned char out[10];
size_t outlen = sizeof(out);

pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
if (EVP_PKEY_derive_init(pctx) <= 0)
    /* Error */
if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha256()) <= 0)
    /* Error */
if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0)
    /* Error */
if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0)
    /* Error */
if (EVP_PKEY_derive(pctx, out, &outlen) <= 0)
    /* Error */

πŸ¦‹ SEE ALSO πŸ¦‹

go read these next, iykyk πŸ’–


πŸ‘‘ HISTORY πŸ‘‘

These functions first appeared in OpenSSL 1.1.0 and have been available since OpenBSD 7.6. glow up timeline honestly ✨


and that's the page, bestie! this one came from the Debian crew, dated June 8, 2025, under the manual name EVP_PKEY_CTX_SET_TLS1_PRF_MD(3) β€” mwah, go derive some keys responsibly πŸ’œπŸŽ€

πŸ“¦ where this page comes from