diff options
23 files changed, 65 insertions, 39 deletions
diff --git a/doc/manual/cipher_modes.rst b/doc/manual/cipher_modes.rst index cc04a3750..6e78a2c1b 100644 --- a/doc/manual/cipher_modes.rst +++ b/doc/manual/cipher_modes.rst @@ -269,10 +269,19 @@ will be returned by :cpp:func:`get_cipher` if the named cipher is an AEAD mode). ever calling update is both efficient and convenient. .. note:: - During decryption, finish will throw an instance of Integrity_Failure - if the MAC does not validate. If this occurs, all plaintext previously - output via calls to update must be destroyed and not used in any - way that an attacker could observe the effects of. + + During decryption, if the supplied authentication tag does not + validate, finish will throw an instance of Invalid_Authentication_Tag + (aka Integrity_Failure, which was the name for this exception in + versions before 2.10, a typedef is included for compatability). + + If this occurs, all plaintext previously output via calls to update + must be destroyed and not used in any way that an attacker could + observe the effects of. This could be anything from echoing the + plaintext back (perhaps in an error message), or by making an external + RPC whose destination or contents depend on the plaintext. The only + thing you can do is buffer it, and in the event of an invalid tag, + erase the previously decrypted content from memory. One simply way to assure this could never happen is to never call update, and instead always marshal the entire message diff --git a/doc/manual/keywrap.rst b/doc/manual/keywrap.rst index 3116797e5..5c3aac0a3 100644 --- a/doc/manual/keywrap.rst +++ b/doc/manual/keywrap.rst @@ -23,7 +23,7 @@ functions with AES, but any 128-bit cipher will do and some other implementation .. cpp:function:: secure_vector<uint8_t> nist_key_unwrap(const uint8_t input[], \ size_t input_len, const BlockCipher& bc) - This unwraps the result of nist_key_wrap, or throw Integrity_Failure on error. + This unwraps the result of nist_key_wrap, or throw Invalid_Authentication_Tag on error. .. cpp:function:: std::vector<uint8_t> nist_key_wrap_padded(const uint8_t input[], \ size_t input_len, const BlockCipher& bc) @@ -33,7 +33,7 @@ functions with AES, but any 128-bit cipher will do and some other implementation .. cpp:function:: secure_vector<uint8_t> nist_key_unwrap_padded(const uint8_t input[], \ size_t input_len, const BlockCipher& bc) - This unwraps the result of nist_key_wrap_padded, or throws Integrity_Failure + This unwraps the result of nist_key_wrap_padded, or throws Invalid_Authentication_Tag on error. RFC 3394 Interface diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index b0c1f6e71..4fe1d8c71 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -62,6 +62,9 @@ int ffi_map_error_type(Botan::ErrorType err) case Botan::ErrorType::DecodingFailure: return BOTAN_FFI_ERROR_INVALID_INPUT; + case Botan::ErrorType::InvalidTag: + return BOTAN_FFI_ERROR_BAD_MAC; + case Botan::ErrorType::InvalidKeyLength: return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH; case Botan::ErrorType::LookupError: diff --git a/src/lib/ffi/ffi_cipher.cpp b/src/lib/ffi/ffi_cipher.cpp index dc340ea61..3c74a524f 100644 --- a/src/lib/ffi/ffi_cipher.cpp +++ b/src/lib/ffi/ffi_cipher.cpp @@ -128,7 +128,7 @@ int botan_cipher_update(botan_cipher_t cipher_obj, { cipher.finish(mbuf); } - catch(Integrity_Failure&) + catch(Invalid_Authentication_Tag&) { return BOTAN_FFI_ERROR_BAD_MAC; } diff --git a/src/lib/misc/nist_keywrap/nist_keywrap.cpp b/src/lib/misc/nist_keywrap/nist_keywrap.cpp index 3c673696d..671d31ea4 100644 --- a/src/lib/misc/nist_keywrap/nist_keywrap.cpp +++ b/src/lib/misc/nist_keywrap/nist_keywrap.cpp @@ -125,7 +125,7 @@ nist_key_unwrap(const uint8_t input[], secure_vector<uint8_t> R = raw_nist_key_unwrap(input, input_len, bc, ICV_out); if(ICV_out != 0xA6A6A6A6A6A6A6A6) - throw Integrity_Failure("NIST key unwrap failed"); + throw Invalid_Authentication_Tag("NIST key unwrap failed"); return R; } @@ -186,19 +186,19 @@ nist_key_unwrap_padded(const uint8_t input[], } if((ICV_out >> 32) != 0xA65959A6) - throw Integrity_Failure("NIST key unwrap failed"); + throw Invalid_Authentication_Tag("NIST key unwrap failed"); const size_t len = (ICV_out & 0xFFFFFFFF); if(R.size() < 8 || len > R.size() || len < R.size() - 8) - throw Integrity_Failure("NIST key unwrap failed"); + throw Invalid_Authentication_Tag("NIST key unwrap failed"); const size_t padding = R.size() - len; for(size_t i = 0; i != padding; ++i) { if(R[R.size() - i - 1] != 0) - throw Integrity_Failure("NIST key unwrap failed"); + throw Invalid_Authentication_Tag("NIST key unwrap failed"); } R.resize(R.size() - padding); diff --git a/src/lib/modes/aead/ccm/ccm.cpp b/src/lib/modes/aead/ccm/ccm.cpp index f630dc39a..effe3a1ff 100644 --- a/src/lib/modes/aead/ccm/ccm.cpp +++ b/src/lib/modes/aead/ccm/ccm.cpp @@ -263,7 +263,7 @@ void CCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) T ^= S0; if(!constant_time_compare(T.data(), buf_end, tag_size())) - throw Integrity_Failure("CCM tag check failed"); + throw Invalid_Authentication_Tag("CCM tag check failed"); buffer.resize(buffer.size() - tag_size()); } diff --git a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp index 8e424ce49..ca0c55184 100644 --- a/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp +++ b/src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp @@ -160,7 +160,7 @@ void ChaCha20Poly1305_Decryption::finish(secure_vector<uint8_t>& buffer, size_t m_nonce_len = 0; if(!constant_time_compare(mac.data(), included_tag, tag_size())) - throw Integrity_Failure("ChaCha20Poly1305 tag check failed"); + throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed"); buffer.resize(offset + remaining); } diff --git a/src/lib/modes/aead/eax/eax.cpp b/src/lib/modes/aead/eax/eax.cpp index 00253e405..1a31c3cff 100644 --- a/src/lib/modes/aead/eax/eax.cpp +++ b/src/lib/modes/aead/eax/eax.cpp @@ -184,7 +184,7 @@ void EAX_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) mac ^= m_ad_mac; if(!constant_time_compare(mac.data(), included_tag, tag_size())) - throw Integrity_Failure("EAX tag check failed"); + throw Invalid_Authentication_Tag("EAX tag check failed"); buffer.resize(offset + remaining); diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp index 75768d851..d299af35f 100644 --- a/src/lib/modes/aead/gcm/gcm.cpp +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -166,7 +166,7 @@ void GCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) const uint8_t* included_tag = &buffer[remaining+offset]; if(!constant_time_compare(mac.data(), included_tag, tag_size())) - throw Integrity_Failure("GCM tag check failed"); + throw Invalid_Authentication_Tag("GCM tag check failed"); buffer.resize(offset + remaining); } diff --git a/src/lib/modes/aead/ocb/ocb.cpp b/src/lib/modes/aead/ocb/ocb.cpp index b25abbe6a..87361ef11 100644 --- a/src/lib/modes/aead/ocb/ocb.cpp +++ b/src/lib/modes/aead/ocb/ocb.cpp @@ -523,7 +523,7 @@ void OCB_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) const uint8_t* included_tag = &buf[remaining]; if(!constant_time_compare(mac.data(), included_tag, tag_size())) - throw Integrity_Failure("OCB tag check failed"); + throw Invalid_Authentication_Tag("OCB tag check failed"); // remove tag from end of message buffer.resize(remaining + offset); diff --git a/src/lib/modes/aead/siv/siv.cpp b/src/lib/modes/aead/siv/siv.cpp index 3a960e0af..75bdb91c4 100644 --- a/src/lib/modes/aead/siv/siv.cpp +++ b/src/lib/modes/aead/siv/siv.cpp @@ -198,7 +198,7 @@ void SIV_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) const secure_vector<uint8_t> T = S2V(buffer.data() + offset, buffer.size() - offset - V.size()); if(!constant_time_compare(T.data(), V.data(), T.size())) - throw Integrity_Failure("SIV tag check failed"); + throw Invalid_Authentication_Tag("SIV tag check failed"); buffer.resize(buffer.size() - tag_size()); } diff --git a/src/lib/psk_db/psk_db.cpp b/src/lib/psk_db/psk_db.cpp index 4851f6bd2..59fa76893 100644 --- a/src/lib/psk_db/psk_db.cpp +++ b/src/lib/psk_db/psk_db.cpp @@ -45,7 +45,7 @@ std::set<std::string> Encrypted_PSK_Database::list_names() const std::string pt_name(cast_uint8_ptr_to_char(name_bits.data()), name_bits.size()); names.insert(pt_name); } - catch(Integrity_Failure&) + catch(Invalid_Authentication_Tag&) { } } diff --git a/src/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp index aa214fd8b..d24542d0e 100644 --- a/src/lib/pubkey/dlies/dlies.cpp +++ b/src/lib/pubkey/dlies/dlies.cpp @@ -192,7 +192,7 @@ secure_vector<uint8_t> DLIES_Decryptor::do_decrypt(uint8_t& valid_mask, try { // the decryption can fail: - // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag + // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag if(m_iv.size()) { diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp index 54055de7a..fb12eaa49 100644 --- a/src/lib/pubkey/ecies/ecies.cpp +++ b/src/lib/pubkey/ecies/ecies.cpp @@ -399,7 +399,7 @@ secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const ui try { // the decryption can fail: - // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag + // e.g. Invalid_Authentication_Tag is thrown if GCM is used and the message does not have a valid tag secure_vector<uint8_t> decrypted_data(encrypted_data.begin(), encrypted_data.end()); m_cipher->finish(decrypted_data); return decrypted_data; diff --git a/src/lib/pubkey/mceies/mceies.cpp b/src/lib/pubkey/mceies/mceies.cpp index 3f8562e17..4d62889fe 100644 --- a/src/lib/pubkey/mceies/mceies.cpp +++ b/src/lib/pubkey/mceies/mceies.cpp @@ -97,7 +97,7 @@ mceies_decrypt(const McEliece_PrivateKey& privkey, aead->finish(pt, 0); return pt; } - catch(Integrity_Failure&) + catch(Invalid_Authentication_Tag&) { throw; } diff --git a/src/lib/pubkey/xmss/xmss_privatekey.cpp b/src/lib/pubkey/xmss/xmss_privatekey.cpp index 05d61981e..9ef2b5c9c 100644 --- a/src/lib/pubkey/xmss/xmss_privatekey.cpp +++ b/src/lib/pubkey/xmss/xmss_privatekey.cpp @@ -37,7 +37,7 @@ XMSS_PrivateKey::XMSS_PrivateKey(const secure_vector<uint8_t>& raw_key) if(raw_key.size() != size()) { - throw Integrity_Failure("Invalid XMSS private key size detected."); + throw Decoding_Error("Invalid XMSS private key size detected."); } // extract & copy unused leaf index from raw_key. @@ -52,8 +52,7 @@ XMSS_PrivateKey::XMSS_PrivateKey(const secure_vector<uint8_t>& raw_key) if(unused_leaf >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { - throw Integrity_Failure("XMSS private key leaf index out of " - "bounds."); + throw Decoding_Error("XMSS private key leaf index out of bounds"); } begin = end; diff --git a/src/lib/pubkey/xmss/xmss_privatekey.h b/src/lib/pubkey/xmss/xmss_privatekey.h index d66933724..e3b41617c 100644 --- a/src/lib/pubkey/xmss/xmss_privatekey.h +++ b/src/lib/pubkey/xmss/xmss_privatekey.h @@ -115,8 +115,7 @@ class BOTAN_PUBLIC_API(2,0) XMSS_PrivateKey final : public virtual XMSS_PublicKe { if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { - throw Integrity_Failure("XMSS private key leaf index out of " - "bounds."); + throw Decoding_Error("XMSS private key leaf index out of bounds"); } else { @@ -140,8 +139,7 @@ class BOTAN_PUBLIC_API(2,0) XMSS_PrivateKey final : public virtual XMSS_PublicKe *recover_global_leaf_index())).fetch_add(1); if(idx >= (1ull << XMSS_PublicKey::m_xmss_params.tree_height())) { - throw Integrity_Failure("XMSS private key, one time signatures " - "exhausted."); + throw Decoding_Error("XMSS private key, one time signatures exhaused"); } return idx; } diff --git a/src/lib/pubkey/xmss/xmss_publickey.cpp b/src/lib/pubkey/xmss/xmss_publickey.cpp index 425c657ca..42fbdb851 100644 --- a/src/lib/pubkey/xmss/xmss_publickey.cpp +++ b/src/lib/pubkey/xmss/xmss_publickey.cpp @@ -26,7 +26,7 @@ XMSS_PublicKey::XMSS_PublicKey(const std::vector<uint8_t>& raw_key) { if(raw_key.size() < size()) { - throw Integrity_Failure("Invalid XMSS public key size detected."); + throw Decoding_Error("Invalid XMSS public key size detected."); } // extract & copy root from raw key. @@ -49,7 +49,7 @@ XMSS_PublicKey::deserialize_xmss_oid(const std::vector<uint8_t>& raw_key) { if(raw_key.size() < 4) { - throw Integrity_Failure("XMSS signature OID missing."); + throw Decoding_Error("XMSS signature OID missing."); } // extract and convert algorithm id to enum type diff --git a/src/lib/pubkey/xmss/xmss_signature.cpp b/src/lib/pubkey/xmss/xmss_signature.cpp index f2d1ba4f1..2ba8a1965 100644 --- a/src/lib/pubkey/xmss/xmss_signature.cpp +++ b/src/lib/pubkey/xmss/xmss_signature.cpp @@ -19,7 +19,7 @@ XMSS_Signature::XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, if(raw_sig.size() != (xmss_params.len() + xmss_params.tree_height() + 1) * xmss_params.element_size() + sizeof(m_leaf_idx)) { - throw Integrity_Failure("XMSS signature size invalid."); + throw Decoding_Error("XMSS signature size invalid."); } for(size_t i = 0; i < 8; i++) @@ -27,7 +27,7 @@ XMSS_Signature::XMSS_Signature(XMSS_Parameters::xmss_algorithm_t oid, if(m_leaf_idx >= (1ull << xmss_params.tree_height())) { - throw Integrity_Failure("XMSS signature leaf index out of bounds."); + throw Decoding_Error("XMSS signature leaf index out of bounds."); } auto begin = raw_sig.begin() + sizeof(m_leaf_idx); diff --git a/src/lib/pubkey/xmss/xmss_verification_operation.cpp b/src/lib/pubkey/xmss/xmss_verification_operation.cpp index 6a757633e..2eacc19fd 100644 --- a/src/lib/pubkey/xmss/xmss_verification_operation.cpp +++ b/src/lib/pubkey/xmss/xmss_verification_operation.cpp @@ -117,7 +117,7 @@ bool XMSS_Verification_Operation::is_valid_signature(const uint8_t sig[], m_msg_buf.clear(); return result; } - catch(Integrity_Failure&) + catch(...) { m_msg_buf.clear(); return false; diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index d3d8f899d..e021be518 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -359,7 +359,7 @@ size_t Channel::received_data(const uint8_t input[], size_t input_size) send_fatal_alert(e.type()); throw; } - catch(Integrity_Failure&) + catch(Invalid_Authentication_Tag&) { send_fatal_alert(Alert::BAD_RECORD_MAC); throw; diff --git a/src/lib/utils/exceptn.cpp b/src/lib/utils/exceptn.cpp index b2dff149b..78365f98b 100644 --- a/src/lib/utils/exceptn.cpp +++ b/src/lib/utils/exceptn.cpp @@ -93,8 +93,8 @@ Decoding_Error::Decoding_Error(const std::string& msg, const std::exception& e) Decoding_Error::Decoding_Error(const std::string& name, const char* exception_message) : Invalid_Argument(name + " failed with exception " + exception_message) {} -Integrity_Failure::Integrity_Failure(const std::string& msg) : - Exception("Integrity failure: " + msg) +Invalid_Authentication_Tag::Invalid_Authentication_Tag(const std::string& msg) : + Exception("Invalid authentication tag: " + msg) {} Invalid_OID::Invalid_OID(const std::string& oid) : diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h index bfff85618..c4934ed04 100644 --- a/src/lib/utils/exceptn.h +++ b/src/lib/utils/exceptn.h @@ -51,6 +51,8 @@ enum class ErrorType { TLSError, /** An error during an HTTP operation */ HttpError, + /** A message with an invalid authentication tag was detected */ + InvalidTag, /** An error when calling OpenSSL */ OpenSSLError = 200, @@ -264,16 +266,24 @@ class BOTAN_PUBLIC_API(2,0) Provider_Not_Found final : public Lookup_Error /** * An AEAD or MAC check detected a message modification +* +* In versions before 2.10, Invalid_Authentication_Tag was named +* Integrity_Failure, it was renamed to make its usage more clear. */ -class BOTAN_PUBLIC_API(2,0) Integrity_Failure final : public Exception +class BOTAN_PUBLIC_API(2,0) Invalid_Authentication_Tag final : public Exception { public: - explicit Integrity_Failure(const std::string& msg); + explicit Invalid_Authentication_Tag(const std::string& msg); - ErrorType error_type() const noexcept override { return ErrorType::DecodingFailure; } + ErrorType error_type() const noexcept override { return ErrorType::InvalidTag; } }; /** +* For compatability with older versions +*/ +typedef Invalid_Authentication_Tag Integrity_Failure; + +/** * An error occurred while operating on an IO stream */ class BOTAN_PUBLIC_API(2,0) Stream_IO_Error final : public Exception @@ -356,6 +366,8 @@ class BOTAN_PUBLIC_API(2,0) Invalid_OID final : public Decoding_Error /** * Self Test Failure Exception +* +* This exception is no longer used. It will be removed in a future major release. */ class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error { @@ -365,6 +377,8 @@ class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error /** * No_Provider_Found Exception +* +* This exception is no longer used. It will be removed in a future major release. */ class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception { @@ -374,6 +388,8 @@ class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception /** * Policy_Violation Exception +* +* This exception is no longer used. It will be removed in a future major release. */ class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State { @@ -388,6 +404,7 @@ class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State * It might or might not be valid in another context like a standard. * * This exception is no longer used, instead Not_Implemented is thrown. +* It will be removed in a future major release. */ class BOTAN_PUBLIC_API(2,0) Unsupported_Argument final : public Invalid_Argument { |