Skip to content
Permalink
Browse files

Allow specifying the tag after AAD in CCM mode

This change allows to pass the authentication tag after specifying
the AAD in CCM mode. This is already true for the other two supported
AEAD modes (GCM and OCB) and it seems appropriate to match the
behavior.

GCM and OCB also support to set the tag at any point before the call
to `EVP_*Final`, but this won't work for CCM due to a restriction
imposed by section 2.6 of RFC3610: The tag must be set before
actually decrypting data.

This commit also adds a test case for setting the tag after supplying
plaintext length and AAD.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from #7243)

(cherry picked from commit 67c81ec)
  • Loading branch information...
tniessen authored and mattcaswell committed Sep 14, 2018
1 parent 8f50627 commit b48e3be947ddc5da6b5a86db8341081c72b9a4ee
Showing with 39 additions and 12 deletions.
  1. +5 −2 crypto/evp/e_aes.c
  2. +3 −1 doc/man3/EVP_EncryptInit.pod
  3. +20 −9 test/evp_test.c
  4. +11 −0 test/recipes/30-test_evp_data/evpciph.txt
@@ -3643,8 +3643,6 @@ static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
if (!cctx->iv_set)
return -1;

if (!EVP_CIPHER_CTX_encrypting(ctx) && !cctx->tag_set)
return -1;
if (!out) {
if (!in) {
if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx),
@@ -3659,6 +3657,11 @@ static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
CRYPTO_ccm128_aad(ccm, in, len);
return len;
}

/* The tag must be set before actually decrypting data */
if (!EVP_CIPHER_CTX_encrypting(ctx) && !cctx->tag_set)
return -1;

/* If not set length yet do it */
if (!cctx->len_set) {
if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx),
@@ -412,7 +412,9 @@ The following I<ctrl>s are supported in CCM mode.
This call is made to set the expected B<CCM> tag value when decrypting or
the length of the tag (with the C<tag> parameter set to NULL) when encrypting.
The tag length is often referred to as B<M>. If not set a default value is
used (12 for AES).
used (12 for AES). When decrypting, the tag needs to be set before passing
in data to be decrypted, but as in GCM and OCB mode, it can be set after
passing additional authenticated data (see L<AEAD Interface>).

=item EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, ivlen, NULL)

@@ -462,6 +462,7 @@ typedef struct cipher_data_st {
size_t aad_len;
unsigned char *tag;
size_t tag_len;
int tag_late;
} CIPHER_DATA;

static int cipher_test_init(EVP_TEST *t, const char *alg)
@@ -525,6 +526,15 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
return parse_bin(value, &cdat->aad, &cdat->aad_len);
if (strcmp(keyword, "Tag") == 0)
return parse_bin(value, &cdat->tag, &cdat->tag_len);
if (strcmp(keyword, "SetTagLate") == 0) {
if (strcmp(value, "TRUE") == 0)
cdat->tag_late = 1;
else if (strcmp(value, "FALSE") == 0)
cdat->tag_late = 0;
else
return 0;
return 1;
}
}

if (strcmp(keyword, "Operation") == 0) {
@@ -610,7 +620,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
* If encrypting or OCB just set tag length initially, otherwise
* set tag length and value.
*/
if (enc || expected->aead == EVP_CIPH_OCB_MODE) {
if (enc || expected->aead == EVP_CIPH_OCB_MODE || expected->tag_late) {
t->err = "TAG_LENGTH_SET_ERROR";
tag = NULL;
} else {
@@ -633,14 +643,6 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
goto err;
}

if (!enc && expected->aead == EVP_CIPH_OCB_MODE) {
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
expected->tag_len, expected->tag)) {
t->err = "TAG_SET_ERROR";
goto err;
}
}

if (expected->aead == EVP_CIPH_CCM_MODE) {
if (!EVP_CipherUpdate(ctx, NULL, &tmplen, NULL, out_len)) {
t->err = "CCM_PLAINTEXT_LENGTH_SET_ERROR";
@@ -675,6 +677,15 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
goto err;
}
}

if (!enc && (expected->aead == EVP_CIPH_OCB_MODE || expected->tag_late)) {
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
expected->tag_len, expected->tag)) {
t->err = "TAG_SET_ERROR";
goto err;
}
}

EVP_CIPHER_CTX_set_padding(ctx, 0);
t->err = "CIPHERUPDATE_ERROR";
tmplen = 0;
@@ -733,6 +733,17 @@ Ciphertext = 9a5fcccdb4cf04e7293d2775cc76a488f042382d949b43b7d6bb2b9864786726
Operation = DECRYPT
Result = CIPHERUPDATE_ERROR

# Test that the tag can be set after specifying AAD.
Cipher = aes-256-ccm
Key = 1bde3251d41a8b5ea013c195ae128b218b3e0306376357077ef1c1c78548b92e
IV = 5b8e40746f6b98e00f1d13ff41
AAD = c17a32514eb6103f3249e076d4c871dc97e04b286699e54491dc18f6d734d4c0
Tag = 2024931d73bca480c24a24ece6b6c2bf
SetTagLate = TRUE
Operation = DECRYPT
Plaintext = 53bd72a97089e312422bf72e242377b3c6ee3e2075389b999c4ef7f28bd2b80a
Ciphertext = 9a5fcccdb4cf04e7293d2775cc76a488f042382d949b43b7d6bb2b9864786726

# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
Cipher = aes-128-gcm
Key = 00000000000000000000000000000000

0 comments on commit b48e3be

Please sign in to comment.
You can’t perform that action at this time.