MINOR: jws: introduce jws_b64_hmac_signature() function for HMAC signing

New jws_b64_hmac_signature() duplicates the same functionality as
jws_b64_signature(), but for the use case of HMAC signing.
Intended to be used for ACME EAB.

OpenSSL allows to use EVP_PKEY for HMAC functionality, so
jws_b64_signature() could be reused, but the problem is that although
isn't deprecated it was removed in BoringSSL, and was removed
(due to BoringSSL roots) but then readded back in AWS-LC, because of
"legacy clients" (citing them), for that reason alone I say that having
a dedicated function for hmac is better, HMAC() macro seems to be widely
supported unlike other ways of doing same thing. Another alternative
would be to use EVP_MD API, but it was introduced in OpenSSL 3.0,
so not as widely supported.
This commit is contained in:
Mia Kanashi 2026-05-07 00:17:41 +03:00 committed by William Lallemand
parent 6900278ac6
commit c9e76e5bb1
2 changed files with 47 additions and 0 deletions

View File

@ -11,6 +11,7 @@ size_t EVP_PKEY_to_pub_jwk(EVP_PKEY *pkey, char *dst, size_t dsize);
enum jwt_alg EVP_PKEY_to_jws_alg(EVP_PKEY *pkey);
size_t jws_b64_payload(char *payload, char *dst, size_t dsize);
size_t jws_b64_protected(enum jwt_alg alg, char *kid, char *jwk, char *nonce, char *url, char *dst, size_t dsize);
size_t jws_b64_hmac_signature(char *key, size_t key_len, enum jwt_alg alg, char *b64protected, char *b64payload, char *dst, size_t dsize);
size_t jws_b64_signature(EVP_PKEY *pkey, enum jwt_alg alg, char *b64protected, char *b64payload, char *dst, size_t dsize);
size_t jws_flattened(char *protected, char *payload, char *signature, char *dst, size_t dsize);
size_t jws_thumbprint(EVP_PKEY *pkey, char *dst, size_t dsize);

View File

@ -452,6 +452,52 @@ out:
return 0;
}
/*
* Generate a JWS HMAC signature using the base64url protected buffer and the base64url payload buffer
*
* Return the size of the data or 0
*/
size_t jws_b64_hmac_signature(char *key, size_t key_len, enum jwt_alg alg, char *b64protected, char *b64payload, char *dst, size_t dsize)
{
const EVP_MD *evp_alg = NULL;
int ret = 0;
unsigned char mac[EVP_MAX_MD_SIZE] = {};
unsigned int mac_len = 0;
struct buffer *sig_data = NULL;
if ((sig_data = alloc_trash_chunk()) == NULL)
goto out;
switch (alg) {
case JWS_ALG_HS256: evp_alg = EVP_sha256(); break;
case JWS_ALG_HS384: evp_alg = EVP_sha384(); break;
case JWS_ALG_HS512: evp_alg = EVP_sha512(); break;
default:
goto out;
}
if (!chunk_memcat(sig_data, b64protected, strlen(b64protected)) ||
!chunk_memcat(sig_data, ".", 1) ||
!chunk_memcat(sig_data, b64payload, strlen(b64payload)))
goto out;
if (HMAC(evp_alg, key, (int)key_len,
(unsigned char*)sig_data->area, sig_data->data,
mac, &mac_len) == NULL)
goto out;
ret = a2base64url((const char *)mac, mac_len, dst, dsize);
out:
free_trash_chunk(sig_data);
if (ret > 0)
return ret;
return 0;
}
/*
* Fill a <dst> buffer of <dsize> size with a jwk thumbprint from a pkey
*