opensslkdfhkdf

openssl: EVP_PKEY_derive failure


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.


Solution

  • 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.)