0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-19 19:52:15 +02:00

Assume AEAD tag at the end of input if not given seperately

Signed-off-by: Arne Schwabe <arne@openvpn.net>
This commit is contained in:
Arne Schwabe 2024-07-12 00:51:12 +02:00 committed by Jenkins-dev
parent 880ebb081a
commit d52d98c7ec
2 changed files with 53 additions and 7 deletions

View File

@ -123,7 +123,20 @@ class CipherContextAEAD : public CipherContextCommon
OPENVPN_THROW(mbedtls_aead_error, "mbedtls_cipher_auth_encrypt failed with status=" << status); OPENVPN_THROW(mbedtls_aead_error, "mbedtls_cipher_auth_encrypt failed with status=" << status);
} }
// input and output may NOT be equal /**
* Decrypts AEAD encrypted data. Note that this method ignores the tag parameter
* and the tag is assumed to be part of input and at the end of the input.
*
* @param input Input data to decrypt
* @param output Where decrypted data will be written to
* @param iv IV of the encrypted data.
* @param length length the of the data, this includes the tag at the end.
* @param ad start of the additional data
* @param ad_len length of the additional data
* @param tag ignored by the mbed TLS variant of the method. (see OpenSSL variant of the method for more details).
*
* input and output may NOT be equal
*/
bool decrypt(const unsigned char *input, bool decrypt(const unsigned char *input,
unsigned char *output, unsigned char *output,
size_t length, size_t length,
@ -134,6 +147,12 @@ class CipherContextAEAD : public CipherContextCommon
{ {
check_initialized(); check_initialized();
if (unlikely(tag != nullptr))
{
/* If we are called with a non-null tag, the function is not going to be able to decrypt */
throw mbedtls_aead_error("tag must be null for aead decrypt");
}
size_t olen; size_t olen;
const int status = mbedtls_cipher_auth_decrypt_ext(&ctx, const int status = mbedtls_cipher_auth_decrypt_ext(&ctx,
iv, iv,

View File

@ -63,7 +63,7 @@ class CipherContextAEAD
}; };
// OpenSSL cipher constants // OpenSSL cipher constants
enum enum : size_t
{ {
IV_LEN = 12, IV_LEN = 12,
AUTH_TAG_LEN = 16 AUTH_TAG_LEN = 16
@ -172,16 +172,38 @@ class CipherContextAEAD
} }
} }
/**
* Decrypts AEAD encrypted data. Note that if tag is the nullptr the tag is assumed to be
* part of input and at the end of the input. The length parameter of input includes the tag in
* this case
*
* @param input Input data to decrypt
* @param output Where decrypted data will be written to
* @param iv IV of the encrypted data.
* @param length length the of the data, this includes the tag at the end if tag is not a nullptr.
* @param ad start of the additional data
* @param ad_len length of the additional data
* @param tag location of the tag to use or nullptr if at the end of the input
*/
bool decrypt(const unsigned char *input, bool decrypt(const unsigned char *input,
unsigned char *output, unsigned char *output,
size_t length, size_t length,
const unsigned char *iv, const unsigned char *iv,
unsigned char *tag, const unsigned char *tag,
const unsigned char *ad, const unsigned char *ad,
size_t ad_len) size_t ad_len)
{ {
int len; if (!tag)
int plaintext_len; {
/* Tag is at the end of input, check that input is large enough to hold the tag */
if (length < AUTH_TAG_LEN)
{
throw openssl_gcm_error("decrypt input length too short");
}
length = length - AUTH_TAG_LEN;
tag = input + length;
}
check_initialized(); check_initialized();
if (!EVP_DecryptInit_ex(ctx, nullptr, nullptr, nullptr, iv)) if (!EVP_DecryptInit_ex(ctx, nullptr, nullptr, nullptr, iv))
@ -189,6 +211,8 @@ class CipherContextAEAD
openssl_clear_error_stack(); openssl_clear_error_stack();
throw openssl_gcm_error("EVP_DecryptInit_ex (reset)"); throw openssl_gcm_error("EVP_DecryptInit_ex (reset)");
} }
int len;
if (!EVP_DecryptUpdate(ctx, nullptr, &len, ad, int(ad_len))) if (!EVP_DecryptUpdate(ctx, nullptr, &len, ad, int(ad_len)))
{ {
openssl_clear_error_stack(); openssl_clear_error_stack();
@ -199,8 +223,11 @@ class CipherContextAEAD
openssl_clear_error_stack(); openssl_clear_error_stack();
throw openssl_gcm_error("EVP_DecryptUpdate data"); throw openssl_gcm_error("EVP_DecryptUpdate data");
} }
plaintext_len = len;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AUTH_TAG_LEN, tag)) int plaintext_len = len;
/** This API of OpenSSL does not modify the tag it is given but the function signature always expects
* a modifiable tag, so we have to const cast it to get around this restriction */
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AUTH_TAG_LEN, const_cast<unsigned char *>(tag)))
{ {
openssl_clear_error_stack(); openssl_clear_error_stack();
throw openssl_gcm_error("EVP_CIPHER_CTX_ctrl set tag"); throw openssl_gcm_error("EVP_CIPHER_CTX_ctrl set tag");