MINOR: ssl: Factorize AES GCM data processing

The parameter parsing and processing and the actual crypto part of the
aes_gcm converter are interleaved. This patch puts the crypto parts in a
dedicated function for better reuse in the upcoming JWE processing.
This commit is contained in:
Remi Tricot-Le Breton 2026-01-13 11:50:53 +01:00 committed by William Lallemand
parent 6870551a57
commit f0e64de753

View file

@ -283,13 +283,95 @@ static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
_ret; \
})
/*
* Encrypt or decrypt <data> alongside additional data <aad> using AES algorithm
* in GCM mode thanks to <key> of size <key_size> using <nonce> as
* initialization vector. The authentication tag <aead_tag> is validated as
* well (in case of decryption) or constructed in case of encryption.
* Returns -1 in case of error, either during the authentication or
* encryption/decryption process, or the <out> buffer size in case of success.
*/
static int aes_process(struct buffer *data, struct buffer *nonce, struct buffer *key, int key_size,
struct buffer *aead_tag, struct buffer *aad, struct buffer *out, int decrypt)
{
EVP_CIPHER_CTX *ctx = NULL;
int size;
int ret;
ctx = EVP_CIPHER_CTX_new();
if (!ctx)
goto err;
switch(key_size) {
case 128:
sample_conv_aes_gcm_init(decrypt, ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
break;
case 192:
sample_conv_aes_gcm_init(decrypt, ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
break;
case 256:
sample_conv_aes_gcm_init(decrypt, ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
break;
default:
goto err;
}
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, b_data(nonce), NULL))
goto err;
/* Initialise IV and key */
if(!sample_conv_aes_gcm_init(decrypt, ctx, NULL, NULL, (unsigned char*)b_orig(key),
(unsigned char*)b_orig(nonce)))
goto err;
if (aad && b_data(aad)) {
if (!sample_conv_aes_gcm_update(decrypt, ctx, NULL, (int*)&out->data,
(unsigned char*)b_orig(aad), (int)b_data(aad)))
goto err;
}
if (!sample_conv_aes_gcm_update(decrypt, ctx, (unsigned char*)b_orig(out),
(int*)&out->data, (unsigned char*)b_orig(data), (int)b_data(data)))
goto err;
size = out->data;
if (decrypt)
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, b_data(aead_tag), b_orig(aead_tag)))
goto err;
ret = sample_conv_aes_gcm_final(decrypt, ctx, (unsigned char*)out->area + out->data,
(int *)&out->data);
if (ret <= 0)
goto err;
out->data += size;
if (!decrypt) {
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, b_orig(aead_tag)))
goto err;
aead_tag->data = 16;
}
EVP_CIPHER_CTX_free(ctx);
return b_data(out);
err:
EVP_CIPHER_CTX_free(ctx);
return -1;
}
/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
static int sample_conv_aes_gcm(const struct arg *arg_p, struct sample *smp, void *private)
{
struct sample nonce, key, aead_tag, aad;
struct buffer *smp_trash = NULL, *smp_trash_alloc = NULL, *aad_trash = NULL;
EVP_CIPHER_CTX *ctx = NULL;
struct buffer *nonce_trash = NULL, *key_trash = NULL, *aead_tag_trash = NULL;
int size, ret, dec;
int retval = 0;
smp_trash_alloc = alloc_trash_chunk();
if (!smp_trash_alloc)
@ -301,156 +383,128 @@ static int sample_conv_aes_gcm(const struct arg *arg_p, struct sample *smp, void
smp_trash_alloc->data = smp_trash_alloc->size;
memcpy(smp_trash_alloc->area, smp->data.u.str.area, smp_trash_alloc->data);
ctx = EVP_CIPHER_CTX_new();
if (!ctx)
goto err;
smp_trash = alloc_trash_chunk();
if (!smp_trash)
goto err;
goto end;
smp_set_owner(&nonce, smp->px, smp->sess, smp->strm, smp->opt);
if (!sample_conv_var2smp_str(&arg_p[1], &nonce))
goto err;
goto end;
if (arg_p[1].type == ARGT_VAR) {
size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
nonce_trash = alloc_trash_chunk();
if (!nonce_trash)
goto end;
size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, nonce_trash->area, nonce_trash->size);
if (size < 0)
goto err;
smp_trash->data = size;
nonce.data.u.str = *smp_trash;
goto end;
nonce_trash->data = size;
nonce.data.u.str = *nonce_trash;
}
/* encrypt (0) or decrypt (1) */
dec = (arg_p[0].type_flags == 1);
/* Set cipher type and mode */
switch(arg_p[0].data.sint) {
case 128:
sample_conv_aes_gcm_init(dec, ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
break;
case 192:
sample_conv_aes_gcm_init(dec, ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
break;
case 256:
sample_conv_aes_gcm_init(dec, ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
break;
}
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce.data.u.str.data, NULL);
/* Initialise IV */
if(!sample_conv_aes_gcm_init(dec, ctx, NULL, NULL, NULL, (unsigned char *) nonce.data.u.str.area))
goto err;
smp_set_owner(&key, smp->px, smp->sess, smp->strm, smp->opt);
if (!sample_conv_var2smp_str(&arg_p[2], &key))
goto err;
goto end;
if (arg_p[2].type == ARGT_VAR) {
size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
key_trash = alloc_trash_chunk();
if (!key_trash)
goto end;
size = base64dec(key.data.u.str.area, key.data.u.str.data, key_trash->area, key_trash->size);
if (size < 0)
goto err;
smp_trash->data = size;
key.data.u.str = *smp_trash;
goto end;
key_trash->data = size;
key.data.u.str = *key_trash;
}
/* Initialise key */
if (!sample_conv_aes_gcm_init(dec, ctx, NULL, NULL, (unsigned char *) key.data.u.str.area, NULL))
goto err;
/* if there's an AAD parameter */
if (arg_p[4].type) {
smp_set_owner(&aad, smp->px, smp->sess, smp->strm, smp->opt);
if (!sample_conv_var2smp_str(&arg_p[4], &aad))
goto err;
goto end;
/* if stored in a variable, the base64 decode was not done in check_aes_gcm() */
if (arg_p[4].type == ARGT_VAR) {
int aad_len;
aad_trash = alloc_trash_chunk();
if (!aad_trash)
return 0;
aad_len = base64dec(aad.data.u.str.area, aad.data.u.str.data, aad_trash->area, aad_trash->size);
if (aad_len < 0)
goto err;
goto end;
aad_trash->data = aad_len;
aad.data.u.str = *aad_trash;
}
if (!sample_conv_aes_gcm_update(dec, ctx, NULL, (int *)&smp_trash->data,
(unsigned char *)aad.data.u.str.area, (int)aad.data.u.str.data))
goto err;
}
if (!sample_conv_aes_gcm_update(dec, ctx, (unsigned char *) smp_trash->area, (int *) &smp_trash->data,
(unsigned char *) smp_trash_alloc->area, (int) smp_trash_alloc->data))
goto err;
smp_set_owner(&aead_tag, smp->px, smp->sess, smp->strm, smp->opt);
if (dec) {
if (!sample_conv_var2smp_str(&arg_p[3], &aead_tag))
goto err;
goto end;
if (arg_p[3].type == ARGT_VAR) {
size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area,
smp_trash_alloc->size);
if (size < 0)
goto err;
smp_trash_alloc->data = size;
aead_tag.data.u.str = *smp_trash_alloc;
}
aead_tag_trash = alloc_trash_chunk();
if (!aead_tag_trash)
goto end;
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead_tag.data.u.str.data,
(void *) aead_tag.data.u.str.area);
size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data,
aead_tag_trash->area, aead_tag_trash->size);
if (size < 0)
goto end;
aead_tag_trash->data = size;
aead_tag.data.u.str = *aead_tag_trash;
}
} else {
aead_tag_trash = alloc_trash_chunk();
if (!aead_tag_trash)
goto end;
}
size = smp_trash->data;
ret = sample_conv_aes_gcm_final(dec, ctx, (unsigned char *) smp_trash->area + smp_trash->data,
(int *) &smp_trash->data);
if (ret <= 0)
goto err;
size = aes_process(smp_trash_alloc, &nonce.data.u.str, &key.data.u.str, arg_p[0].data.sint,
dec ? &aead_tag.data.u.str : aead_tag_trash,
arg_p[4].type ? &aad.data.u.str : NULL, smp_trash, dec);
if (size < 0)
goto end;
if (!dec) {
struct buffer *trash = get_trash_chunk();
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, (void *) trash->area);
chunk_memcpy(trash, b_orig(aead_tag_trash), b_data(aead_tag_trash));
aead_tag.data.u.str = *smp_trash_alloc;
ret = a2base64(trash->area, 16, aead_tag.data.u.str.area, aead_tag.data.u.str.size);
if (ret < 0)
goto err;
goto end;
aead_tag.data.u.str.data = ret;
aead_tag.data.type = SMP_T_STR;
if (!var_set(&arg_p[3].data.var, &aead_tag,
(arg_p[3].data.var.scope == SCOPE_PROC) ? VF_COND_IFEXISTS : 0)) {
goto err;
goto end;
}
}
smp->data.u.str.data = size + smp_trash->data;
smp->data.u.str.data = smp_trash->data;
smp->data.u.str.area = smp_trash->area;
smp->data.type = SMP_T_BIN;
smp_dup(smp);
free_trash_chunk(smp_trash_alloc);
free_trash_chunk(smp_trash);
free_trash_chunk(aad_trash);
EVP_CIPHER_CTX_free(ctx);
return 1;
err:
retval = 1;
end:
free_trash_chunk(smp_trash_alloc);
free_trash_chunk(smp_trash);
free_trash_chunk(aad_trash);
EVP_CIPHER_CTX_free(ctx);
return 0;
free_trash_chunk(nonce_trash);
free_trash_chunk(key_trash);
free_trash_chunk(aead_tag_trash);
return retval;
}
#endif