From: Patrick Steuer Subject: fix old aes-gcm decrypt code path. Patch-mainline: v3.1.1 Git-commit: b95a9fd29fbdab9fd201c8f347bd4710d1811ada References: LTC#158531 Description: libica: AES-GCM/CCM sometimes compute wrong tag values Symptom: When the tag values of (unmodified) data are wrong, it is (wrongly) indicated that the data has been modified. Problem: With AES-GCM in-place decryption, the tag is computed from the plaintext. With AES-CCM in-place encryption, the tag is computed from the ciphertext. Solution: AES-GCM decryption always computes the tag from the ciphertext. AES-CCM encryption always computes the tag from the plaintext. Reproduction: When used with the ibmca 1.4 openssl engine (which enables libica's AES-GCM for libcrypto): (1) A SSH connection fails using an AES-GCM based cipher-suite, (2) A connection of openssl's s_client and s_server using an AES-GCM based cipher-suite fails. Upstream-Description: fix old aes-gcm decrypt code path. The old aes-gcm decrypt code was like pt<-dec(ct), tag<-mac(ct). So in case of "in-place" decryption (pt=ct), the tag was computed from the plaintext. Signed-off-by: Patrick Steuer Signed-off-by: Patrick Steuer --- src/include/s390_gcm.h | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) --- a/src/include/s390_gcm.h +++ b/src/include/s390_gcm.h @@ -321,8 +321,14 @@ static inline int s390_gcm(unsigned int memcpy(tmp_ctr, j0, AES_BLOCK_SIZE); __inc_aes_ctr((struct uint128 *)tmp_ctr, GCM_CTR_WIDTH); - /* en-/decrypt payload */ if (function_code % 2) { + /* mac */ + rc = s390_gcm_authenticate(ciphertext, text_length, + aad, aad_length, + subkey_h, tmp_tag); + if (rc) + return rc; + /* decrypt */ rc = s390_aes_ctr(UNDIRECTED_FC(function_code), ciphertext, plaintext, text_length, @@ -336,14 +342,14 @@ static inline int s390_gcm(unsigned int key, tmp_ctr, GCM_CTR_WIDTH); if (rc) return rc; - } - /* generate authentication tag */ - rc = s390_gcm_authenticate(ciphertext, text_length, - aad, aad_length, - subkey_h, tmp_tag); - if (rc) - return rc; + /* mac */ + rc = s390_gcm_authenticate(ciphertext, text_length, + aad, aad_length, + subkey_h, tmp_tag); + if (rc) + return rc; + } /* encrypt tag */ return s390_aes_ctr(UNDIRECTED_FC(function_code), @@ -393,8 +399,13 @@ static inline int s390_gcm_intermediate( if (!msa4_switch) return EPERM; - /* en-/decrypt payload */ if (function_code % 2) { + /* mac */ + rc = s390_gcm_authenticate_intermediate(ciphertext, text_length, aad, + aad_length, subkey, tag); + if (rc) + return rc; + /* decrypt */ rc = s390_aes_ctr(UNDIRECTED_FC(function_code), ciphertext, plaintext, text_length, key, ctr, GCM_CTR_WIDTH); @@ -406,13 +417,13 @@ static inline int s390_gcm_intermediate( text_length, key, ctr, GCM_CTR_WIDTH); if (rc) return rc; - } - /* generate authentication tag */ - rc = s390_gcm_authenticate_intermediate(ciphertext, text_length, aad, - aad_length, subkey, tag); - if (rc) - return rc; + /* mac */ + rc = s390_gcm_authenticate_intermediate(ciphertext, text_length, aad, + aad_length, subkey, tag); + if (rc) + return rc; + } return 0; }