EVP_PKEY_CTX_SET_TLS1_PRF_MD(3SSL)

✨ EVP_PKEY_CTX_SET_TLS1_PRF_MD β€” the OpenSSL 3SSL glow-up ✨

okay bestie, pull up a chair 🫢 this is the manual page for EVP_PKEY_CTX_SET_TLS1_PRF_MD from the 3SSL section of the OpenSSL docs, and we're gonna make TLS key derivation make sense. iykyk, but if you don't yet, you're about to. πŸ’…


🌸 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. that's it, that's the trio πŸ‘‘


✨ SYNOPSIS ✨

#include <openssl/kdf.h>

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

no cap, that's the whole API surface. three little functions, one big vibe. πŸ¦‹


πŸ’– DESCRIPTION πŸ’–

so the EVP_PKEY_TLS1_PRF algorithm is the icon that implements the PRF key derivation function for TLS. she has no associated private key β€” like, none, zero, she doesn't need one β€” and the only thing she does is key derivation, via EVP_PKEY_derive(3). main character energy, obviously. πŸ‘‘

  • EVP_PKEY_set_tls1_prf_md() β€” sets the message digest associated with the TLS PRF. and here's the tea: EVP_md5_sha1() is treated as a special case which uses the PRF algorithm using both MD5 and SHA1, exactly like it was used in TLS 1.0 and 1.1. iconic legacy 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 though: any existing secret value is replaced and any seed is reset. it's giving fresh start, but also, watch out, she's not sentimental. πŸ’€
  • 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. so it's add-one, not set-one, the name really did mean what it said, slay. 🌸

πŸŽ€ STRING CTRLS πŸŽ€

the TLS PRF also supports string based control operations using EVP_PKEY_CTX_ctrl_str(3). here's the cheat sheet, 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 is converted to binary. 🧚

πŸ”₯ NOTES πŸ”₯

want a context for the TLS PRF? you get one 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 setting things up mid-derive, that's not the vibe. 🚫

also: the total length of all seeds cannot exceed 1024 bytes in length. which, fr fr, should be more than enough for any normal use of the TLS PRF. πŸ’…

and the output length of the PRF is specified by the length parameter in the EVP_PKEY_derive() function. since the output length is variable, setting the buffer to NULL is not meaningful for the TLS PRF. so don't do that, it's not a slay, it's just confusing. 😭


⭐ RETURN VALUES ⭐

all these functions return 1 for success and 0 or a negative value for failure. but specifically, bestie:

πŸ‘‘ a return value of -2 means the operation is not supported by the public key algorithm.

so if you see a -2, that's not you being bad at code, that's the algorithm saying "not my department." πŸ’€


πŸ¦‹ EXAMPLES πŸ¦‹

this example derives 10 bytes using SHA-256 with the secret key "secret" and seed value "seed". look how clean she is:

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 how every single call gets checked? that's the whole lesson. check your returns, bestie. 🫢


🌈 SEE ALSO 🌈

go read those too, they're the supporting cast and they ate. ✨


πŸ’œ HISTORY πŸ’œ

all of the functions described here were converted from macros to functions in OpenSSL 3.0. glow-up of the century honestly, macros to real functions, we love a redemption arc. 🌸


Copyright 2016-2025 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 πŸ’– this was OpenSSL 4.0.3, dated 2026-09-29 β€” go forth and derive those keys, you absolute icon. periodt. πŸŽ€βœ¨πŸ¦‹

πŸ“¦ where this page comes from