Skip to content

Commit b48e3be

Browse files
tniessenmattcaswell
authored andcommitted
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 <[email protected]> Reviewed-by: Matt Caswell <[email protected]> (Merged from #7243) (cherry picked from commit 67c81ec)
1 parent 8f50627 commit b48e3be

File tree

4 files changed

+39
-12
lines changed

4 files changed

+39
-12
lines changed

crypto/evp/e_aes.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,8 +3643,6 @@ static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
36433643
if (!cctx->iv_set)
36443644
return -1;
36453645

3646-
if (!EVP_CIPHER_CTX_encrypting(ctx) && !cctx->tag_set)
3647-
return -1;
36483646
if (!out) {
36493647
if (!in) {
36503648
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,
36593657
CRYPTO_ccm128_aad(ccm, in, len);
36603658
return len;
36613659
}
3660+
3661+
/* The tag must be set before actually decrypting data */
3662+
if (!EVP_CIPHER_CTX_encrypting(ctx) && !cctx->tag_set)
3663+
return -1;
3664+
36623665
/* If not set length yet do it */
36633666
if (!cctx->len_set) {
36643667
if (CRYPTO_ccm128_setiv(ccm, EVP_CIPHER_CTX_iv_noconst(ctx),

doc/man3/EVP_EncryptInit.pod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,9 @@ The following I<ctrl>s are supported in CCM mode.
412412
This call is made to set the expected B<CCM> tag value when decrypting or
413413
the length of the tag (with the C<tag> parameter set to NULL) when encrypting.
414414
The tag length is often referred to as B<M>. If not set a default value is
415-
used (12 for AES).
415+
used (12 for AES). When decrypting, the tag needs to be set before passing
416+
in data to be decrypted, but as in GCM and OCB mode, it can be set after
417+
passing additional authenticated data (see L<AEAD Interface>).
416418

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

test/evp_test.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ typedef struct cipher_data_st {
462462
size_t aad_len;
463463
unsigned char *tag;
464464
size_t tag_len;
465+
int tag_late;
465466
} CIPHER_DATA;
466467

467468
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,
525526
return parse_bin(value, &cdat->aad, &cdat->aad_len);
526527
if (strcmp(keyword, "Tag") == 0)
527528
return parse_bin(value, &cdat->tag, &cdat->tag_len);
529+
if (strcmp(keyword, "SetTagLate") == 0) {
530+
if (strcmp(value, "TRUE") == 0)
531+
cdat->tag_late = 1;
532+
else if (strcmp(value, "FALSE") == 0)
533+
cdat->tag_late = 0;
534+
else
535+
return 0;
536+
return 1;
537+
}
528538
}
529539

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

636-
if (!enc && expected->aead == EVP_CIPH_OCB_MODE) {
637-
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
638-
expected->tag_len, expected->tag)) {
639-
t->err = "TAG_SET_ERROR";
640-
goto err;
641-
}
642-
}
643-
644646
if (expected->aead == EVP_CIPH_CCM_MODE) {
645647
if (!EVP_CipherUpdate(ctx, NULL, &tmplen, NULL, out_len)) {
646648
t->err = "CCM_PLAINTEXT_LENGTH_SET_ERROR";
@@ -675,6 +677,15 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
675677
goto err;
676678
}
677679
}
680+
681+
if (!enc && (expected->aead == EVP_CIPH_OCB_MODE || expected->tag_late)) {
682+
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
683+
expected->tag_len, expected->tag)) {
684+
t->err = "TAG_SET_ERROR";
685+
goto err;
686+
}
687+
}
688+
678689
EVP_CIPHER_CTX_set_padding(ctx, 0);
679690
t->err = "CIPHERUPDATE_ERROR";
680691
tmplen = 0;

test/recipes/30-test_evp_data/evpciph.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,17 @@ Ciphertext = 9a5fcccdb4cf04e7293d2775cc76a488f042382d949b43b7d6bb2b9864786726
733733
Operation = DECRYPT
734734
Result = CIPHERUPDATE_ERROR
735735

736+
# Test that the tag can be set after specifying AAD.
737+
Cipher = aes-256-ccm
738+
Key = 1bde3251d41a8b5ea013c195ae128b218b3e0306376357077ef1c1c78548b92e
739+
IV = 5b8e40746f6b98e00f1d13ff41
740+
AAD = c17a32514eb6103f3249e076d4c871dc97e04b286699e54491dc18f6d734d4c0
741+
Tag = 2024931d73bca480c24a24ece6b6c2bf
742+
SetTagLate = TRUE
743+
Operation = DECRYPT
744+
Plaintext = 53bd72a97089e312422bf72e242377b3c6ee3e2075389b999c4ef7f28bd2b80a
745+
Ciphertext = 9a5fcccdb4cf04e7293d2775cc76a488f042382d949b43b7d6bb2b9864786726
746+
736747
# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
737748
Cipher = aes-128-gcm
738749
Key = 00000000000000000000000000000000

0 commit comments

Comments
 (0)