From dc64dc2edd215d6cc5843c1bfe1f0b64bff26adc Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Wed, 11 Sep 2019 17:52:30 +1000 Subject: [PATCH] Add EVP_CIPHER_CTX_tag_length() There is no deprecated CTRL support for this new field. Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/9698) --- crypto/evp/evp_lib.c | 11 +++++++++++ crypto/evp/evp_utils.c | 2 ++ doc/man3/EVP_EncryptInit.pod | 9 +++++++++ doc/man7/provider-cipher.pod | 5 +++++ include/openssl/core_names.h | 3 ++- include/openssl/evp.h | 1 + providers/common/ciphers/cipher_ccm.c | 14 ++++++++++++-- providers/common/ciphers/cipher_common.c | 1 + providers/common/ciphers/cipher_gcm.c | 11 +++++++++++ .../common/include/internal/ciphers/cipher_ccm.h | 2 +- test/aesgcmtest.c | 2 ++ test/evp_extra_test.c | 3 +++ util/libcrypto.num | 1 + 13 files changed, 61 insertions(+), 4 deletions(-) diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index 9c3edb3322..5be04b0502 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -336,6 +336,17 @@ legacy: return v; } +int EVP_CIPHER_CTX_tag_length(const EVP_CIPHER_CTX *ctx) +{ + int ret; + size_t v = 0; + OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, &v); + ret = evp_do_ciph_ctx_getparams(ctx->cipher, ctx->provctx, params); + return ret == 1 ? (int)v : 0; +} + const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx) { return ctx->oiv; diff --git a/crypto/evp/evp_utils.c b/crypto/evp/evp_utils.c index e5cd5b84e1..3da208a69f 100644 --- a/crypto/evp/evp_utils.c +++ b/crypto/evp/evp_utils.c @@ -25,6 +25,8 @@ * use the same value, and other callers will have to compensate. */ #define PARAM_CHECK(obj, func, errfunc) \ + if (obj == NULL) \ + return 0; \ if (obj->prov == NULL) \ return EVP_CTRL_RET_UNSUPPORTED; \ if (obj->func == NULL) { \ diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index 11d0250a0d..78f67bd643 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -49,6 +49,7 @@ EVP_CIPHER_CTX_settable_params, EVP_CIPHER_CTX_block_size, EVP_CIPHER_CTX_key_length, EVP_CIPHER_CTX_iv_length, +EVP_CIPHER_CTX_tag_length, EVP_CIPHER_CTX_get_app_data, EVP_CIPHER_CTX_set_app_data, EVP_CIPHER_CTX_type, @@ -137,6 +138,7 @@ EVP_CIPHER_do_all_ex int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); + int EVP_CIPHER_CTX_tag_length(const EVP_CIPHER_CTX *ctx); void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); void EVP_CIPHER_CTX_set_app_data(const EVP_CIPHER_CTX *ctx, void *data); int EVP_CIPHER_CTX_type(const EVP_CIPHER_CTX *ctx); @@ -297,6 +299,10 @@ length of a cipher when passed an B or B. It will return zero if the cipher does not use an IV. The constant B is the maximum IV length for all ciphers. +EVP_CIPHER_CTX_tag_length() returns the tag length of a AEAD cipher when passed +a B. It will return zero if the cipher does not support a tag. +It returns a default value if the tag length has not been set. + EVP_CIPHER_block_size() and EVP_CIPHER_CTX_block_size() return the block size of a cipher when passed an B or B structure. The constant B is also the maximum block @@ -395,6 +401,9 @@ EVP_CIPHER_CTX_set_padding() always returns 1. EVP_CIPHER_iv_length() and EVP_CIPHER_CTX_iv_length() return the IV length or zero if the cipher does not use an IV. +EVP_CIPHER_CTX_tag_length() return the tag length or zero if the cipher does not +use a tag. + EVP_CIPHER_type() and EVP_CIPHER_CTX_type() return the NID of the cipher's OBJECT IDENTIFIER or NID_undef if it has no defined OBJECT IDENTIFIER. diff --git a/doc/man7/provider-cipher.pod b/doc/man7/provider-cipher.pod index 1b7dff8f76..d5d2f13390 100644 --- a/doc/man7/provider-cipher.pod +++ b/doc/man7/provider-cipher.pod @@ -248,6 +248,11 @@ block has been "used" already. Gets or sets the AEAD tag for the associated cipher ctx. See L. +=item B (size_t) + +Gets the tag length to be used for an AEAD cipher for the associated cipher ctx. +It returns a default value if it has not been set. + =item B (octet_string) =for comment TODO(3.0): Consider changing this interface so that all ciphers diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index b11bc614a8..e1bc43d8db 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -63,7 +63,8 @@ extern "C" { #define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD "tlsaad" /* octet_string */ #define OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD "tlsaadpad" /* size_t */ #define OSSL_CIPHER_PARAM_AEAD_TLS1_IV_FIXED "tlsivfixed" /* octet_string */ -#define OSSL_CIPHER_PARAM_AEAD_IVLEN OSSL_CIPHER_PARAM_IVLEN +#define OSSL_CIPHER_PARAM_AEAD_IVLEN OSSL_CIPHER_PARAM_IVLEN +#define OSSL_CIPHER_PARAM_AEAD_TAGLEN "taglen" /* size_t */ #define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */ /* digest parameters */ diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 69d70e5e9c..2eb6802d3e 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -493,6 +493,7 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); +int EVP_CIPHER_CTX_tag_length(const EVP_CIPHER_CTX *ctx); const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); const unsigned char *EVP_CIPHER_CTX_original_iv(const EVP_CIPHER_CTX *ctx); unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); diff --git a/providers/common/ciphers/cipher_ccm.c b/providers/common/ciphers/cipher_ccm.c index 8970b02670..9c58dfeafa 100644 --- a/providers/common/ciphers/cipher_ccm.c +++ b/providers/common/ciphers/cipher_ccm.c @@ -148,6 +148,16 @@ int ccm_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 0; } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL) { + size_t m = ctx->m; + + if (!OSSL_PARAM_set_size_t(p, m)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); if (p != NULL) { if (ccm_get_ivlen(ctx) != p->data_size) { @@ -346,7 +356,7 @@ static int ccm_cipher_internal(PROV_CCM_CTX *ctx, unsigned char *out, if (!ctx->key_set) return 0; - if (ctx->tls_aad_len >= 0) + if (ctx->tls_aad_len != UNINITIALISED_SIZET) return ccm_tls_cipher(ctx, out, padlen, in, len); /* EVP_*Final() doesn't return any data */ @@ -406,7 +416,7 @@ void ccm_initctx(PROV_CCM_CTX *ctx, size_t keybits, const PROV_CCM_HW *hw) ctx->len_set = 0; ctx->l = 8; ctx->m = 12; - ctx->tls_aad_len = -1; + ctx->tls_aad_len = UNINITIALISED_SIZET; ctx->hw = hw; } diff --git a/providers/common/ciphers/cipher_common.c b/providers/common/ciphers/cipher_common.c index de67fc1341..18d6dd9ca5 100644 --- a/providers/common/ciphers/cipher_common.c +++ b/providers/common/ciphers/cipher_common.c @@ -85,6 +85,7 @@ const OSSL_PARAM *cipher_generic_settable_ctx_params(void) static const OSSL_PARAM cipher_aead_known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TLS1_AAD_PAD, NULL), diff --git a/providers/common/ciphers/cipher_gcm.c b/providers/common/ciphers/cipher_gcm.c index 4247319091..9a61eabdfc 100644 --- a/providers/common/ciphers/cipher_gcm.c +++ b/providers/common/ciphers/cipher_gcm.c @@ -98,6 +98,16 @@ int gcm_get_ctx_params(void *vctx, OSSL_PARAM params[]) ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return 0; } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p != NULL) { + size_t taglen = (ctx->taglen != UNINITIALISED_SIZET) ? ctx->taglen : + GCM_TAG_MAX_SIZE; + + if (!OSSL_PARAM_set_size_t(p, taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + } p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); if (p != NULL) { @@ -133,6 +143,7 @@ int gcm_get_ctx_params(void *vctx, OSSL_PARAM params[]) return 0; } } + return 1; } diff --git a/providers/common/include/internal/ciphers/cipher_ccm.h b/providers/common/include/internal/ciphers/cipher_ccm.h index 08a2d46858..757c22eb53 100644 --- a/providers/common/include/internal/ciphers/cipher_ccm.h +++ b/providers/common/include/internal/ciphers/cipher_ccm.h @@ -35,7 +35,7 @@ typedef struct prov_ccm_st { unsigned int len_set : 1; /* Set if message length set */ size_t l, m; /* L and M parameters from RFC3610 */ size_t keylen; - int tls_aad_len; /* TLS AAD length */ + size_t tls_aad_len; /* TLS AAD length */ size_t tls_aad_pad_sz; unsigned char iv[AES_BLOCK_SIZE]; unsigned char buf[AES_BLOCK_SIZE]; diff --git a/test/aesgcmtest.c b/test/aesgcmtest.c index a13e9b856c..4a255d502c 100644 --- a/test/aesgcmtest.c +++ b/test/aesgcmtest.c @@ -54,6 +54,7 @@ static int do_encrypt(unsigned char *iv_gen, unsigned char *ct, int *ct_len, && TEST_true(EVP_EncryptUpdate(ctx, ct, ct_len, gcm_pt, sizeof(gcm_pt)) > 0) && TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &outlen) > 0) + && TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 16) && TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tag) > 0) && TEST_true(iv_gen == NULL @@ -75,6 +76,7 @@ static int do_decrypt(const unsigned char *iv, const unsigned char *ct, && TEST_true(EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) > 0) && TEST_true(EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_key, iv) > 0) + && TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 16) && TEST_true(EVP_DecryptUpdate(ctx, NULL, &outlen, gcm_aad, sizeof(gcm_aad)) > 0) && TEST_true(EVP_DecryptUpdate(ctx, pt, &ptlen, ct, diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 7b7c632dd1..631ad65540 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -1241,10 +1241,13 @@ static int encrypt_decrypt(const EVP_CIPHER *cipher, const unsigned char *msg, memset(key, 0, sizeof(key)); if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0) || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 1)) + || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0) || !TEST_true(EVP_CipherUpdate(ctx, ct, &ctlen, msg, len)) || !TEST_true(EVP_CipherFinal_ex(ctx, ct, &ctlen)) || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 0)) + || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0) || !TEST_true(EVP_CipherUpdate(ctx, pt, &ptlen, ct, ctlen)) || !TEST_true(EVP_CipherFinal_ex(ctx, pt, &ptlen)) || !TEST_mem_eq(pt, ptlen, msg, len)) diff --git a/util/libcrypto.num b/util/libcrypto.num index e5c869af44..07469a1f26 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4752,3 +4752,4 @@ EVP_PKEY_CTX_get_signature_md 4868 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_get_params 4869 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_gettable_params 4870 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_settable_params 4871 3_0_0 EXIST::FUNCTION: +EVP_CIPHER_CTX_tag_length 4872 3_0_0 EXIST::FUNCTION: -- 2.34.1