feat: add EVP APIs for cipher pipelining

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24636)
This commit is contained in:
Ramkumar 2024-09-09 12:28:28 +05:30 committed by Matt Caswell
parent 81af0b04cb
commit ef7967d0b4
11 changed files with 242 additions and 8 deletions

View File

@ -788,6 +788,7 @@ EVP_R_OUTPUT_WOULD_OVERFLOW:202:output would overflow
EVP_R_PARAMETER_TOO_LARGE:187:parameter too large
EVP_R_PARTIALLY_OVERLAPPING:162:partially overlapping buffers
EVP_R_PBKDF2_ERROR:181:pbkdf2 error
EVP_R_PIPELINE_NOT_SUPPORTED:230:pipeline not supported
EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED:179:\
pkey application asn1 method already registered
EVP_R_PRIVATE_KEY_DECODE_ERROR:145:private key decode error
@ -797,6 +798,7 @@ EVP_R_SETTING_XOF_FAILED:227:setting xof failed
EVP_R_SET_DEFAULT_PROPERTY_FAILURE:209:set default property failure
EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE:228:\
signature type and key type incompatible
EVP_R_TOO_MANY_PIPES:231:too many pipes
EVP_R_TOO_MANY_RECORDS:183:too many records
EVP_R_UNABLE_TO_ENABLE_LOCKING:212:unable to enable locking
EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE:215:unable to get maximum request size

View File

