From 2c938e2ee8b420e3a1260a2446f3f820f01e71d5 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 1 Oct 2019 09:40:57 +0100 Subject: [PATCH] Implement provider support for Asym Ciphers Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/10152) --- crypto/err/openssl.txt | 1 + crypto/evp/evp_local.h | 19 + crypto/evp/pmeth_fn.c | 381 ++++++++++++++++-- crypto/evp/pmeth_lib.c | 55 ++- include/crypto/evp.h | 9 + include/openssl/core_numbers.h | 42 +- include/openssl/evp.h | 15 + include/openssl/types.h | 2 + .../common/include/prov/providercommonerr.h | 1 + providers/common/provider_err.c | 1 + util/libcrypto.num | 8 + 11 files changed, 501 insertions(+), 33 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index f3fb8a55d9..9c0f94413a 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2695,6 +2695,7 @@ PROV_R_INVALID_DIGEST:122:invalid digest PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count PROV_R_INVALID_IVLEN:116:invalid ivlen PROV_R_INVALID_IV_LENGTH:109:invalid iv length +PROV_R_INVALID_KEY:158:invalid key PROV_R_INVALID_KEYLEN:117:invalid keylen PROV_R_INVALID_KEY_LEN:124:invalid key len PROV_R_INVALID_KEY_LENGTH:105:invalid key length diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index 803f7863a3..e229cf2971 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -143,6 +143,25 @@ struct evp_signature_st { OSSL_OP_signature_settable_ctx_md_params_fn *settable_ctx_md_params; } /* EVP_SIGNATURE */; +struct evp_asym_cipher_st { + int name_id; + OSSL_PROVIDER *prov; + CRYPTO_REF_COUNT refcnt; + CRYPTO_RWLOCK *lock; + + OSSL_OP_asym_cipher_newctx_fn *newctx; + OSSL_OP_asym_cipher_encrypt_init_fn *encrypt_init; + OSSL_OP_asym_cipher_encrypt_fn *encrypt; + OSSL_OP_asym_cipher_decrypt_init_fn *decrypt_init; + OSSL_OP_asym_cipher_decrypt_fn *decrypt; + OSSL_OP_asym_cipher_freectx_fn *freectx; + OSSL_OP_asym_cipher_dupctx_fn *dupctx; + OSSL_OP_asym_cipher_get_ctx_params_fn *get_ctx_params; + OSSL_OP_asym_cipher_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_OP_asym_cipher_set_ctx_params_fn *set_ctx_params; + OSSL_OP_asym_cipher_settable_ctx_params_fn *settable_ctx_params; +} /* EVP_ASYM_CIPHER */; + int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen, ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md, diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c index d49d80bffe..1115e18ba2 100644 --- a/crypto/evp/pmeth_fn.c +++ b/crypto/evp/pmeth_fn.c @@ -563,70 +563,391 @@ int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx, return ctx->pmeth->verify_recover(ctx, rout, routlen, sig, siglen); } -int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) +static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation) { - int ret; - if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { - EVPerr(EVP_F_EVP_PKEY_ENCRYPT_INIT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + int ret = 0; + void *provkey = NULL; + EVP_ASYM_CIPHER *cipher = NULL; + + if (ctx == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } - ctx->operation = EVP_PKEY_OP_ENCRYPT; - if (!ctx->pmeth->encrypt_init) - return 1; - ret = ctx->pmeth->encrypt_init(ctx); + + evp_pkey_ctx_free_old_ops(ctx); + ctx->operation = operation; + + if (ctx->algorithm == NULL || ctx->engine != NULL) + goto legacy; + + /* + * Because we cleared out old ops, we shouldn't need to worry about + * checking if exchange is already there. Keymgmt is a different + * matter, as it isn't tied to a specific EVP_PKEY op. + */ + cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, ctx->algorithm, ctx->propquery); + if (cipher != NULL && ctx->keymgmt == NULL) { + int name_id = EVP_ASYM_CIPHER_number(cipher); + + ctx->keymgmt = + evp_keymgmt_fetch_by_number(ctx->libctx, name_id, ctx->propquery); + } + + if (ctx->keymgmt == NULL + || cipher == NULL + || (EVP_KEYMGMT_provider(ctx->keymgmt) + != EVP_ASYM_CIPHER_provider(cipher))) { + /* + * We don't have the full support we need with provided methods, + * let's go see if legacy does. Also, we don't need to free + * ctx->keymgmt here, as it's not necessarily tied to this + * operation. It will be freed by EVP_PKEY_CTX_free(). + */ + EVP_ASYM_CIPHER_free(cipher); + goto legacy; + } + + ctx->op.ciph.cipher = cipher; + + if (ctx->pkey != NULL) { + provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0); + if (provkey == NULL) { + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + goto err; + } + } + ctx->op.ciph.ciphprovctx = cipher->newctx(ossl_provider_ctx(cipher->prov)); + if (ctx->op.ciph.ciphprovctx == NULL) { + /* The provider key can stay in the cache */ + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + goto err; + } + + switch (operation) { + case EVP_PKEY_OP_ENCRYPT: + if (cipher->encrypt_init == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ret = -2; + goto err; + } + ret = cipher->encrypt_init(ctx->op.ciph.ciphprovctx, provkey); + break; + case EVP_PKEY_OP_DECRYPT: + if (cipher->decrypt_init == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ret = -2; + goto err; + } + ret = cipher->decrypt_init(ctx->op.ciph.ciphprovctx, provkey); + break; + default: + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + goto err; + } + + if (ret <= 0) { + cipher->freectx(ctx->op.ciph.ciphprovctx); + ctx->op.ciph.ciphprovctx = NULL; + goto err; + } + return 1; + + legacy: + if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } + switch(ctx->operation) { + case EVP_PKEY_OP_ENCRYPT: + if (ctx->pmeth->encrypt_init == NULL) + return 1; + ret = ctx->pmeth->encrypt_init(ctx); + break; + case EVP_PKEY_OP_DECRYPT: + if (ctx->pmeth->decrypt_init == NULL) + return 1; + ret = ctx->pmeth->decrypt_init(ctx); + break; + default: + EVPerr(0, EVP_R_INITIALIZATION_ERROR); + ret = -1; + } + + err: if (ret <= 0) ctx->operation = EVP_PKEY_OP_UNDEFINED; return ret; } +int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) +{ + return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_ENCRYPT); +} + int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { - if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { - EVPerr(EVP_F_EVP_PKEY_ENCRYPT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + int ret; + + if (ctx == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + if (ctx->operation != EVP_PKEY_OP_ENCRYPT) { - EVPerr(EVP_F_EVP_PKEY_ENCRYPT, EVP_R_OPERATON_NOT_INITIALIZED); + EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED); return -1; } + + if (ctx->op.ciph.ciphprovctx == NULL) + goto legacy; + + ret = ctx->op.ciph.cipher->encrypt(ctx->op.ciph.ciphprovctx, out, outlen, + (out == NULL ? 0 : *outlen), in, inlen); + return ret; + + legacy: + if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) { + EVPerr(EVP_F_EVP_PKEY_ENCRYPT, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_ENCRYPT) return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen); } int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { - int ret; - if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { - EVPerr(EVP_F_EVP_PKEY_DECRYPT_INIT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; - } - ctx->operation = EVP_PKEY_OP_DECRYPT; - if (!ctx->pmeth->decrypt_init) - return 1; - ret = ctx->pmeth->decrypt_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + return evp_pkey_asym_cipher_init(ctx, EVP_PKEY_OP_DECRYPT); } int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { - if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { - EVPerr(EVP_F_EVP_PKEY_DECRYPT, - EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + int ret; + + if (ctx == NULL) { + EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + if (ctx->operation != EVP_PKEY_OP_DECRYPT) { - EVPerr(EVP_F_EVP_PKEY_DECRYPT, EVP_R_OPERATON_NOT_INITIALIZED); + EVPerr(0, EVP_R_OPERATON_NOT_INITIALIZED); return -1; } + + if (ctx->op.ciph.ciphprovctx == NULL) + goto legacy; + + ret = ctx->op.ciph.cipher->decrypt(ctx->op.ciph.ciphprovctx, out, outlen, + (out == NULL ? 0 : *outlen), in, inlen); + return ret; + + legacy: + if (ctx->pmeth == NULL || ctx->pmeth->decrypt == NULL) { + EVPerr(EVP_F_EVP_PKEY_DECRYPT, + EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return -2; + } M_check_autoarg(ctx, out, outlen, EVP_F_EVP_PKEY_DECRYPT) return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen); } + + +static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov) +{ + EVP_ASYM_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_ASYM_CIPHER)); + + cipher->lock = CRYPTO_THREAD_lock_new(); + if (cipher->lock == NULL) { + OPENSSL_free(cipher); + return NULL; + } + cipher->prov = prov; + ossl_provider_up_ref(prov); + cipher->refcnt = 1; + + return cipher; +} + +static void *evp_asym_cipher_from_dispatch(int name_id, + const OSSL_DISPATCH *fns, + OSSL_PROVIDER *prov) +{ + EVP_ASYM_CIPHER *cipher = NULL; + int ctxfncnt = 0, encfncnt = 0, decfncnt = 0; + int gparamfncnt = 0, sparamfncnt = 0; + + if ((cipher = evp_asym_cipher_new(prov)) == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + cipher->name_id = name_id; + + for (; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_ASYM_CIPHER_NEWCTX: + if (cipher->newctx != NULL) + break; + cipher->newctx = OSSL_get_OP_asym_cipher_newctx(fns); + ctxfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT: + if (cipher->encrypt_init != NULL) + break; + cipher->encrypt_init = OSSL_get_OP_asym_cipher_encrypt_init(fns); + encfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_ENCRYPT: + if (cipher->encrypt != NULL) + break; + cipher->encrypt = OSSL_get_OP_asym_cipher_encrypt(fns); + encfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT: + if (cipher->decrypt_init != NULL) + break; + cipher->decrypt_init = OSSL_get_OP_asym_cipher_decrypt_init(fns); + decfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_DECRYPT: + if (cipher->decrypt != NULL) + break; + cipher->decrypt = OSSL_get_OP_asym_cipher_decrypt(fns); + decfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_FREECTX: + if (cipher->freectx != NULL) + break; + cipher->freectx = OSSL_get_OP_asym_cipher_freectx(fns); + ctxfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_DUPCTX: + if (cipher->dupctx != NULL) + break; + cipher->dupctx = OSSL_get_OP_asym_cipher_dupctx(fns); + break; + case OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS: + if (cipher->get_ctx_params != NULL) + break; + cipher->get_ctx_params + = OSSL_get_OP_asym_cipher_get_ctx_params(fns); + gparamfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS: + if (cipher->gettable_ctx_params != NULL) + break; + cipher->gettable_ctx_params + = OSSL_get_OP_asym_cipher_gettable_ctx_params(fns); + gparamfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS: + if (cipher->set_ctx_params != NULL) + break; + cipher->set_ctx_params + = OSSL_get_OP_asym_cipher_set_ctx_params(fns); + sparamfncnt++; + break; + case OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS: + if (cipher->settable_ctx_params != NULL) + break; + cipher->settable_ctx_params + = OSSL_get_OP_asym_cipher_settable_ctx_params(fns); + sparamfncnt++; + break; + } + } + if (ctxfncnt != 2 + || (encfncnt != 0 && encfncnt != 2) + || (decfncnt != 0 && decfncnt != 2) + || (encfncnt != 2 && decfncnt != 2) + || (gparamfncnt != 0 && gparamfncnt != 2) + || (sparamfncnt != 0 && sparamfncnt != 2)) { + /* + * In order to be a consistent set of functions we must have at least + * a set of context functions (newctx and freectx) as well as a pair of + * "cipher" functions: (encrypt_init, encrypt) or + * (decrypt_init decrypt). set_ctx_params and settable_ctx_params are + * optional, but if one of them is present then the other one must also + * be present. The same applies to get_ctx_params and + * gettable_ctx_params. The dupctx function is optional. + */ + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_PROVIDER_FUNCTIONS); + goto err; + } + + return cipher; + err: + EVP_ASYM_CIPHER_free(cipher); + return NULL; +} + +void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher) +{ + if (cipher != NULL) { + int i; + + CRYPTO_DOWN_REF(&cipher->refcnt, &i, cipher->lock); + if (i > 0) + return; + ossl_provider_free(cipher->prov); + CRYPTO_THREAD_lock_free(cipher->lock); + OPENSSL_free(cipher); + } +} + +int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher) +{ + int ref = 0; + + CRYPTO_UP_REF(&cipher->refcnt, &ref, cipher->lock); + return 1; +} + +OSSL_PROVIDER *EVP_ASYM_CIPHER_provider(const EVP_ASYM_CIPHER *cipher) +{ + return cipher->prov; +} + +EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties) +{ + return evp_generic_fetch(ctx, OSSL_OP_ASYM_CIPHER, algorithm, properties, + evp_asym_cipher_from_dispatch, + (int (*)(void *))EVP_ASYM_CIPHER_up_ref, + (void (*)(void *))EVP_ASYM_CIPHER_free); +} + +int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name) +{ + return evp_is_a(cipher->prov, cipher->name_id, name); +} + +int EVP_ASYM_CIPHER_number(const EVP_ASYM_CIPHER *cipher) +{ + return cipher->name_id; +} + +void EVP_ASYM_CIPHER_do_all_provided(OPENSSL_CTX *libctx, + void (*fn)(EVP_ASYM_CIPHER *cipher, + void *arg), + void *arg) +{ + evp_generic_do_all(libctx, OSSL_OP_ASYM_CIPHER, + (void (*)(void *, void *))fn, arg, + evp_asym_cipher_from_dispatch, + (void (*)(void *))EVP_ASYM_CIPHER_free); +} + + +void EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher, + void (*fn)(const char *name, void *data), + void *data) +{ + if (cipher->prov != NULL) + evp_names_do_all(cipher->prov, cipher->name_id, fn, data); +} + diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 30cff95077..6bbe025bfc 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -237,6 +237,12 @@ void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx) EVP_SIGNATURE_free(ctx->op.sig.signature); ctx->op.sig.sigprovctx = NULL; ctx->op.sig.signature = NULL; + } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { + if (ctx->op.ciph.ciphprovctx != NULL && ctx->op.ciph.cipher != NULL) + ctx->op.ciph.cipher->freectx(ctx->op.ciph.ciphprovctx); + EVP_ASYM_CIPHER_free(ctx->op.ciph.cipher); + ctx->op.ciph.ciphprovctx = NULL; + ctx->op.ciph.cipher = NULL; } } @@ -401,6 +407,26 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(const EVP_PKEY_CTX *pctx) } return rctx; } + } else if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(pctx)) { + if (pctx->op.ciph.cipher != NULL) { + rctx->op.ciph.cipher = pctx->op.ciph.cipher; + if (!EVP_ASYM_CIPHER_up_ref(rctx->op.ciph.cipher)) { + OPENSSL_free(rctx); + return NULL; + } + } + if (pctx->op.ciph.ciphprovctx != NULL) { + if (!ossl_assert(pctx->op.ciph.cipher != NULL)) + return NULL; + rctx->op.ciph.ciphprovctx + = pctx->op.ciph.cipher->dupctx(pctx->op.ciph.ciphprovctx); + if (rctx->op.ciph.ciphprovctx == NULL) { + EVP_ASYM_CIPHER_free(rctx->op.ciph.cipher); + OPENSSL_free(rctx); + return NULL; + } + return rctx; + } } rctx->pmeth = pctx->pmeth; @@ -500,6 +526,12 @@ int EVP_PKEY_CTX_get_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) && ctx->op.sig.signature->get_ctx_params != NULL) return ctx->op.sig.signature->get_ctx_params(ctx->op.sig.sigprovctx, params); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx != NULL + && ctx->op.ciph.cipher != NULL + && ctx->op.ciph.cipher->get_ctx_params != NULL) + return ctx->op.ciph.cipher->get_ctx_params(ctx->op.ciph.ciphprovctx, + params); return 0; } @@ -510,6 +542,11 @@ const OSSL_PARAM *EVP_PKEY_CTX_gettable_params(EVP_PKEY_CTX *ctx) && ctx->op.sig.signature->gettable_ctx_params != NULL) return ctx->op.sig.signature->gettable_ctx_params(); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.cipher != NULL + && ctx->op.ciph.cipher->gettable_ctx_params != NULL) + return ctx->op.ciph.cipher->gettable_ctx_params(); + return NULL; } @@ -527,6 +564,12 @@ int EVP_PKEY_CTX_set_params(EVP_PKEY_CTX *ctx, OSSL_PARAM *params) && ctx->op.sig.signature->set_ctx_params != NULL) return ctx->op.sig.signature->set_ctx_params(ctx->op.sig.sigprovctx, params); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx != NULL + && ctx->op.ciph.cipher != NULL + && ctx->op.ciph.cipher->set_ctx_params != NULL) + return ctx->op.ciph.cipher->set_ctx_params(ctx->op.ciph.ciphprovctx, + params); return 0; } @@ -540,6 +583,10 @@ const OSSL_PARAM *EVP_PKEY_CTX_settable_params(EVP_PKEY_CTX *ctx) && ctx->op.sig.signature != NULL && ctx->op.sig.signature->settable_ctx_params != NULL) return ctx->op.sig.signature->settable_ctx_params(); + if (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.cipher != NULL + && ctx->op.ciph.cipher->settable_ctx_params != NULL) + return ctx->op.ciph.cipher->settable_ctx_params(); return NULL; } @@ -670,7 +717,9 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL) || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL)) + && ctx->op.sig.sigprovctx != NULL) + || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx != NULL)) return legacy_ctrl_to_param(ctx, keytype, optype, cmd, p1, p2); if (ctx->pmeth == NULL || ctx->pmeth->ctrl == NULL) { @@ -748,7 +797,9 @@ int EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, if ((EVP_PKEY_CTX_IS_DERIVE_OP(ctx) && ctx->op.kex.exchprovctx != NULL) || (EVP_PKEY_CTX_IS_SIGNATURE_OP(ctx) - && ctx->op.sig.sigprovctx != NULL)) + && ctx->op.sig.sigprovctx != NULL) + || (EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) + && ctx->op.ciph.ciphprovctx != NULL)) return legacy_ctrl_str_to_param(ctx, name, value); if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) { diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 7753bc0e42..7f5e405486 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -42,6 +42,11 @@ struct evp_pkey_ctx_st { EVP_SIGNATURE *signature; void *sigprovctx; } sig; + + struct { + EVP_ASYM_CIPHER *cipher; + void *ciphprovctx; + } ciph; } op; /* Legacy fields below */ @@ -572,6 +577,10 @@ struct evp_pkey_st { #define EVP_PKEY_CTX_IS_DERIVE_OP(ctx) \ ((ctx)->operation == EVP_PKEY_OP_DERIVE) +#define EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx) \ + ((ctx)->operation == EVP_PKEY_OP_ENCRYPT \ + || (ctx)->operation == EVP_PKEY_OP_DECRYPT) + void openssl_add_all_ciphers_int(void); void openssl_add_all_digests_int(void); void evp_cleanup_int(void); diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 5268aca21f..54241c7623 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -157,8 +157,9 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,provider_get_reason_strings, # define OSSL_OP_KEYMGMT 10 # define OSSL_OP_KEYEXCH 11 # define OSSL_OP_SIGNATURE 12 +# define OSSL_OP_ASYM_CIPHER 13 /* Highest known operation number */ -# define OSSL_OP__HIGHEST 12 +# define OSSL_OP__HIGHEST 13 /* Digests */ @@ -484,6 +485,45 @@ OSSL_CORE_MAKE_FUNC(int, OP_signature_set_ctx_md_params, OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_signature_settable_ctx_md_params, (void *ctx)) + +/* Asymmetric Ciphers */ + +# define OSSL_FUNC_ASYM_CIPHER_NEWCTX 1 +# define OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT 2 +# define OSSL_FUNC_ASYM_CIPHER_ENCRYPT 3 +# define OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT 4 +# define OSSL_FUNC_ASYM_CIPHER_DECRYPT 5 +# define OSSL_FUNC_ASYM_CIPHER_FREECTX 6 +# define OSSL_FUNC_ASYM_CIPHER_DUPCTX 7 +# define OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS 8 +# define OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS 9 +# define OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS 10 +# define OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS 11 + +OSSL_CORE_MAKE_FUNC(void *, OP_asym_cipher_newctx, (void *provctx)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_encrypt_init, (void *ctx, void *provkey)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_encrypt, (void *ctx, unsigned char *out, + size_t *outlen, + size_t outsize, + const unsigned char *in, + size_t inlen)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_decrypt_init, (void *ctx, void *provkey)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_decrypt, (void *ctx, unsigned char *out, + size_t *outlen, + size_t outsize, + const unsigned char *in, + size_t inlen)) +OSSL_CORE_MAKE_FUNC(void, OP_asym_cipher_freectx, (void *ctx)) +OSSL_CORE_MAKE_FUNC(void *, OP_asym_cipher_dupctx, (void *ctx)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_get_ctx_params, + (void *ctx, OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_asym_cipher_gettable_ctx_params, + (void)) +OSSL_CORE_MAKE_FUNC(int, OP_asym_cipher_set_ctx_params, + (void *ctx, const OSSL_PARAM params[])) +OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_asym_cipher_settable_ctx_params, + (void)) + # ifdef __cplusplus } # endif diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 05bf87147c..e6b08d0b72 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1531,6 +1531,21 @@ void EVP_SIGNATURE_names_do_all(const EVP_SIGNATURE *signature, void (*fn)(const char *name, void *data), void *data); +void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher); +int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher); +OSSL_PROVIDER *EVP_ASYM_CIPHER_provider(const EVP_ASYM_CIPHER *cipher); +EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm, + const char *properties); +int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name); +int EVP_ASYM_CIPHER_number(const EVP_ASYM_CIPHER *cipher); +void EVP_ASYM_CIPHER_do_all_provided(OPENSSL_CTX *libctx, + void (*fn)(EVP_ASYM_CIPHER *cipher, + void *arg), + void *arg); +void EVP_ASYM_CIPHER_names_do_all(const EVP_ASYM_CIPHER *cipher, + void (*fn)(const char *name, void *data), + void *data); + int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, diff --git a/include/openssl/types.h b/include/openssl/types.h index 8cfeb6ee22..151e3f1713 100644 --- a/include/openssl/types.h +++ b/include/openssl/types.h @@ -116,6 +116,8 @@ typedef struct evp_keyexch_st EVP_KEYEXCH; typedef struct evp_signature_st EVP_SIGNATURE; +typedef struct evp_asym_cipher_st EVP_ASYM_CIPHER; + typedef struct evp_Encode_Ctx_st EVP_ENCODE_CTX; typedef struct hmac_ctx_st HMAC_CTX; diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h index 48daf69861..503f0270c5 100644 --- a/providers/common/include/prov/providercommonerr.h +++ b/providers/common/include/prov/providercommonerr.h @@ -67,6 +67,7 @@ int ERR_load_PROV_strings(void); # define PROV_R_INVALID_ITERATION_COUNT 123 # define PROV_R_INVALID_IVLEN 116 # define PROV_R_INVALID_IV_LENGTH 109 +# define PROV_R_INVALID_KEY 158 # define PROV_R_INVALID_KEYLEN 117 # define PROV_R_INVALID_KEY_LEN 124 # define PROV_R_INVALID_KEY_LENGTH 105 diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c index 589f37be70..2b7bac037d 100644 --- a/providers/common/provider_err.c +++ b/providers/common/provider_err.c @@ -42,6 +42,7 @@ static const ERR_STRING_DATA PROV_str_reasons[] = { "invalid iteration count"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IVLEN), "invalid ivlen"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IV_LENGTH), "invalid iv length"}, + {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY), "invalid key"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEYLEN), "invalid keylen"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LEN), "invalid key len"}, {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LENGTH), diff --git a/util/libcrypto.num b/util/libcrypto.num index c68eb9d8c9..58bf343e0b 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4854,3 +4854,11 @@ EVP_PKEY_key_fromdata_init ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_fromdata ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_param_fromdata_settable ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_key_fromdata_settable ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_free ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_up_ref ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_provider ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_fetch ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_is_a ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_number ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_do_all_provided ? 3_0_0 EXIST::FUNCTION: +EVP_ASYM_CIPHER_names_do_all ? 3_0_0 EXIST::FUNCTION: -- 2.39.5