+bool digest_set_key(digest_t *digest, const void *key, size_t len) {
+#if OPENSSL_VERSION_MAJOR < 3
+ digest->hmac_ctx = HMAC_CTX_new();
+
+ if(!digest->hmac_ctx) {
+ abort();
+ }
+
+ HMAC_Init_ex(digest->hmac_ctx, key, (int)len, digest->digest, NULL);
+#else
+ EVP_MAC *mac = EVP_MAC_fetch(NULL, OSSL_MAC_NAME_HMAC, NULL);
+
+ if(!mac) {
+ openssl_err("fetch MAC");
+ return false;
+ }
+
+ digest->hmac_ctx = EVP_MAC_CTX_new(mac);
+ EVP_MAC_free(mac);
+
+ if(!digest->hmac_ctx) {
+ openssl_err("create MAC context");
+ return false;
+ }
+
+ const char *hmac_algo = EVP_MD_get0_name(digest->digest);
+
+ if(!hmac_algo) {
+ openssl_err("get HMAC algorithm name");
+ return false;
+ }
+
+ // The casts are okay, the parameters are not going to change. For example, see:
+ // https://github.com/openssl/openssl/blob/31b7f23d2f958491d46c8a8e61c2b77b1b546f3e/crypto/ec/ecdh_kdf.c#L37-L38
+ const OSSL_PARAM params[] = {
+ OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, (void *)key, len),
+ OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, (void *)hmac_algo, 0),
+ OSSL_PARAM_END,
+ };
+
+ if(!EVP_MAC_init(digest->hmac_ctx, NULL, 0, params)) {
+ openssl_err("set MAC context params");
+ return false;
+ }