@ -93,6 +93,7 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher,
ENGINE *impl, const unsigned char *key,
const unsigned char *iv, int enc,
uint8_t is_pipeline,
const OSSL_PARAM params[])
{
int n;
@ -119,6 +120,8 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
}
/* Code below to be removed when legacy support is dropped. */
if (is_pipeline)
goto nonlegacy;
#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
/*
@ -166,7 +169,7 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
}
/* Start of non-legacy code below */
nonlegacy:
/* Ensure a context left lying around from last time is cleared */
if (cipher != NULL && ctx->cipher != NULL) {
unsigned long flags = ctx->flags;
@ -216,6 +219,12 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
ctx->fetched_cipher = (EVP_CIPHER *)cipher;
}
ctx->cipher = cipher;
if (is_pipeline && !EVP_CIPHER_can_pipeline(cipher, enc)) {
ERR_raise(ERR_LIB_EVP, EVP_R_PIPELINE_NOT_SUPPORTED);
return 0;
}
if (ctx->algctx == NULL) {
ctx->algctx = ctx->cipher->newctx(ossl_provider_ctx(cipher->prov));
if (ctx->algctx == NULL) {
@ -248,7 +257,7 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
OSSL_PARAM *q = param_lens;
const OSSL_PARAM *p;
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
if (p != NULL)
memcpy(q++, p, sizeof(*q));
@ -269,6 +278,9 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx,
}
#endif
if (is_pipeline)
return 1;
if (enc) {
if (ctx->cipher->einit == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
@ -444,7 +456,7 @@ int EVP_CipherInit_ex2(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
const unsigned char *key, const unsigned char *iv,
int enc, const OSSL_PARAM params[])
{
return evp_cipher_init_internal(ctx, cipher, NULL, key, iv, enc, params);
return evp_cipher_init_internal(ctx, cipher, NULL, key, iv, enc, 0, params);
}
int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
@ -452,14 +464,74 @@ int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
{
if (cipher != NULL)
EVP_CIPHER_CTX_reset(ctx);
return evp_cipher_init_internal(ctx, cipher, NULL, key, iv, enc, NULL);
return evp_cipher_init_internal(ctx, cipher, NULL, key, iv, enc, 0, NULL);
}
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
ENGINE *impl, const unsigned char *key,
const unsigned char *iv, int enc)
{
return evp_cipher_init_internal(ctx, cipher, impl, key, iv, enc, NULL);
return evp_cipher_init_internal(ctx, cipher, impl, key, iv, enc, 0, NULL);
}
int EVP_CipherPipelineEncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen,
size_t numpipes,
const unsigned char **iv, size_t ivlen)
{
if (numpipes > EVP_MAX_PIPES) {
ERR_raise(ERR_LIB_EVP, EVP_R_TOO_MANY_PIPES);
return 0;
}
ctx->numpipes = numpipes;
if (!evp_cipher_init_internal(ctx, cipher, NULL, NULL, NULL, 1, 1,
NULL))
return 0;
if (ctx->cipher->p_einit == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return 0;
}
return ctx->cipher->p_einit(ctx->algctx,
key,
keylen,
numpipes,
iv,
ivlen,
NULL);
}
int EVP_CipherPipelineDecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen,
size_t numpipes,
const unsigned char **iv, size_t ivlen)
{
if (numpipes > EVP_MAX_PIPES) {
ERR_raise(ERR_LIB_EVP, EVP_R_TOO_MANY_PIPES);
return 0;
}
ctx->numpipes = numpipes;
if (!evp_cipher_init_internal(ctx, cipher, NULL, NULL, NULL, 0, 1,
NULL))
return 0;
if (ctx->cipher->p_dinit == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return 0;
}
return ctx->cipher->p_dinit(ctx->algctx,
key,
keylen,
numpipes,
iv,
ivlen,
NULL);
}
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
@ -471,6 +543,41 @@ int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
return EVP_DecryptUpdate(ctx, out, outl, in, inl);
}
int EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx,
unsigned char **out, size_t *outl,
const size_t *outsize,
const unsigned char **in, const size_t *inl)
{
size_t i;
if (ossl_unlikely(outl == NULL || inl == NULL)) {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ossl_unlikely(ctx->cipher == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
return 0;
}
if (ossl_unlikely(ctx->cipher->prov == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
return 0;
}
if (ossl_unlikely(ctx->cipher->p_cupdate == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
return 0;
}
for (i = 0; i < ctx->numpipes; i++)
outl[i] = 0;
return ctx->cipher->p_cupdate(ctx->algctx, ctx->numpipes,
out, outl, outsize,
in, inl);
}
int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
{
if (ctx->encrypt)
@ -487,6 +594,39 @@ int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
return EVP_DecryptFinal(ctx, out, outl);
}
int EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx,
unsigned char **out, size_t *outl,
const size_t *outsize)
{
size_t i;
if (ossl_unlikely(outl == NULL)) {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ossl_unlikely(ctx->cipher == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
return 0;
}
if (ossl_unlikely(ctx->cipher->prov == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
return 0;
}
if (ossl_unlikely(ctx->cipher->p_cfinal == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_FINAL_ERROR);
return 0;
}
for (i = 0; i < ctx->numpipes; i++)
outl[i] = 0;
return ctx->cipher->p_cfinal(ctx->algctx, ctx->numpipes,
out, outl, outsize);
}
int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
const unsigned char *key, const unsigned char *iv)
{
@ -1567,7 +1707,7 @@ static void *evp_cipher_from_algorithm(const int name_id,
{
const OSSL_DISPATCH *fns = algodef->implementation;
EVP_CIPHER *cipher = NULL;
int fnciphcnt = 0, fnctxcnt = 0;
int fnciphcnt = 0, fnpipecnt = 0, fnctxcnt = 0;
if ((cipher = evp_cipher_new()) == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
@ -1628,6 +1768,30 @@ static void *evp_cipher_from_algorithm(const int name_id,
break;
cipher->ccipher = OSSL_FUNC_cipher_cipher(fns);
break;
case OSSL_FUNC_CIPHER_PIPELINE_ENCRYPT_INIT:
if (cipher->p_einit != NULL)
break;
cipher->p_einit = OSSL_FUNC_cipher_pipeline_encrypt_init(fns);
fnpipecnt++;
break;
case OSSL_FUNC_CIPHER_PIPELINE_DECRYPT_INIT:
if (cipher->p_dinit != NULL)
break;
cipher->p_dinit = OSSL_FUNC_cipher_pipeline_decrypt_init(fns);
fnpipecnt++;
break;
case OSSL_FUNC_CIPHER_PIPELINE_UPDATE:
if (cipher->p_cupdate != NULL)
break;
cipher->p_cupdate = OSSL_FUNC_cipher_pipeline_update(fns);
fnpipecnt++;
break;
case OSSL_FUNC_CIPHER_PIPELINE_FINAL:
if (cipher->p_cfinal != NULL)
break;
cipher->p_cfinal = OSSL_FUNC_cipher_pipeline_final(fns);
fnpipecnt++;
break;
case OSSL_FUNC_CIPHER_FREECTX:
if (cipher->freectx != NULL)
break;
@ -1674,7 +1838,9 @@ static void *evp_cipher_from_algorithm(const int name_id,
}
}
if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4)
|| (fnciphcnt == 0 && cipher->ccipher == NULL)
|| (fnciphcnt == 0 && cipher->ccipher == NULL && fnpipecnt == 0)
|| (fnpipecnt != 0 && (fnpipecnt < 3 || cipher->p_cupdate == NULL
|| cipher->p_cfinal == NULL))
|| fnctxcnt != 2) {
/*
* In order to be a consistent set of functions we must have at least
@ -1720,6 +1886,15 @@ EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
return cipher;
}
int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc)
{
if (((enc && cipher->p_einit != NULL) || (!enc && cipher->p_dinit != NULL))
&& cipher->p_cupdate != NULL && cipher->p_cfinal != NULL)
return 1;
return 0;
}
int EVP_CIPHER_up_ref(EVP_CIPHER *cipher)
{
int ref = 0;

View File

@ -143,6 +143,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PARTIALLY_OVERLAPPING),
"partially overlapping buffers"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PBKDF2_ERROR), "pbkdf2 error"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PIPELINE_NOT_SUPPORTED),
"pipeline not supported"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED),
"pkey application asn1 method already registered"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PRIVATE_KEY_DECODE_ERROR),
@ -155,6 +157,7 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
"set default property failure"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE),
"signature type and key type incompatible"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_PIPES), "too many pipes"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_TOO_MANY_RECORDS), "too many records"},
{ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNABLE_TO_ENABLE_LOCKING),
"unable to enable locking"},

View File

@ -52,6 +52,7 @@ struct evp_cipher_ctx_st {
int final_used;
int block_mask;
unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
size_t numpipes;
/*
* Opaque ctx returned from a providers cipher algorithm implementation

View File

@ -341,6 +341,10 @@ struct evp_cipher_st {
OSSL_FUNC_cipher_update_fn *cupdate;
OSSL_FUNC_cipher_final_fn *cfinal;
OSSL_FUNC_cipher_cipher_fn *ccipher;
OSSL_FUNC_cipher_pipeline_encrypt_init_fn *p_einit;
OSSL_FUNC_cipher_pipeline_decrypt_init_fn *p_dinit;
OSSL_FUNC_cipher_pipeline_update_fn *p_cupdate;
OSSL_FUNC_cipher_pipeline_final_fn *p_cfinal;
OSSL_FUNC_cipher_freectx_fn *freectx;
OSSL_FUNC_cipher_dupctx_fn *dupctx;
OSSL_FUNC_cipher_get_params_fn *get_params;

View File

@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy

View File

@ -353,6 +353,10 @@ OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, digest_gettable_ctx_params,
# define OSSL_FUNC_CIPHER_GETTABLE_PARAMS 12
# define OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS 13
# define OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS 14
# define OSSL_FUNC_CIPHER_PIPELINE_ENCRYPT_INIT 15
# define OSSL_FUNC_CIPHER_PIPELINE_DECRYPT_INIT 16
# define OSSL_FUNC_CIPHER_PIPELINE_UPDATE 17
# define OSSL_FUNC_CIPHER_PIPELINE_FINAL 18
OSSL_CORE_MAKE_FUNC(void *, cipher_newctx, (void *provctx))
OSSL_CORE_MAKE_FUNC(int, cipher_encrypt_init, (void *cctx,
@ -378,6 +382,23 @@ OSSL_CORE_MAKE_FUNC(int, cipher_cipher,
(void *cctx,
unsigned char *out, size_t *outl, size_t outsize,
const unsigned char *in, size_t inl))
OSSL_CORE_MAKE_FUNC(int, cipher_pipeline_encrypt_init,
(void *cctx,
const unsigned char *key, size_t keylen,
size_t numpipes, const unsigned char **iv, size_t ivlen,
const OSSL_PARAM params[]))
OSSL_CORE_MAKE_FUNC(int, cipher_pipeline_decrypt_init,
(void *cctx,
const unsigned char *key, size_t keylen,
size_t numpipes, const unsigned char **iv, size_t ivlen,
const OSSL_PARAM params[]))
OSSL_CORE_MAKE_FUNC(int, cipher_pipeline_update,
(void *cctx, size_t numpipes,
unsigned char **out, size_t *outl, const size_t *outsize,
const unsigned char **in, const size_t *inl))
OSSL_CORE_MAKE_FUNC(int, cipher_pipeline_final,
(void *cctx, size_t numpipes,
unsigned char **out, size_t *outl, const size_t *outsize))
OSSL_CORE_MAKE_FUNC(void, cipher_freectx, (void *cctx))
OSSL_CORE_MAKE_FUNC(void *, cipher_dupctx, (void *cctx))
OSSL_CORE_MAKE_FUNC(int, cipher_get_params, (OSSL_PARAM params[]))

View File

@ -37,6 +37,8 @@
# define EVP_MAX_BLOCK_LENGTH 32
# define EVP_MAX_AEAD_TAG_LENGTH 16
# define EVP_MAX_PIPES 32
# define PKCS5_SALT_LEN 8
/* Default PKCS#5 iteration count */
# define PKCS5_DEFAULT_ITER 2048
@ -611,6 +613,7 @@ int EVP_CIPHER_get_type(const EVP_CIPHER *cipher);
# define EVP_CIPHER_type EVP_CIPHER_get_type
EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm,
const char *properties);
int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc);
int EVP_CIPHER_up_ref(EVP_CIPHER *cipher);
void EVP_CIPHER_free(EVP_CIPHER *cipher);
@ -807,6 +810,23 @@ __owur int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
int *outl, const unsigned char *in, int inl);
__owur int EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm,
int *outl);
__owur int EVP_CipherPipelineEncryptInit(EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen,
size_t numpipes,
const unsigned char **iv, size_t ivlen);
__owur int EVP_CipherPipelineDecryptInit(EVP_CIPHER_CTX *ctx,
const EVP_CIPHER *cipher,
const unsigned char *key, size_t keylen,
size_t numpipes,
const unsigned char **iv, size_t ivlen);
__owur int EVP_CipherPipelineUpdate(EVP_CIPHER_CTX *ctx,
unsigned char **out, size_t *outl,
const size_t *outsize,
const unsigned char **in, const size_t *inl);
__owur int EVP_CipherPipelineFinal(EVP_CIPHER_CTX *ctx,
unsigned char **outm, size_t *outl,
const size_t *outsize);
__owur int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm,
int *outl);

View File

@ -100,6 +100,7 @@
# define EVP_R_PARAMETER_TOO_LARGE 187
# define EVP_R_PARTIALLY_OVERLAPPING 162
# define EVP_R_PBKDF2_ERROR 181
# define EVP_R_PIPELINE_NOT_SUPPORTED 230
# define EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED 179
# define EVP_R_PRIVATE_KEY_DECODE_ERROR 145
# define EVP_R_PRIVATE_KEY_ENCODE_ERROR 146
@ -107,6 +108,7 @@
# define EVP_R_SETTING_XOF_FAILED 227
# define EVP_R_SET_DEFAULT_PROPERTY_FAILURE 209
# define EVP_R_SIGNATURE_TYPE_AND_KEY_TYPE_INCOMPATIBLE 228
# define EVP_R_TOO_MANY_PIPES 231
# define EVP_R_TOO_MANY_RECORDS 183
# define EVP_R_UNABLE_TO_ENABLE_LOCKING 212
# define EVP_R_UNABLE_TO_GET_MAXIMUM_REQUEST_SIZE 215

View File

@ -5831,3 +5831,8 @@ i2d_OSSL_TIME_PERIOD ? 3_5_0 EXIST::FUNCTION:
OSSL_TIME_PERIOD_free ? 3_5_0 EXIST::FUNCTION:
OSSL_TIME_PERIOD_new ? 3_5_0 EXIST::FUNCTION:
OSSL_TIME_PERIOD_it ? 3_5_0 EXIST::FUNCTION:
EVP_CIPHER_can_pipeline ? 3_5_0 EXIST::FUNCTION:
EVP_CipherPipelineEncryptInit ? 3_5_0 EXIST::FUNCTION:
EVP_CipherPipelineDecryptInit ? 3_5_0 EXIST::FUNCTION:
EVP_CipherPipelineUpdate ? 3_5_0 EXIST::FUNCTION:
EVP_CipherPipelineFinal ? 3_5_0 EXIST::FUNCTION:

View File

@ -124,6 +124,7 @@ my %params = (
'CIPHER_PARAM_NUM' => "num", # uint
'CIPHER_PARAM_ROUNDS' => "rounds", # uint
'CIPHER_PARAM_AEAD_TAG' => "tag", # octet_string
'CIPHER_PARAM_PIPELINE_AEAD_TAG' => "pipeline-tag",# octet_ptr
'CIPHER_PARAM_AEAD_TLS1_AAD' => "tlsaad", # octet_string
'CIPHER_PARAM_AEAD_TLS1_AAD_PAD' => "tlsaadpad", # size_t
'CIPHER_PARAM_AEAD_TLS1_IV_FIXED' => "tlsivfixed", # octet_string