I try to test the sample code from https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_CTX_set1_hkdf_salt.html (with some modification). When I run it, the function call of EVP_PKEY_derive returns 0 but no clear error code.
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
int main()
{
char error[1024];
if (EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL))
{
unsigned char out[1024];
size_t outlen = sizeof(out);
if (EVP_PKEY_derive_init(pctx) <= 0 ||
EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0 ||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, "salt", 4) <= 0 ||
EVP_PKEY_CTX_set1_hkdf_key(pctx, "secret", 6) <= 0 ||
EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 5) <= 0 )
{
ERR_error_string(ERR_get_error(), error);
printf("%s\n", error);
}
else
{
int r = EVP_PKEY_derive(pctx, NULL, &outlen);
if (r <= 0)
{
ERR_error_string(ERR_get_error(), error);
printf("EVP_PKEY_derive: %d, %s\n", r, error);
}
else
{
printf("%d\n", outlen);
}
}
EVP_PKEY_CTX_free(pctx);
}
return 0;
}
Below is the output.
EVP_PKEY_derive: 0, error:00000000:lib(0):func(0):reason(0)
BTW, the openssl I am using is 1.1.1k.
Although the error handling here is not the best, the doc page you link explains the cause:
The output length of an HKDF expand operation is specified via the length parameter to the EVP_PKEY_derive(3) function. Since the HKDF output length is variable, passing a NULL buffer as a means to obtain the requisite length is not meaningful with HKDF in any mode that performs an expand operation. Instead, the caller must allocate a buffer of the desired length, and pass that buffer to EVP_PKEY_derive(3) along with (a pointer initialized to) the desired length. Passing a NULL buffer to obtain the length is allowed when using EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY.
and your code (like the example) defaults the mode to extract-and-expand, thus it does perform expand.
OpenSSL 3 returns rc=1 with outlen=-1 (a length that is always invalid) for this case. (It also adds a new EVP_KDF*
API that supports quite a few more KDFs than EVP_PKEY_derive*
does.)