vibhav950
vibhav950

Reputation: 39

How can I do an ECDH key exchange with OpenSSL 3.0

Most of the API that EC_KEY* functions like EC_KEY_get0_public_key have been deprecated in OpenSSL 3.0, so as far as I know there's no way but to use the EVP interface. I want to export the public key to a buffer, calculate a MAC over it and then verify the MAC before using the key for a DH key exchange at the recipient end.

I could get a EVP_PKEY object with the generated EC key but I cannot figure out how to extract the public key (raw bytes) and the group name in a way that I can reconstruct for an ECDH key exchange.

void generateAndExport() {
  /* params have been set */
  EVP_PKEY_CTX *keygen_ctx;
  EC_PKEY *ec_key;
  size_t pubkey_size;

  if (!(keygen_ctx = EVP_PKEY_CTX_new(ec_params, NULL)))
    return -1;

  if (!EVP_PKEY_keygen_init(keygen_ctx))
    return -1;

  if (!EVP_PKEY_keygen(keygen_ctx, &ec_key))
    return -1;

  pubkey_size = 0;
  /* Query the buffer size */
  if (!EVP_PKEY_get_octet_string_param(
          ec_key, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pubkey_size))
    return -1;

  /* Allocate the buffer for the public key */
  if (!(ec_pub = calloc(1, pubkey_size)))
    return -1;

  /* Get the public key */
  if (!EVP_PKEY_get_octet_string_param(ec_key,
                                       OSSL_PKEY_PARAM_PUB_KEY, ec_pub,
                                       pubkey_size, &pubkey_size))
    return -1;

  /* calculate a MAC over the public key */

cleanup:
  EVP_PKEY_CTX_free(keygen_ctx);
  EVP_PKEY_free(ec_key);
  return 0;
}

Edit: This seems to be the correct code for doing exactly what I wanted. If anyone would like to know, here is the code I used for recovering the public key and deriving a shared secret:

void deriveSharedSecret(EVP_PKEY *priv,
                        unsigned char *pkey,
                        size_t pkey_len,
                        unsigned char *group_name,
                        unsigned char **shared_key,
                        size_t *shared_key_len) {
  EVP_PKEY_CTX *derive_ctx = NULL;
  EVP_PKEY *peer_key = NULL;

  CHECK(pkey && (pkey_len > 0));

  CHECK(!(peer_key = EVP_PKEY_new_raw_public_key(
          EVP_PKEY_EC,
          NULL,
          pkey,
          pkey_len)));
  CHECK(derive_ctx = EVP_PKEY_CTX_new(priv, NULL));
  CHECK(EVP_PKEY_derive_init(derive_ctx));
  CHECK(EVP_PKEY_CTX_set_group_name(derive_ctx, group_name));
  CHECK(EVP_PKEY_derive_set_peer(derive_ctx, peer_key));

  /* Query buffer size for shared secret */
  *shared_key_len = 0;
  CHECK(EVP_PKEY_derive(derive_ctx, NULL, shared_key_len));

  if (!(*shared_key = calloc(1, *shared_key_len)))
    return -1;
  CHECK(EVP_PKEY_derive(derive_ctx, *shared_key, shared_key_len));

  EVP_PKEY_free(peer_key);
  EVP_PKEY_CTX_free(derive_ctx);
  return 0;
}

Also, to get the group name:

unsigned char groupname[MAX_GROUP_NAME_SIZE];
size_t groupname_len;

CHECK(EVP_PKEY_get_octet_string_param(
      ec_key,
      OSSL_PKEY_PARAM_GROUP_NAME,
      groupname,
      0,
      &groupname_len));

Upvotes: 0

Views: 130

Answers (0)

Related Questions