From 13273237a65d46186b6bea0b51aec90670d4598a Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Tue, 9 Jul 2019 07:32:16 +0200 Subject: [PATCH] Adapt diverse EVP_CIPHER functions to use get_params and set_params interfaces Reviewed-by: Paul Dale Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/9328) --- crypto/evp/build.info | 2 +- crypto/evp/evp_enc.c | 77 ++++++++++++++-------------- crypto/evp/evp_lib.c | 112 ++++++++++++++++++++++------------------- crypto/evp/evp_locl.h | 37 ++++++++++++++ crypto/evp/evp_utils.c | 78 ++++++++++++++++++++++++++++ include/openssl/evp.h | 2 +- 6 files changed, 216 insertions(+), 92 deletions(-) create mode 100644 crypto/evp/evp_utils.c diff --git a/crypto/evp/build.info b/crypto/evp/build.info index 26be4d9342..fa49f2efbe 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -1,5 +1,5 @@ LIBS=../../libcrypto -$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c +$COMMON=digest.c evp_enc.c evp_lib.c evp_fetch.c cmeth_lib.c evp_utils.c SOURCE[../../libcrypto]=$COMMON\ encode.c evp_key.c evp_cnf.c \ e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\ diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index ebe7fa8fac..3b83d1173c 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -920,6 +920,14 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) { + int ok = evp_do_param(c->cipher, &keylen, sizeof(keylen), + OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_setparams, c->provctx); + + if (ok != -2) + return ok; + + /* TODO(3.0) legacy code follows */ if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH) return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, keylen, NULL); if (EVP_CIPHER_CTX_key_length(c) == keylen) @@ -934,40 +942,51 @@ int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) { + int ok; + if (pad) ctx->flags &= ~EVP_CIPH_NO_PADDING; else ctx->flags |= EVP_CIPH_NO_PADDING; - if (ctx->cipher != NULL && ctx->cipher->prov != NULL) { - OSSL_PARAM params[] = { - OSSL_PARAM_int(OSSL_CIPHER_PARAM_PADDING, NULL), - OSSL_PARAM_END - }; - - params[0].data = &pad; - - if (ctx->cipher->ctx_set_params == NULL) { - EVPerr(EVP_F_EVP_CIPHER_CTX_SET_PADDING, EVP_R_CTRL_NOT_IMPLEMENTED); - return 0; - } - - if (!ctx->cipher->ctx_set_params(ctx->provctx, params)) - return 0; - } - - return 1; + ok = evp_do_param(ctx->cipher, &pad, sizeof(pad), + OSSL_CIPHER_PARAM_PADDING, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_setparams, ctx->provctx); + return ok != 0; } int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) { - int ret; + int ret = -2; /* Unsupported */ if (!ctx->cipher) { EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET); return 0; } + if (ctx->cipher->prov == NULL) + goto legacy; + + switch (type) { + case EVP_CTRL_SET_KEY_LENGTH: + ret = evp_do_param(ctx->cipher, &arg, sizeof(arg), + OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_setparams, ctx->provctx); + break; + case EVP_CTRL_GET_IV: + ret = evp_do_param(ctx->cipher, ptr, arg, + OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_STRING, + evp_do_ciph_ctx_getparams, ctx->provctx); + break; + case EVP_CTRL_RAND_KEY: /* Used by DES */ + case EVP_CTRL_SET_PIPELINE_OUTPUT_BUFS: /* Used by DASYNC */ + case EVP_CTRL_INIT: /* TODO(3.0) Purely legacy, no provider counterpart */ + ret = -2; /* Unsupported */ + break; + } + return ret; + + legacy: if (!ctx->cipher->ctrl) { EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED); return 0; @@ -1123,21 +1142,6 @@ static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns, break; cipher->dupctx = OSSL_get_OP_cipher_dupctx(fns); break; - case OSSL_FUNC_CIPHER_KEY_LENGTH: - if (cipher->key_length != NULL) - break; - cipher->key_length = OSSL_get_OP_cipher_key_length(fns); - break; - case OSSL_FUNC_CIPHER_IV_LENGTH: - if (cipher->iv_length != NULL) - break; - cipher->iv_length = OSSL_get_OP_cipher_iv_length(fns); - break; - case OSSL_FUNC_CIPHER_BLOCK_SIZE: - if (cipher->blocksize != NULL) - break; - cipher->blocksize = OSSL_get_OP_cipher_block_size(fns); - break; case OSSL_FUNC_CIPHER_GET_PARAMS: if (cipher->get_params != NULL) break; @@ -1157,10 +1161,7 @@ static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns, } if ((fnciphcnt != 0 && fnciphcnt != 3 && fnciphcnt != 4) || (fnciphcnt == 0 && cipher->ccipher == NULL) - || fnctxcnt != 2 - || cipher->blocksize == NULL - || cipher->iv_length == NULL - || cipher->key_length == NULL) { + || fnctxcnt != 2) { /* * In order to be a consistent set of functions we must have at least * a complete set of "encrypt" functions, or a complete set of "decrypt" diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index 8ed39cb53e..9d1d197c2a 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -217,13 +217,12 @@ int EVP_CIPHER_type(const EVP_CIPHER *ctx) int EVP_CIPHER_block_size(const EVP_CIPHER *cipher) { - if (cipher->prov != NULL) { - if (cipher->blocksize != NULL) - return cipher->blocksize(); - /* We default to a block size of 1 */ - return 1; - } - return cipher->block_size; + int v = cipher->block_size; + int ok = evp_do_param(cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_BLOCK_SIZE, OSSL_PARAM_INTEGER, + evp_do_ciph_getparams, NULL); + + return ok != 0 ? v : -1; } int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) @@ -266,7 +265,12 @@ int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx) unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher) { - return cipher->flags; + unsigned long v = cipher->flags; + int ok = evp_do_param(cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_FLAGS, OSSL_PARAM_UNSIGNED_INTEGER, + evp_do_ciph_getparams, NULL); + + return ok != 0 ? v : 0; } void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx) @@ -296,13 +300,12 @@ void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data) int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) { - if (cipher->prov != NULL) { - if (cipher->iv_length != NULL) - return (int)cipher->iv_length(); - return 0; - } + int v = cipher->iv_len; + int ok = evp_do_param(cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_IVLEN, OSSL_PARAM_UNSIGNED_INTEGER, + evp_do_ciph_getparams, NULL); - return cipher->iv_len; + return ok != 0 ? v: -1; } int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) @@ -315,14 +318,27 @@ const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx) return ctx->oiv; } +/* + * OSSL_PARAM_OCTET_PTR gets us the pointer to the running IV in the provider + */ const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) { - return ctx->iv; + const unsigned char *v = ctx->iv; + int ok = evp_do_param(ctx->cipher, &v, sizeof(ctx->iv), + OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_PTR, + evp_do_ciph_ctx_getparams, ctx->provctx); + + return ok != 0 ? v: NULL; } unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) { - return ctx->iv; + unsigned char *v = ctx->iv; + int ok = evp_do_param(ctx->cipher, &v, sizeof(ctx->iv), + OSSL_CIPHER_PARAM_IV, OSSL_PARAM_OCTET_PTR, + evp_do_ciph_ctx_getparams, ctx->provctx); + + return ok != 0 ? v: NULL; } unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx) @@ -332,34 +348,42 @@ unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx) int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx) { - return ctx->num; + int v = ctx->num; + int ok = evp_do_param(ctx->cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_NUM, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_getparams, ctx->provctx); + + return ok != 0 ? v: -1; } -void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num) +int EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num) { + int ok = evp_do_param(ctx->cipher, &num, sizeof(num), + OSSL_CIPHER_PARAM_NUM, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_setparams, ctx->provctx); + ctx->num = num; + return ok != 0; } int EVP_CIPHER_key_length(const EVP_CIPHER *cipher) { - if (cipher->prov != NULL) { - if (cipher->key_length != NULL) - return (int)cipher->key_length(); - return -1; - } + int v = cipher->key_len; + int ok = evp_do_param(cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER, + evp_do_ciph_getparams, NULL); - return cipher->key_len; + return ok != 0 ? v: -1; } int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) { - /* - * TODO(3.0): This may need to change if/when we introduce variable length - * key ciphers into the providers. - */ - if (ctx->cipher != NULL && ctx->cipher->prov != NULL) - return EVP_CIPHER_key_length(ctx->cipher); - return ctx->key_len; + int v = ctx->key_len; + int ok = evp_do_param(ctx->cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_KEYLEN, OSSL_PARAM_INTEGER, + evp_do_ciph_ctx_getparams, ctx->provctx); + + return ok != 0 ? v: -1; } int EVP_CIPHER_nid(const EVP_CIPHER *cipher) @@ -374,28 +398,12 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) int EVP_CIPHER_mode(const EVP_CIPHER *cipher) { - if (cipher->prov != NULL) { - int mode; + int v = EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE; + int ok = evp_do_param(cipher, &v, sizeof(v), + OSSL_CIPHER_PARAM_MODE, OSSL_PARAM_INTEGER, + evp_do_ciph_getparams, NULL); - /* Cipher comes from a provider - so ask the provider for the mode */ - OSSL_PARAM params[] = { - OSSL_PARAM_int(OSSL_CIPHER_PARAM_MODE, NULL), - OSSL_PARAM_END - }; - - params[0].data = &mode; - - if (cipher->get_params == NULL) { - EVPerr(EVP_F_EVP_CIPHER_MODE, EVP_R_CTRL_NOT_IMPLEMENTED); - return 0; - } - - if (!cipher->get_params(params)) - return 0; - - return mode; - } - return EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE; + return ok != 0 ? v: 0; } diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index fdafe4f281..54f9e0814b 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -95,3 +95,40 @@ void *evp_generic_fetch(OPENSSL_CTX *ctx, int operation_id, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), void (*free_method)(void *)); + +/* Helper functions to avoid duplicating code */ + +/* + * The callbacks implement different ways to pass a params array to the + * provider. They will return one of these values: + * + * -2 if the method doesn't come from a provider + * (evp_do_param will return this to the called) + * -1 if the provider doesn't offer the desired function + * (evp_do_param will raise an error and return 0) + * or the return value from the desired function + * (evp_do_param will return it to the caller) + */ +int evp_do_ciph_getparams(const void *vciph, void *ignored, + OSSL_PARAM params[]); +int evp_do_ciph_ctx_getparams(const void *vciph, void *provctx, + OSSL_PARAM params[]); +int evp_do_ciph_ctx_setparams(const void *vciph, void *provctx, + OSSL_PARAM params[]); + +/*- + * prepares a singular parameter, then calls the callback to execute. + * + * |method| points to the method used by the callback. + * EVP_CIPHER, EVP_MD, ... + * |ptr| points at the data to transfer. + * |sz| is the size of the data to transfer. + * |key| is the name of the parameter to pass. + * |datatype| is the data type of the parameter to pass. + * |cb| is the callback that actually performs the parameter passing + * |cb_ctx| is the cipher context + */ +int evp_do_param(const void *method, void *ptr, size_t sz, const char *key, + int datatype, + int (*cb)(const void *method, void *ctx, OSSL_PARAM params[]), + void *cb_ctx); diff --git a/crypto/evp/evp_utils.c b/crypto/evp/evp_utils.c new file mode 100644 index 0000000000..48f548c7b6 --- /dev/null +++ b/crypto/evp/evp_utils.c @@ -0,0 +1,78 @@ +/* + * Copyright 2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* Internal EVP utility functions */ + +#include +#include +#include +#include /* evp_locl.h needs it */ +#include /* evp_locl.h needs it */ +#include "internal/evp_int.h" /* evp_locl.h needs it */ +#include "evp_locl.h" + +int evp_do_ciph_getparams(const void *vciph, void *ignored, + OSSL_PARAM params[]) +{ + const EVP_CIPHER *ciph = vciph; + + if (ciph->prov == NULL) + return -2; + if (ciph->get_params == NULL) + return -1; + return ciph->get_params(params); +} + +int evp_do_ciph_ctx_getparams(const void *vciph, void *provctx, + OSSL_PARAM params[]) +{ + const EVP_CIPHER *ciph = vciph; + + if (ciph->prov == NULL) + return -2; + if (ciph->ctx_get_params == NULL) + return -1; + return ciph->ctx_get_params(provctx, params); +} + +int evp_do_ciph_ctx_setparams(const void *vciph, void *provctx, + OSSL_PARAM params[]) +{ + const EVP_CIPHER *ciph = vciph; + + if (ciph->prov == NULL) + return -2; + if (ciph->ctx_set_params == NULL) + return -1; + return ciph->ctx_set_params(provctx, params); +} + +int evp_do_param(const void *method, void *ptr, size_t sz, const char *key, + int datatype, + int (*cb)(const void *method, void *ctx, OSSL_PARAM params[]), + void *cb_ctx) +{ + OSSL_PARAM params[2] = { + OSSL_PARAM_END, + OSSL_PARAM_END + }; + int ret; + + params[0].key = key; + params[0].data_type = datatype; + params[0].data = ptr; + params[0].data_size = sz; + + ret = cb(method, cb_ctx, params); + if (ret == -1) { + EVPerr(0, EVP_R_CTRL_NOT_IMPLEMENTED); + ret = 0; + } + return ret; +} diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2fb5fe2763..e781ebe212 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -490,7 +490,7 @@ const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx); unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); unsigned char *EVP_CIPHER_CTX_buf_noconst(EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_num(const EVP_CIPHER_CTX *ctx); -void EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num); +int EVP_CIPHER_CTX_set_num(EVP_CIPHER_CTX *ctx, int num); int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in); void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data); -- 2.25.1