diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index 39eb4f379a..55cc4423a7 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -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), diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index faf7bb4c0d..09e92624dc 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -412,7 +412,9 @@ The following Is are supported in CCM mode. This call is made to set the expected B tag value when decrypting or the length of the tag (with the C parameter set to NULL) when encrypting. The tag length is often referred to as B. 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). =item EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, ivlen, NULL) diff --git a/test/evp_test.c b/test/evp_test.c index 85c1552a7a..7a3e41c885 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -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; diff --git a/test/recipes/30-test_evp_data/evpciph.txt b/test/recipes/30-test_evp_data/evpciph.txt index f474e7482c..56f43567e1 100644 --- a/test/recipes/30-test_evp_data/evpciph.txt +++ b/test/recipes/30-test_evp_data/evpciph.txt @@ -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