diff options
author | Jack Lloyd <[email protected]> | 2018-11-17 16:23:51 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-11-23 11:15:25 -0500 |
commit | b909778857b3e0b7eb86ac26c818e5f25baaddbd (patch) | |
tree | f8a5c9cbec26310bbfc9077563892b04db158a48 | |
parent | c20a428ca2f7c1ef96e642f55bb898010444c499 (diff) |
Make exceptions easier to translate to error codes
Avoid throwing base Botan::Exception type, as it is difficult to
determine what the error is in that case.
Add Exception::error_code and Exception::error_type which allows
(for error code) more information about the error and (for error type)
allows knowing the error type without requiring a sequence of catches.
See GH #1742
81 files changed, 655 insertions, 359 deletions
diff --git a/src/lib/compression/bzip2/bzip2.cpp b/src/lib/compression/bzip2/bzip2.cpp index 02d17ea07..c9dfc2ce8 100644 --- a/src/lib/compression/bzip2/bzip2.cpp +++ b/src/lib/compression/bzip2/bzip2.cpp @@ -48,10 +48,8 @@ class Bzip2_Compression_Stream final : public Bzip2_Stream int rc = BZ2_bzCompressInit(streamp(), block_size, 0, 0); - if(rc == BZ_MEM_ERROR) - throw Exception("bzip memory allocation failure"); - else if(rc != BZ_OK) - throw Exception("bzip compress initialization failed"); + if(rc != BZ_OK) + throw Compression_Error("BZ2_bzCompressInit", ErrorType::Bzip2Error, rc); } ~Bzip2_Compression_Stream() @@ -63,10 +61,8 @@ class Bzip2_Compression_Stream final : public Bzip2_Stream { int rc = BZ2_bzCompress(streamp(), flags); - if(rc == BZ_MEM_ERROR) - throw Exception("bzip memory allocation failure"); - else if(rc < 0) - throw Exception("bzip compress error " + std::to_string(-rc)); + if(rc < 0) + throw Compression_Error("BZ2_bzCompress", ErrorType::Bzip2Error, rc); return (rc == BZ_STREAM_END); } @@ -79,10 +75,8 @@ class Bzip2_Decompression_Stream final : public Bzip2_Stream { int rc = BZ2_bzDecompressInit(streamp(), 0, 0); - if(rc == BZ_MEM_ERROR) - throw Exception("bzip memory allocation failure"); - else if(rc != BZ_OK) - throw Exception("bzip decompress initialization failed"); + if(rc != BZ_OK) + throw Compression_Error("BZ2_bzDecompressInit", ErrorType::Bzip2Error, rc); } ~Bzip2_Decompression_Stream() @@ -94,10 +88,8 @@ class Bzip2_Decompression_Stream final : public Bzip2_Stream { int rc = BZ2_bzDecompress(streamp()); - if(rc == BZ_MEM_ERROR) - throw Exception("bzip memory allocation failure"); - else if(rc != BZ_OK && rc != BZ_STREAM_END) - throw Exception("bzip decompress error " + std::to_string(-rc)); + if(rc != BZ_OK && rc != BZ_STREAM_END) + throw Compression_Error("BZ2_bzDecompress", ErrorType::Bzip2Error, rc); return (rc == BZ_STREAM_END); } diff --git a/src/lib/compression/compress_utils.cpp b/src/lib/compression/compress_utils.cpp index 6bdf3d0fd..f49a0ede1 100644 --- a/src/lib/compression/compress_utils.cpp +++ b/src/lib/compression/compress_utils.cpp @@ -39,7 +39,7 @@ void Compression_Alloc_Info::do_free(void* ptr) auto i = m_current_allocs.find(ptr); if(i == m_current_allocs.end()) - throw Exception("Compression_Alloc_Info::free got pointer not allocated by us"); + throw Internal_Error("Compression_Alloc_Info::free got pointer not allocated by us"); secure_scrub_memory(ptr, i->second); std::free(ptr); @@ -190,7 +190,7 @@ void Stream_Decompression::finish(secure_vector<uint8_t>& buf, size_t offset) process(buf, offset, m_stream->finish_flag()); if(m_stream.get()) - throw Exception(name() + " finished but not at stream end"); + throw Invalid_State(name() + " finished but not at stream end"); } } diff --git a/src/lib/compression/compression.h b/src/lib/compression/compression.h index f331874cf..1365894e2 100644 --- a/src/lib/compression/compression.h +++ b/src/lib/compression/compression.h @@ -9,11 +9,12 @@ #define BOTAN_COMPRESSION_TRANSFORM_H_ #include <botan/secmem.h> +#include <botan/exceptn.h> #include <string> namespace Botan { -/* +/** * Interface for a compression algorithm. */ class BOTAN_PUBLIC_API(2,0) Compression_Algorithm @@ -134,6 +135,35 @@ BOTAN_PUBLIC_API(2,0) Compression_Algorithm* make_compressor(const std::string& BOTAN_PUBLIC_API(2,0) Decompression_Algorithm* make_decompressor(const std::string& type); /** +* An error that occurred during compression (or decompression) +*/ +class BOTAN_PUBLIC_API(2,9) Compression_Error : public Exception + { + public: + + /** + * @param func_name the name of the compression API that was called + * (eg "BZ2_bzCompressInit" or "lzma_code") + * @param rc the error return code from the compression API. The + * interpretation of this value will depend on the library. + */ + Compression_Error(const char* func_name, ErrorType type, int rc) : + Exception("Compression API " + std::string(func_name) + + " failed with return code " + std::to_string(rc)), + m_type(type), + m_rc(rc) + {} + + ErrorType error_type() const noexcept override { return m_type; } + + int error_code() const noexcept override { return m_rc; } + + private: + ErrorType m_type; + int m_rc; + }; + +/** * Adapts a zlib style API */ class Compression_Stream diff --git a/src/lib/compression/lzma/lzma.cpp b/src/lib/compression/lzma/lzma.cpp index 92c61840a..73bb9eb89 100644 --- a/src/lib/compression/lzma/lzma.cpp +++ b/src/lib/compression/lzma/lzma.cpp @@ -37,10 +37,8 @@ class LZMA_Stream : public Zlib_Style_Stream<lzma_stream, uint8_t> { lzma_ret rc = ::lzma_code(streamp(), static_cast<lzma_action>(flags)); - if(rc == LZMA_MEM_ERROR) - throw Exception("lzma memory allocation failed"); - else if (rc != LZMA_OK && rc != LZMA_STREAM_END) - throw Exception("Lzma error"); + if(rc != LZMA_OK && rc != LZMA_STREAM_END) + throw Compression_Error("lzma_code", ErrorType::LzmaError, rc); return (rc == LZMA_STREAM_END); } @@ -64,10 +62,8 @@ class LZMA_Compression_Stream final : public LZMA_Stream lzma_ret rc = ::lzma_easy_encoder(streamp(), level, LZMA_CHECK_CRC64); - if(rc == LZMA_MEM_ERROR) - throw Exception("lzma memory allocation failed"); - else if(rc != LZMA_OK) - throw Exception("lzma compress initialization failed"); + if(rc != LZMA_OK) + throw Compression_Error("lzam_easy_encoder", ErrorType::LzmaError, rc); } }; @@ -79,10 +75,8 @@ class LZMA_Decompression_Stream final : public LZMA_Stream lzma_ret rc = ::lzma_stream_decoder(streamp(), UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK); - if(rc == LZMA_MEM_ERROR) - throw Exception("lzma memory allocation failed"); - else if(rc != LZMA_OK) - throw Exception("Bad setting in lzma_stream_decoder"); + if(rc != LZMA_OK) + throw Compression_Error("lzma_stream_decoder", ErrorType::LzmaError, rc); } }; diff --git a/src/lib/compression/zlib/zlib.cpp b/src/lib/compression/zlib/zlib.cpp index 57494e225..285bc4e91 100644 --- a/src/lib/compression/zlib/zlib.cpp +++ b/src/lib/compression/zlib/zlib.cpp @@ -54,7 +54,7 @@ class Zlib_Compression_Stream : public Zlib_Stream int rc = ::deflateInit2(streamp(), level, Z_DEFLATED, wbits, 8, Z_DEFAULT_STRATEGY); if(rc != Z_OK) - throw Exception("zlib deflate initialization failed"); + throw Compression_Error("deflateInit2", ErrorType::ZlibError, rc); } ~Zlib_Compression_Stream() @@ -66,10 +66,8 @@ class Zlib_Compression_Stream : public Zlib_Stream { int rc = ::deflate(streamp(), flags); - if(rc == Z_MEM_ERROR) - throw Exception("zlib memory allocation failure"); - else if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) - throw Exception("zlib deflate error " + std::to_string(rc)); + if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) + throw Compression_Error("zlib deflate", ErrorType::ZlibError, rc); return (rc == Z_STREAM_END); } @@ -82,10 +80,8 @@ class Zlib_Decompression_Stream : public Zlib_Stream { int rc = ::inflateInit2(streamp(), compute_window_bits(wbits, wbits_offset)); - if(rc == Z_MEM_ERROR) - throw Exception("zlib memory allocation failure"); - else if(rc != Z_OK) - throw Exception("zlib inflate initialization failed"); + if(rc != Z_OK) + throw Compression_Error("inflateInit2", ErrorType::ZlibError, rc); } ~Zlib_Decompression_Stream() @@ -97,10 +93,8 @@ class Zlib_Decompression_Stream : public Zlib_Stream { int rc = ::inflate(streamp(), flags); - if(rc == Z_MEM_ERROR) - throw Exception("zlib memory allocation failure"); - else if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) - throw Exception("zlib inflate error " + std::to_string(rc)); + if(rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) + throw Compression_Error("zlib inflate", ErrorType::ZlibError, rc); return (rc == Z_STREAM_END); } @@ -131,7 +125,7 @@ class Gzip_Compression_Stream final : public Zlib_Compression_Stream int rc = deflateSetHeader(streamp(), &m_header); if(rc != Z_OK) - throw Exception("setting gzip header failed"); + throw Compression_Error("deflateSetHeader", ErrorType::ZlibError, rc); } private: diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp index 56552228a..44fcbace3 100644 --- a/src/lib/entropy/dev_random/dev_random.cpp +++ b/src/lib/entropy/dev_random/dev_random.cpp @@ -47,15 +47,14 @@ Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnam either a bug in the application or file descriptor exhaustion. */ if(errno != ENOENT && errno != EACCES) - throw Exception("Opening OS RNG device failed with errno " + - std::to_string(errno)); + throw System_Error("Opening OS RNG device failed", errno); } else { if(fd > FD_SETSIZE) { ::close(fd); - throw Exception("Open of OS RNG succeeded but fd is too large for fd_set"); + throw Invalid_State("Open of OS RNG succeeded but returned fd is too large for fd_set"); } m_dev_fds.push_back(fd); diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 74291199b..cfc2cb2d5 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -25,6 +25,59 @@ int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) return rc; } +namespace { + +int ffi_map_error_type(Botan::ErrorType err) + { + switch(err) + { + case Botan::ErrorType::Unknown: + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + case Botan::ErrorType::SystemError: + case Botan::ErrorType::IoError: + case Botan::ErrorType::OpenSSLError: + case Botan::ErrorType::Pkcs11Error: + case Botan::ErrorType::CommonCryptoError: + case Botan::ErrorType::TPMError: + case Botan::ErrorType::ZlibError: + case Botan::ErrorType::Bzip2Error: + case Botan::ErrorType::LzmaError: + return BOTAN_FFI_ERROR_SYSTEM_ERROR; + + case Botan::ErrorType::NotImplemented: + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + case Botan::ErrorType::OutOfMemory: + return BOTAN_FFI_ERROR_OUT_OF_MEMORY; + case Botan::ErrorType::InternalError: + return BOTAN_FFI_ERROR_INTERNAL_ERROR; + case Botan::ErrorType::InvalidObjectState: + return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE; + case Botan::ErrorType::KeyNotSet: + return BOTAN_FFI_ERROR_KEY_NOT_SET; + case Botan::ErrorType::InvalidArgument: + case Botan::ErrorType::InvalidNonceLength: + return BOTAN_FFI_ERROR_BAD_PARAMETER; + + case Botan::ErrorType::EncodingFailure: + case Botan::ErrorType::DecodingFailure: + return BOTAN_FFI_ERROR_INVALID_INPUT; + + case Botan::ErrorType::InvalidKeyLength: + return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH; + case Botan::ErrorType::LookupError: + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + + case Botan::ErrorType::HttpError: + return BOTAN_FFI_ERROR_HTTP_ERROR; + case Botan::ErrorType::TLSError: + return BOTAN_FFI_ERROR_TLS_ERROR; + } + + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + } + +} + int ffi_guard_thunk(const char* func_name, std::function<int ()> thunk) { try @@ -39,25 +92,9 @@ int ffi_guard_thunk(const char* func_name, std::function<int ()> thunk) { return ffi_error_exception_thrown(func_name, e.what(), e.error_code()); } - catch(Botan::Lookup_Error& e) - { - return ffi_error_exception_thrown(func_name, e.what(), BOTAN_FFI_ERROR_NOT_IMPLEMENTED); - } - catch(Botan::Invalid_Key_Length& e) - { - return ffi_error_exception_thrown(func_name, e.what(), BOTAN_FFI_ERROR_INVALID_KEY_LENGTH); - } - catch(Botan::Key_Not_Set& e) - { - return ffi_error_exception_thrown(func_name, e.what(), BOTAN_FFI_ERROR_KEY_NOT_SET); - } - catch(Botan::Invalid_Argument& e) - { - return ffi_error_exception_thrown(func_name, e.what(), BOTAN_FFI_ERROR_BAD_PARAMETER); - } - catch(Botan::Not_Implemented& e) + catch(Botan::Exception& e) { - return ffi_error_exception_thrown(func_name, e.what(), BOTAN_FFI_ERROR_NOT_IMPLEMENTED); + return ffi_error_exception_thrown(func_name, e.what(), ffi_map_error_type(e.error_type())); } catch(std::exception& e) { @@ -102,6 +139,12 @@ const char* botan_error_description(int err) case BOTAN_FFI_ERROR_OUT_OF_MEMORY: return "Out of memory"; + case BOTAN_FFI_ERROR_SYSTEM_ERROR: + return "Error while calling system API"; + + case BOTAN_FFI_ERROR_INTERNAL_ERROR: + return "Internal error"; + case BOTAN_FFI_ERROR_BAD_FLAG: return "Bad flag"; @@ -117,12 +160,21 @@ const char* botan_error_description(int err) case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH: return "Invalid key length"; + case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE: + return "Invalid object state"; + case BOTAN_FFI_ERROR_NOT_IMPLEMENTED: return "Not implemented"; case BOTAN_FFI_ERROR_INVALID_OBJECT: return "Invalid object handle"; + case BOTAN_FFI_ERROR_TLS_ERROR: + return "TLS error"; + + case BOTAN_FFI_ERROR_HTTP_ERROR: + return "HTTP error"; + case BOTAN_FFI_ERROR_UNKNOWN_ERROR: return "Unknown error"; } diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index fbc396d12..c3712bd97 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -54,6 +54,9 @@ API follows a few simple rules: /** * Error codes +* +* If you add a new value here be sure to also add it in +* botan_error_description */ enum BOTAN_FFI_ERROR { BOTAN_FFI_SUCCESS = 0, @@ -63,16 +66,25 @@ enum BOTAN_FFI_ERROR { BOTAN_FFI_ERROR_BAD_MAC = -2, BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE = -10, + BOTAN_FFI_ERROR_EXCEPTION_THROWN = -20, BOTAN_FFI_ERROR_OUT_OF_MEMORY = -21, + BOTAN_FFI_ERROR_SYSTEM_ERROR = -22, + BOTAN_FFI_ERROR_INTERNAL_ERROR = -23, + BOTAN_FFI_ERROR_BAD_FLAG = -30, BOTAN_FFI_ERROR_NULL_POINTER = -31, BOTAN_FFI_ERROR_BAD_PARAMETER = -32, BOTAN_FFI_ERROR_KEY_NOT_SET = -33, BOTAN_FFI_ERROR_INVALID_KEY_LENGTH = -34, + BOTAN_FFI_ERROR_INVALID_OBJECT_STATE = -35, + BOTAN_FFI_ERROR_NOT_IMPLEMENTED = -40, BOTAN_FFI_ERROR_INVALID_OBJECT = -50, + BOTAN_FFI_ERROR_TLS_ERROR = -75, + BOTAN_FFI_ERROR_HTTP_ERROR = -76, + BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100, }; diff --git a/src/lib/ffi/ffi_util.h b/src/lib/ffi/ffi_util.h index d68baf699..2962b05e1 100644 --- a/src/lib/ffi/ffi_util.h +++ b/src/lib/ffi/ffi_util.h @@ -24,7 +24,9 @@ class BOTAN_UNSTABLE_API FFI_Error final : public Botan::Exception m_err_code(err_code) {} - int error_code() const { return m_err_code; } + int error_code() const noexcept override { return m_err_code; } + + Botan::ErrorType error_type() const noexcept override { return Botan::ErrorType::InvalidArgument; } private: int m_err_code; diff --git a/src/lib/filters/buf_filt.cpp b/src/lib/filters/buf_filt.cpp index 8acc6c74f..11ca9bbfe 100644 --- a/src/lib/filters/buf_filt.cpp +++ b/src/lib/filters/buf_filt.cpp @@ -82,7 +82,7 @@ void Buffered_Filter::write(const uint8_t input[], size_t input_size) void Buffered_Filter::end_msg() { if(m_buffer_pos < m_final_minimum) - throw Exception("Buffered filter end_msg without enough input"); + throw Invalid_State("Buffered filter end_msg without enough input"); size_t spare_blocks = (m_buffer_pos - m_final_minimum) / m_main_block_mod; diff --git a/src/lib/math/bigint/big_io.cpp b/src/lib/math/bigint/big_io.cpp index 803e1cc4a..90c2253e9 100644 --- a/src/lib/math/bigint/big_io.cpp +++ b/src/lib/math/bigint/big_io.cpp @@ -20,7 +20,7 @@ std::ostream& operator<<(std::ostream& stream, const BigInt& n) if(stream.flags() & std::ios::hex) base = BigInt::Hexadecimal; else if(stream.flags() & std::ios::oct) - throw Exception("Octal output of BigInt not supported"); + throw Invalid_Argument("Octal output of BigInt not supported"); if(n == 0) stream.write("0", 1); diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h index bd63425fd..64e408798 100644 --- a/src/lib/math/bigint/bigint.h +++ b/src/lib/math/bigint/bigint.h @@ -37,11 +37,14 @@ class BOTAN_PUBLIC_API(2,0) BigInt final /** * DivideByZero Exception + * + * In a future release this exception will be removed and its usage + * replaced by Invalid_Argument */ - class BOTAN_PUBLIC_API(2,0) DivideByZero final : public Exception + class BOTAN_PUBLIC_API(2,0) DivideByZero final : public Invalid_Argument { public: - DivideByZero() : Exception("BigInt divide by zero") {} + DivideByZero() : Invalid_Argument("BigInt divide by zero") {} }; /** diff --git a/src/lib/math/numbertheory/numthry.cpp b/src/lib/math/numbertheory/numthry.cpp index bb86f5ce0..a8dfe8eaf 100644 --- a/src/lib/math/numbertheory/numthry.cpp +++ b/src/lib/math/numbertheory/numthry.cpp @@ -351,7 +351,7 @@ BigInt inverse_euclid(const BigInt& n, const BigInt& mod) word monty_inverse(word input) { if(input == 0) - throw Exception("monty_inverse: divide by zero"); + throw Invalid_Argument("monty_inverse: divide by zero"); word b = input; word x2 = 1, x1 = 0, y2 = 0, y1 = 1; diff --git a/src/lib/misc/fpe_fe1/fpe_fe1.cpp b/src/lib/misc/fpe_fe1/fpe_fe1.cpp index 680967ea9..3bd01ce34 100644 --- a/src/lib/misc/fpe_fe1/fpe_fe1.cpp +++ b/src/lib/misc/fpe_fe1/fpe_fe1.cpp @@ -50,7 +50,7 @@ void factor(BigInt n, BigInt& a, BigInt& b) a *= n; if(a <= 1 || b <= 1) - throw Exception("Could not factor n for use in FPE"); + throw Internal_Error("Could not factor n for use in FPE"); } } @@ -69,7 +69,7 @@ FPE_FE1::FPE_FE1(const BigInt& n, m_n_bytes = BigInt::encode(n); if(m_n_bytes.size() > MAX_N_BYTES) - throw Exception("N is too large for FPE encryption"); + throw Invalid_Argument("N is too large for FPE encryption"); factor(n, m_a, m_b); diff --git a/src/lib/misc/srp6/srp6.cpp b/src/lib/misc/srp6/srp6.cpp index cb7e3c600..0ec4fd2bb 100644 --- a/src/lib/misc/srp6/srp6.cpp +++ b/src/lib/misc/srp6/srp6.cpp @@ -64,13 +64,13 @@ std::string srp6_group_identifier(const BigInt& N, const BigInt& g) if(group.get_p() == N && group.get_g() == g) return group_name; - - throw Exception("Unknown SRP params"); } catch(...) { - throw Invalid_Argument("Bad SRP group parameters"); } + + // If we didn't return, the group was unknown or did not match + throw Invalid_Argument("Invalid or unknown SRP group parameters"); } std::pair<BigInt, SymmetricKey> @@ -91,7 +91,7 @@ srp6_client_agree(const std::string& identifier, const size_t p_bytes = group.p_bytes(); if(B <= 0 || B >= p) - throw Exception("Invalid SRP parameter from server"); + throw Decoding_Error("Invalid SRP parameter from server"); const BigInt k = hash_seq(hash_id, p_bytes, p, g); @@ -150,7 +150,7 @@ BigInt SRP6_Server_Session::step1(const BigInt& v, SymmetricKey SRP6_Server_Session::step2(const BigInt& A) { if(A <= 0 || A >= m_p) - throw Exception("Invalid SRP parameter from client"); + throw Decoding_Error("Invalid SRP parameter from client"); const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B); diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp index 457c4831f..75768d851 100644 --- a/src/lib/modes/aead/gcm/gcm.cpp +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -150,7 +150,7 @@ void GCM_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) uint8_t* buf = buffer.data() + offset; if(sz < tag_size()) - throw Exception("Insufficient input for GCM decryption, tag missing"); + throw Decoding_Error("Insufficient input for GCM decryption, tag missing"); const size_t remaining = sz - tag_size(); diff --git a/src/lib/modes/cbc/cbc.cpp b/src/lib/modes/cbc/cbc.cpp index aa73eb884..a4af7f0bf 100644 --- a/src/lib/modes/cbc/cbc.cpp +++ b/src/lib/modes/cbc/cbc.cpp @@ -136,7 +136,7 @@ void CBC_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset) padding().add_padding(buffer, bytes_in_final_block, BS); if((buffer.size()-offset) % BS) - throw Exception("Did not pad to full block size in " + name()); + throw Internal_Error("Did not pad to full block size in " + name()); update(buffer, offset); } diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp index 6fc007bf3..9d0be3a58 100644 --- a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp +++ b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp @@ -25,7 +25,7 @@ void pbkdf2_set_key(MessageAuthenticationCode& prf, } catch(Invalid_Key_Length&) { - throw Exception("PBKDF2 cannot accept passphrase of the given size"); + throw Invalid_Argument("PBKDF2 cannot accept passphrase of the given size"); } } diff --git a/src/lib/pbkdf/scrypt/scrypt.cpp b/src/lib/pbkdf/scrypt/scrypt.cpp index 826438926..c20225734 100644 --- a/src/lib/pbkdf/scrypt/scrypt.cpp +++ b/src/lib/pbkdf/scrypt/scrypt.cpp @@ -226,7 +226,7 @@ void scrypt(uint8_t output[], size_t output_len, } catch(Invalid_Key_Length&) { - throw Exception("Scrypt cannot accept passphrases of the provided length"); + throw Invalid_Argument("Scrypt cannot accept passphrases of the provided length"); } pbkdf2(*hmac_sha256.get(), diff --git a/src/lib/prov/commoncrypto/commoncrypto.h b/src/lib/prov/commoncrypto/commoncrypto.h index 958cbab7d..31fa110fc 100644 --- a/src/lib/prov/commoncrypto/commoncrypto.h +++ b/src/lib/prov/commoncrypto/commoncrypto.h @@ -24,14 +24,23 @@ typedef int32_t CCCryptorStatus; class BOTAN_PUBLIC_API(2, 0) CommonCrypto_Error final : public Exception { - std::string ccryptorstatus_to_string(CCCryptorStatus status); - public: CommonCrypto_Error(const std::string& what) : - Exception(what + " failed.") {} + Exception(what + " failed."), + m_rc(0) {} CommonCrypto_Error(const std::string& what, int32_t status) : - Exception(what + std::string(" failed. Status: ") + ccryptorstatus_to_string(status)) {} + Exception(what + std::string(" failed. Status: ") + ccryptorstatus_to_string(status)), + m_rc(status) {} + + ErrorType error_type() const noexcept override { return ErrorType::CommonCryptoError; } + + int error_code() const noexcept override { return m_rc; } + + private: + std::string ccryptorstatus_to_string(CCCryptorStatus status); + + int32_t m_rc; }; /* Cipher Modes */ diff --git a/src/lib/prov/openssl/openssl.h b/src/lib/prov/openssl/openssl.h index 3db7b39af..a68dda5af 100644 --- a/src/lib/prov/openssl/openssl.h +++ b/src/lib/prov/openssl/openssl.h @@ -33,11 +33,16 @@ enum Cipher_Dir : int; class BOTAN_PUBLIC_API(2,0) OpenSSL_Error final : public Exception { public: - OpenSSL_Error(const std::string& what) : - Exception(what + " failed: " + ERR_error_string(ERR_get_error(), nullptr)) {} - OpenSSL_Error(const std::string& what, int err) : - Exception(what + " failed: " + ERR_error_string(err, nullptr)) {} + Exception(what + " failed: " + ERR_error_string(err, nullptr)), + m_err(err) {} + + ErrorType error_type() const noexcept override { return ErrorType::OpenSSLError; } + + int error_code() const noexcept override { return m_err; } + + private: + int m_err; }; /* Block Ciphers */ diff --git a/src/lib/prov/openssl/openssl_block.cpp b/src/lib/prov/openssl/openssl_block.cpp index d785c3c8d..fdded7285 100644 --- a/src/lib/prov/openssl/openssl_block.cpp +++ b/src/lib/prov/openssl/openssl_block.cpp @@ -39,7 +39,7 @@ class OpenSSL_BlockCipher final : public BlockCipher verify_key_set(m_key_set); int out_len = 0; if(!EVP_EncryptUpdate(m_encrypt, out, &out_len, in, blocks * m_block_sz)) - throw OpenSSL_Error("EVP_EncryptUpdate"); + throw OpenSSL_Error("EVP_EncryptUpdate", ERR_get_error()); } void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override @@ -47,7 +47,7 @@ class OpenSSL_BlockCipher final : public BlockCipher verify_key_set(m_key_set); int out_len = 0; if(!EVP_DecryptUpdate(m_decrypt, out, &out_len, in, blocks * m_block_sz)) - throw OpenSSL_Error("EVP_DecryptUpdate"); + throw OpenSSL_Error("EVP_DecryptUpdate", ERR_get_error()); } void key_schedule(const uint8_t key[], size_t key_len) override; @@ -73,20 +73,20 @@ OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, m_encrypt = EVP_CIPHER_CTX_new(); m_decrypt = EVP_CIPHER_CTX_new(); if (m_encrypt == nullptr || m_decrypt == nullptr) - throw OpenSSL_Error("Can't allocate new context"); + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); EVP_CIPHER_CTX_init(m_encrypt); EVP_CIPHER_CTX_init(m_decrypt); if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_EncryptInit_ex"); + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_DecryptInit_ex"); + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); } OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, @@ -105,20 +105,20 @@ OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name, m_encrypt = EVP_CIPHER_CTX_new(); m_decrypt = EVP_CIPHER_CTX_new(); if (m_encrypt == nullptr || m_decrypt == nullptr) - throw OpenSSL_Error("Can't allocate new context"); + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); EVP_CIPHER_CTX_init(m_encrypt); EVP_CIPHER_CTX_init(m_decrypt); if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_EncryptInit_ex"); + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_DecryptInit_ex"); + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); } OpenSSL_BlockCipher::~OpenSSL_BlockCipher() @@ -150,9 +150,9 @@ void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length) } if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr)) - throw OpenSSL_Error("EVP_EncryptInit_ex"); + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); if(!EVP_DecryptInit_ex(m_decrypt, nullptr, nullptr, full_key.data(), nullptr)) - throw OpenSSL_Error("EVP_DecryptInit_ex"); + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); m_key_set = true; } @@ -179,19 +179,19 @@ void OpenSSL_BlockCipher::clear() m_key_set = false; if(!EVP_CIPHER_CTX_cleanup(m_encrypt)) - throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup encrypt", ERR_get_error()); if(!EVP_CIPHER_CTX_cleanup(m_decrypt)) - throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup decrypt", ERR_get_error()); EVP_CIPHER_CTX_init(m_encrypt); EVP_CIPHER_CTX_init(m_decrypt); if(!EVP_EncryptInit_ex(m_encrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_EncryptInit_ex"); + throw OpenSSL_Error("EVP_EncryptInit_ex", ERR_get_error()); if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr)) - throw OpenSSL_Error("EVP_DecryptInit_ex"); + throw OpenSSL_Error("EVP_DecryptInit_ex", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_encrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding encrypt", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error()); } } diff --git a/src/lib/prov/openssl/openssl_ec.cpp b/src/lib/prov/openssl/openssl_ec.cpp index e044d552a..026dfa5e0 100644 --- a/src/lib/prov/openssl/openssl_ec.cpp +++ b/src/lib/prov/openssl/openssl_ec.cpp @@ -142,16 +142,16 @@ class OpenSSL_ECDSA_Verification_Operation final : public PK_Ops::Verification_w ::EC_GROUP_free); if(!grp) - throw OpenSSL_Error("EC_GROUP_new_by_curve_name"); + throw OpenSSL_Error("EC_GROUP_new_by_curve_name", ERR_get_error()); if(!::EC_KEY_set_group(m_ossl_ec.get(), grp.get())) - throw OpenSSL_Error("EC_KEY_set_group"); + throw OpenSSL_Error("EC_KEY_set_group", ERR_get_error()); const std::vector<uint8_t> enc = ecdsa.public_point().encode(PointGFp::UNCOMPRESSED); const uint8_t* enc_ptr = enc.data(); EC_KEY* key_ptr = m_ossl_ec.get(); if(!::o2i_ECPublicKey(&key_ptr, &enc_ptr, enc.size())) - throw OpenSSL_Error("o2i_ECPublicKey"); + throw OpenSSL_Error("o2i_ECPublicKey", ERR_get_error()); const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get()); m_order_bits = ::EC_GROUP_get_degree(group); @@ -178,7 +178,7 @@ class OpenSSL_ECDSA_Verification_Operation final : public PK_Ops::Verification_w BIGNUM* r = BN_bin2bn(sig_bytes , sig_len / 2, nullptr); BIGNUM* s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, nullptr); if(r == nullptr || s == nullptr) - throw OpenSSL_Error("BN_bin2bn sig s"); + throw OpenSSL_Error("BN_bin2bn sig s", ERR_get_error()); ECDSA_SIG_set0(sig.get(), r, s); #endif @@ -225,7 +225,7 @@ class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA const uint8_t* der_ptr = der.data(); m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size())); if(!m_ossl_ec) - throw OpenSSL_Error("d2i_ECPrivateKey"); + throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error()); const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get()); m_order_bits = ::EC_GROUP_get_degree(group); @@ -241,7 +241,7 @@ class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get())); if(!sig) - throw OpenSSL_Error("ECDSA_do_sign"); + throw OpenSSL_Error("ECDSA_do_sign", ERR_get_error()); #if OPENSSL_VERSION_NUMBER < 0x10100000L const BIGNUM* r = sig->r; @@ -318,7 +318,7 @@ class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF const uint8_t* der_ptr = der.data(); m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size())); if(!m_ossl_ec) - throw OpenSSL_Error("d2i_ECPrivateKey"); + throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error()); } size_t agreed_value_size() const override { return m_value_size; } @@ -331,13 +331,13 @@ class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF EC_POINT* pub_key = ::EC_POINT_new(group); if(!pub_key) - throw OpenSSL_Error("EC_POINT_new"); + throw OpenSSL_Error("EC_POINT_new", ERR_get_error()); const int os2ecp_rc = ::EC_POINT_oct2point(group, pub_key, w, w_len, nullptr); if(os2ecp_rc != 1) - throw OpenSSL_Error("EC_POINT_oct2point"); + throw OpenSSL_Error("EC_POINT_oct2point", ERR_get_error()); const int ecdh_rc = ::ECDH_compute_key(out.data(), out.size(), @@ -346,7 +346,7 @@ class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF /*KDF*/nullptr); if(ecdh_rc <= 0) - throw OpenSSL_Error("ECDH_compute_key"); + throw OpenSSL_Error("ECDH_compute_key", ERR_get_error()); const size_t ecdh_sz = static_cast<size_t>(ecdh_rc); diff --git a/src/lib/prov/openssl/openssl_hash.cpp b/src/lib/prov/openssl/openssl_hash.cpp index 1f4da0484..4eaca12b4 100644 --- a/src/lib/prov/openssl/openssl_hash.cpp +++ b/src/lib/prov/openssl/openssl_hash.cpp @@ -21,7 +21,7 @@ class OpenSSL_HashFunction final : public HashFunction { const EVP_MD* algo = EVP_MD_CTX_md(m_md); if(!EVP_DigestInit_ex(m_md, algo, nullptr)) - throw OpenSSL_Error("EVP_DigestInit_ex"); + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); } std::string provider() const override { return "openssl"; } @@ -59,10 +59,10 @@ class OpenSSL_HashFunction final : public HashFunction #endif if(m_md == nullptr) - throw OpenSSL_Error("Can't allocate new context"); + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); EVP_MD_CTX_init(m_md); if(md && !EVP_DigestInit_ex(m_md, md, nullptr)) - throw OpenSSL_Error("EVP_DigestInit_ex"); + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); } OpenSSL_HashFunction(EVP_MD_CTX* ctx) : m_md(ctx) @@ -82,16 +82,16 @@ class OpenSSL_HashFunction final : public HashFunction void add_data(const uint8_t input[], size_t length) override { if(!EVP_DigestUpdate(m_md, input, length)) - throw OpenSSL_Error("EVP_DigestUpdate"); + throw OpenSSL_Error("EVP_DigestUpdate", ERR_get_error()); } void final_result(uint8_t output[]) override { if(!EVP_DigestFinal_ex(m_md, output, nullptr)) - throw OpenSSL_Error("EVP_DigestFinal_ex"); + throw OpenSSL_Error("EVP_DigestFinal_ex", ERR_get_error()); const EVP_MD* algo = EVP_MD_CTX_md(m_md); if(!EVP_DigestInit_ex(m_md, algo, nullptr)) - throw OpenSSL_Error("EVP_DigestInit_ex"); + throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error()); } std::string m_name; diff --git a/src/lib/prov/openssl/openssl_mode.cpp b/src/lib/prov/openssl/openssl_mode.cpp index d1983949d..81f8413a2 100644 --- a/src/lib/prov/openssl/openssl_mode.cpp +++ b/src/lib/prov/openssl/openssl_mode.cpp @@ -65,14 +65,14 @@ OpenSSL_Cipher_Mode::OpenSSL_Cipher_Mode(const std::string& name, m_cipher = EVP_CIPHER_CTX_new(); if (m_cipher == nullptr) - throw OpenSSL_Error("Can't allocate new context"); + throw OpenSSL_Error("Can't allocate new context", ERR_get_error()); EVP_CIPHER_CTX_init(m_cipher); if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr, m_direction == ENCRYPTION ? 1 : 0)) - throw OpenSSL_Error("EVP_CipherInit_ex"); + throw OpenSSL_Error("EVP_CipherInit_ex", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding", ERR_get_error()); } OpenSSL_Cipher_Mode::~OpenSSL_Cipher_Mode() @@ -90,13 +90,13 @@ void OpenSSL_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) if(nonce_len) { if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nonce, -1)) - throw OpenSSL_Error("EVP_CipherInit_ex nonce"); + throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error()); } else if(m_nonce_set == false) { const std::vector<uint8_t> zeros(m_block_size); if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, zeros.data(), -1)) - throw OpenSSL_Error("EVP_CipherInit_ex nonce"); + throw OpenSSL_Error("EVP_CipherInit_ex nonce", ERR_get_error()); } // otherwise existing CBC state left unchanged @@ -116,7 +116,7 @@ size_t OpenSSL_Cipher_Mode::process(uint8_t msg[], size_t msg_len) secure_vector<uint8_t> out(outl); if(!EVP_CipherUpdate(m_cipher, out.data(), &outl, msg, msg_len)) - throw OpenSSL_Error("EVP_CipherUpdate"); + throw OpenSSL_Error("EVP_CipherUpdate", ERR_get_error()); copy_mem(msg, out.data(), outl); return outl; } @@ -136,7 +136,7 @@ void OpenSSL_Cipher_Mode::finish(secure_vector<uint8_t>& buffer, secure_vector<uint8_t> out(outl); if(!EVP_CipherFinal_ex(m_cipher, out.data(), &outl)) - throw OpenSSL_Error("EVP_CipherFinal_ex"); + throw OpenSSL_Error("EVP_CipherFinal_ex", ERR_get_error()); copy_mem(buf + written, out.data(), outl); written += outl; buffer.resize(offset + written); @@ -178,19 +178,19 @@ void OpenSSL_Cipher_Mode::clear() const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_cipher); if(!EVP_CIPHER_CTX_cleanup(m_cipher)) - throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup"); + throw OpenSSL_Error("EVP_CIPHER_CTX_cleanup", ERR_get_error()); EVP_CIPHER_CTX_init(m_cipher); if(!EVP_CipherInit_ex(m_cipher, algo, nullptr, nullptr, nullptr, m_direction == ENCRYPTION ? 1 : 0)) - throw OpenSSL_Error("EVP_CipherInit_ex clear"); + throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error()); if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding clear"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding clear", ERR_get_error()); } void OpenSSL_Cipher_Mode::reset() { if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nullptr, -1)) - throw OpenSSL_Error("EVP_CipherInit_ex clear"); + throw OpenSSL_Error("EVP_CipherInit_ex clear", ERR_get_error()); m_nonce_set = false; } @@ -202,9 +202,9 @@ Key_Length_Specification OpenSSL_Cipher_Mode::key_spec() const void OpenSSL_Cipher_Mode::key_schedule(const uint8_t key[], size_t length) { if(!EVP_CIPHER_CTX_set_key_length(m_cipher, length)) - throw OpenSSL_Error("EVP_CIPHER_CTX_set_key_length"); + throw OpenSSL_Error("EVP_CIPHER_CTX_set_key_length", ERR_get_error()); if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, key, nullptr, -1)) - throw OpenSSL_Error("EVP_CipherInit_ex key"); + throw OpenSSL_Error("EVP_CipherInit_ex key", ERR_get_error()); m_key_set = true; m_nonce_set = false; } diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp index 0e00607de..dbda890f8 100644 --- a/src/lib/prov/openssl/openssl_rc4.cpp +++ b/src/lib/prov/openssl/openssl_rc4.cpp @@ -51,7 +51,7 @@ class OpenSSL_RC4 final : public StreamCipher void set_iv(const uint8_t*, size_t len) override { if(len > 0) - throw Exception("RC4 does not support an IV"); + throw Invalid_IV_Length("RC4", len); } void seek(uint64_t) override diff --git a/src/lib/prov/openssl/openssl_rsa.cpp b/src/lib/prov/openssl/openssl_rsa.cpp index 4e9068ce4..6744b35b2 100644 --- a/src/lib/prov/openssl/openssl_rsa.cpp +++ b/src/lib/prov/openssl/openssl_rsa.cpp @@ -52,7 +52,7 @@ class OpenSSL_RSA_Encryption_Operation final : public PK_Ops::Encryption const uint8_t* der_ptr = der.data(); m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) - throw OpenSSL_Error("d2i_RSAPublicKey"); + throw OpenSSL_Error("d2i_RSAPublicKey", ERR_get_error()); m_bits = 8 * (n_size() - pad_overhead) - 1; } @@ -86,7 +86,7 @@ class OpenSSL_RSA_Encryption_Operation final : public PK_Ops::Encryption int rc = ::RSA_public_encrypt(inbuf.size(), inbuf.data(), outbuf.data(), m_openssl_rsa.get(), m_padding); if(rc < 0) - throw OpenSSL_Error("RSA_public_encrypt"); + throw OpenSSL_Error("RSA_public_encrypt", ERR_get_error()); return outbuf; } @@ -109,7 +109,7 @@ class OpenSSL_RSA_Decryption_Operation final : public PK_Ops::Decryption const uint8_t* der_ptr = der.data(); m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) - throw OpenSSL_Error("d2i_RSAPrivateKey"); + throw OpenSSL_Error("d2i_RSAPrivateKey", ERR_get_error()); } size_t plaintext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); } @@ -155,7 +155,7 @@ class OpenSSL_RSA_Verification_Operation final : public PK_Ops::Verification_wit const uint8_t* der_ptr = der.data(); m_openssl_rsa.reset(::d2i_RSAPublicKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) - throw OpenSSL_Error("d2i_RSAPublicKey"); + throw OpenSSL_Error("d2i_RSAPublicKey", ERR_get_error()); } size_t max_input_bits() const override @@ -206,7 +206,7 @@ class OpenSSL_RSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA const uint8_t* der_ptr = der.data(); m_openssl_rsa.reset(d2i_RSAPrivateKey(nullptr, &der_ptr, der.size())); if(!m_openssl_rsa) - throw OpenSSL_Error("d2i_RSAPrivateKey"); + throw OpenSSL_Error("d2i_RSAPrivateKey", ERR_get_error()); } size_t signature_length() const override { return ::RSA_size(m_openssl_rsa.get()); } @@ -227,7 +227,7 @@ class OpenSSL_RSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA int rc = ::RSA_private_encrypt(inbuf.size(), inbuf.data(), outbuf.data(), m_openssl_rsa.get(), RSA_NO_PADDING); if(rc < 0) - throw OpenSSL_Error("RSA_private_encrypt"); + throw OpenSSL_Error("RSA_private_encrypt", ERR_get_error()); return outbuf; } @@ -286,20 +286,20 @@ make_openssl_rsa_private_key(RandomNumberGenerator& rng, size_t rsa_bits) std::unique_ptr<BIGNUM, std::function<void (BIGNUM*)>> bn(BN_new(), BN_free); if(!bn) - throw OpenSSL_Error("BN_new"); + throw OpenSSL_Error("BN_new", ERR_get_error()); if(!BN_set_word(bn.get(), RSA_F4)) - throw OpenSSL_Error("BN_set_word"); + throw OpenSSL_Error("BN_set_word", ERR_get_error()); std::unique_ptr<RSA, std::function<void (RSA*)>> rsa(RSA_new(), RSA_free); if(!rsa) - throw OpenSSL_Error("RSA_new"); + throw OpenSSL_Error("RSA_new", ERR_get_error()); if(!RSA_generate_key_ex(rsa.get(), rsa_bits, bn.get(), nullptr)) - throw OpenSSL_Error("RSA_generate_key_ex"); + throw OpenSSL_Error("RSA_generate_key_ex", ERR_get_error()); uint8_t* der = nullptr; int bytes = i2d_RSAPrivateKey(rsa.get(), &der); if(bytes < 0) - throw OpenSSL_Error("i2d_RSAPrivateKey"); + throw OpenSSL_Error("i2d_RSAPrivateKey", ERR_get_error()); const secure_vector<uint8_t> keydata(der, der + bytes); secure_scrub_memory(der, bytes); diff --git a/src/lib/prov/pkcs11/p11.h b/src/lib/prov/pkcs11/p11.h index 597a8e125..99c2d0b33 100644 --- a/src/lib/prov/pkcs11/p11.h +++ b/src/lib/prov/pkcs11/p11.h @@ -2875,6 +2875,8 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_Error : public Exception Exception("PKCS11 error", what) { } + + ErrorType error_type() const noexcept override { return ErrorType::Pkcs11Error; } }; class BOTAN_PUBLIC_API(2,0) PKCS11_ReturnError final : public PKCS11_Error diff --git a/src/lib/prov/pkcs11/p11_ecc_key.h b/src/lib/prov/pkcs11/p11_ecc_key.h index 5522b07ca..9b6fe9240 100644 --- a/src/lib/prov/pkcs11/p11_ecc_key.h +++ b/src/lib/prov/pkcs11/p11_ecc_key.h @@ -186,7 +186,7 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_EC_PrivateKey : public virtual Private_Key, { if(m_public_key.is_zero()) { - throw Exception("Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible."); + throw Invalid_State("Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible."); } return m_public_key; } diff --git a/src/lib/prov/pkcs11/p11_object.h b/src/lib/prov/pkcs11/p11_object.h index 4cacdbfa7..6d6c7b259 100644 --- a/src/lib/prov/pkcs11/p11_object.h +++ b/src/lib/prov/pkcs11/p11_object.h @@ -357,7 +357,7 @@ class BOTAN_PUBLIC_API(2,0) KeyProperties : public StorageObjectProperties */ inline void set_allowed_mechanisms(const std::vector<MechanismType>&) { - throw Exception("Not implemented (KeyProperties::set_allowed_mechanisms)"); + throw Not_Implemented("KeyProperties::set_allowed_mechanisms"); } /// @return the key type of this key object @@ -424,7 +424,7 @@ class BOTAN_PUBLIC_API(2,0) PublicKeyProperties : public KeyProperties */ inline void set_wrap_template(const AttributeContainer&) { - throw Exception("Not implemented (PublicKeyProperties::set_wrap_template)"); + throw Not_Implemented("PublicKeyProperties::set_wrap_template"); } /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key @@ -503,7 +503,7 @@ class BOTAN_PUBLIC_API(2,0) PrivateKeyProperties : public KeyProperties */ inline void set_unwrap_template(const AttributeContainer&) { - throw Exception("Not implemented (PrivateKeyProperties::set_unwrap_template)"); + throw Not_Implemented("PrivateKeyProperties::set_unwrap_template"); } /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key @@ -603,7 +603,7 @@ class BOTAN_PUBLIC_API(2,0) SecretKeyProperties final : public KeyProperties */ inline void set_wrap_template(const AttributeContainer&) { - throw Exception("Not implemented (SecretKeyProperties::set_wrap_template)"); + throw Not_Implemented("SecretKeyProperties::set_wrap_template"); } /** @@ -614,7 +614,7 @@ class BOTAN_PUBLIC_API(2,0) SecretKeyProperties final : public KeyProperties */ inline void set_unwrap_template(const AttributeContainer&) { - throw Exception("Not implemented (SecretKeyProperties::set_unwrap_template)"); + throw Not_Implemented("SecretKeyProperties::set_unwrap_template"); } }; diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h index 7eaf2140c..093bebd62 100644 --- a/src/lib/prov/tpm/tpm.h +++ b/src/lib/prov/tpm/tpm.h @@ -25,6 +25,7 @@ class BOTAN_PUBLIC_API(2,0) TPM_Error final : public Exception { public: TPM_Error(const std::string& err) : Exception(err) {} + ErrorType error_type() const noexcept override { return ErrorType::TPMError; } }; /** diff --git a/src/lib/pubkey/blinding.cpp b/src/lib/pubkey/blinding.cpp index ecd420780..d1f299229 100644 --- a/src/lib/pubkey/blinding.cpp +++ b/src/lib/pubkey/blinding.cpp @@ -35,7 +35,7 @@ BigInt Blinder::blinding_nonce() const BigInt Blinder::blind(const BigInt& i) const { if(!m_reducer.initialized()) - throw Exception("Blinder not initialized, cannot blind"); + throw Invalid_State("Blinder not initialized, cannot blind"); ++m_counter; @@ -58,7 +58,7 @@ BigInt Blinder::blind(const BigInt& i) const BigInt Blinder::unblind(const BigInt& i) const { if(!m_reducer.initialized()) - throw Exception("Blinder not initialized, cannot unblind"); + throw Invalid_State("Blinder not initialized, cannot unblind"); return m_reducer.multiply(i, m_d); } diff --git a/src/lib/pubkey/ec_group/point_gfp.h b/src/lib/pubkey/ec_group/point_gfp.h index fa447bf87..222b5f474 100644 --- a/src/lib/pubkey/ec_group/point_gfp.h +++ b/src/lib/pubkey/ec_group/point_gfp.h @@ -19,23 +19,26 @@ namespace Botan { /** * Exception thrown if you try to convert a zero point to an affine * coordinate +* +* In a future major release this exception type will be removed and its +* usage replaced by Invalid_State */ -class BOTAN_PUBLIC_API(2,0) Illegal_Transformation final : public Exception +class BOTAN_PUBLIC_API(2,0) Illegal_Transformation final : public Invalid_State { public: - explicit Illegal_Transformation(const std::string& err = - "Requested transformation is not possible") : - Exception(err) {} + explicit Illegal_Transformation(const std::string& err) : Invalid_State(err) {} }; /** * Exception thrown if some form of illegal point is decoded +* +* In a future major release this exception type will be removed and its +* usage replaced by Decoding_Error */ -class BOTAN_PUBLIC_API(2,0) Illegal_Point final : public Exception +class BOTAN_PUBLIC_API(2,0) Illegal_Point final : public Decoding_Error { public: - explicit Illegal_Point(const std::string& err = "Malformed ECP point detected") : - Exception(err) {} + explicit Illegal_Point(const std::string& err) : Decoding_Error(err) {} }; /** diff --git a/src/lib/pubkey/mce/gf2m_small_m.cpp b/src/lib/pubkey/mce/gf2m_small_m.cpp index 95187c7af..8a2632b10 100644 --- a/src/lib/pubkey/mce/gf2m_small_m.cpp +++ b/src/lib/pubkey/mce/gf2m_small_m.cpp @@ -59,7 +59,7 @@ const std::vector<gf2m>& exp_table(size_t deg) static std::vector<gf2m> tabs[MAX_EXT_DEG + 1]; if(deg < 2 || deg > MAX_EXT_DEG) - throw Exception("GF2m_Field does not support degree " + std::to_string(deg)); + throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); if(tabs[deg].empty()) tabs[deg] = gf_exp_table(deg, prim_poly[deg]); @@ -84,7 +84,7 @@ const std::vector<gf2m>& log_table(size_t deg) static std::vector<gf2m> tabs[MAX_EXT_DEG + 1]; if(deg < 2 || deg > MAX_EXT_DEG) - throw Exception("GF2m_Field does not support degree " + std::to_string(deg)); + throw Invalid_Argument("GF2m_Field does not support degree " + std::to_string(deg)); if(tabs[deg].empty()) tabs[deg] = gf_log_table(deg, exp_table(deg)); diff --git a/src/lib/pubkey/mceies/mceies.cpp b/src/lib/pubkey/mceies/mceies.cpp index 15706d430..875c9dd10 100644 --- a/src/lib/pubkey/mceies/mceies.cpp +++ b/src/lib/pubkey/mceies/mceies.cpp @@ -83,7 +83,7 @@ mceies_decrypt(const McEliece_PrivateKey& privkey, const size_t nonce_len = aead->default_nonce_length(); if(ct_len < mce_code_bytes + nonce_len + aead->tag_size()) - throw Exception("Input message too small to be valid"); + throw Decoding_Error("Input message too small to be valid"); const secure_vector<uint8_t> mce_key = kem_op.decrypt(ct, mce_code_bytes, 64); @@ -102,7 +102,7 @@ mceies_decrypt(const McEliece_PrivateKey& privkey, } catch(std::exception& e) { - throw Exception("mce_decrypt failed: " + std::string(e.what())); + throw Decoding_Error("mce_decrypt failed: " + std::string(e.what())); } } diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h index 1878a7417..6bab2143e 100644 --- a/src/lib/pubkey/pk_ops_impl.h +++ b/src/lib/pubkey/pk_ops_impl.h @@ -82,7 +82,7 @@ class Verification_with_EMSA : public Verification * @return the message prefix if this signature scheme uses * a message prefix, signaled via has_prefix() */ - virtual secure_vector<uint8_t> message_prefix() const { throw Exception( "No prefix" ); } + virtual secure_vector<uint8_t> message_prefix() const { throw Invalid_State("No prefix"); } /** * @return boolean specifying if this key type supports message @@ -146,7 +146,7 @@ class Signature_with_EMSA : public Signature * @return the message prefix if this signature scheme uses * a message prefix, signaled via has_prefix() */ - virtual secure_vector<uint8_t> message_prefix() const { throw Exception( "No prefix" ); } + virtual secure_vector<uint8_t> message_prefix() const { throw Invalid_State("No prefix"); } std::unique_ptr<EMSA> clone_emsa() const { return std::unique_ptr<EMSA>(m_emsa->clone()); } diff --git a/src/lib/pubkey/pkcs8.cpp b/src/lib/pubkey/pkcs8.cpp index f6d50256d..d299a98a4 100644 --- a/src/lib/pubkey/pkcs8.cpp +++ b/src/lib/pubkey/pkcs8.cpp @@ -105,7 +105,7 @@ secure_vector<uint8_t> PKCS8_decode( if(is_encrypted) { if(OIDS::lookup(pbe_alg_id.get_oid()) != "PBE-PKCS5v20") - throw Exception("Unknown PBE type " + pbe_alg_id.get_oid().as_string()); + throw PKCS8_Exception("Unknown PBE type " + pbe_alg_id.get_oid().as_string()); #if defined(BOTAN_HAS_PKCS5_PBES2) key = pbes2_decrypt(key_data, get_passphrase(), pbe_alg_id.get_parameters()); #else @@ -167,10 +167,13 @@ choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo) } SCAN_Name request(pbe_algo); - if(request.arg_count() != 2) - throw Exception("Unsupported PBE " + pbe_algo); - if(request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2") - throw Exception("Unsupported PBE " + pbe_algo); + + if(request.arg_count() != 2 || + (request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2")) + { + throw Invalid_Argument("Unsupported PBE " + pbe_algo); + } + return std::make_pair(request.arg(0), request.arg(1)); } diff --git a/src/lib/pubkey/xmss/xmss_parameters.cpp b/src/lib/pubkey/xmss/xmss_parameters.cpp index 288b50fdc..b67e5694e 100644 --- a/src/lib/pubkey/xmss/xmss_parameters.cpp +++ b/src/lib/pubkey/xmss/xmss_parameters.cpp @@ -177,8 +177,7 @@ XMSS_Parameters::XMSS_Parameters(xmss_algorithm_t oid) m_wots_oid = XMSS_WOTS_Parameters::ots_algorithm_t::WOTSP_SHAKE256_W16; break; default: - throw Unsupported_Argument( - "Algorithm id does not match any XMSS algorithm id."); + throw Not_Implemented("Algorithm id does not match any known XMSS algorithm id."); break; } } diff --git a/src/lib/pubkey/xmss/xmss_wots_parameters.cpp b/src/lib/pubkey/xmss/xmss_wots_parameters.cpp index 7ba3dad58..c2a324475 100644 --- a/src/lib/pubkey/xmss/xmss_wots_parameters.cpp +++ b/src/lib/pubkey/xmss/xmss_wots_parameters.cpp @@ -75,8 +75,7 @@ XMSS_WOTS_Parameters::XMSS_WOTS_Parameters(ots_algorithm_t oid) m_strength = 512; break; default: - throw Unsupported_Argument( - "Algorithm id does not match any XMSS WOTS algorithm id."); + throw Not_Implemented("Algorithm id does not match any known XMSS WOTS algorithm id."); break; } diff --git a/src/lib/rng/auto_rng/auto_rng.cpp b/src/lib/rng/auto_rng/auto_rng.cpp index 8494f115a..a13429e9b 100644 --- a/src/lib/rng/auto_rng/auto_rng.cpp +++ b/src/lib/rng/auto_rng/auto_rng.cpp @@ -67,7 +67,7 @@ void AutoSeeded_RNG::force_reseed() if(!m_rng->is_seeded()) { - throw Exception("AutoSeeded_RNG reseeding failed"); + throw Internal_Error("AutoSeeded_RNG reseeding failed"); } } diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/lib/rng/rdrand_rng/rdrand_rng.cpp index a3ea25921..ba36c9aac 100644 --- a/src/lib/rng/rdrand_rng/rdrand_rng.cpp +++ b/src/lib/rng/rdrand_rng/rdrand_rng.cpp @@ -18,7 +18,7 @@ namespace Botan { RDRAND_RNG::RDRAND_RNG() { if(!RDRAND_RNG::available()) - throw Exception("Current CPU does not support RDRAND instruction"); + throw Invalid_State("Current CPU does not support RDRAND instruction"); } //static diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp index 2947ac629..743f7c7aa 100644 --- a/src/lib/rng/rng.cpp +++ b/src/lib/rng/rng.cpp @@ -71,7 +71,7 @@ RandomNumberGenerator* RandomNumberGenerator::make_rng() #if defined(BOTAN_HAS_AUTO_SEEDING_RNG) return new AutoSeeded_RNG; #else - throw Exception("make_rng failed, no AutoSeeded_RNG in this build"); + throw Not_Implemented("make_rng failed, no AutoSeeded_RNG in this build"); #endif } @@ -82,7 +82,7 @@ Serialized_RNG::Serialized_RNG() : m_rng(new AutoSeeded_RNG) {} #else Serialized_RNG::Serialized_RNG() { - throw Exception("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); + throw Not_Implemented("Serialized_RNG default constructor failed: AutoSeeded_RNG disabled in build"); } #endif diff --git a/src/lib/rng/stateful_rng/stateful_rng.cpp b/src/lib/rng/stateful_rng/stateful_rng.cpp index 058245d14..80442542f 100644 --- a/src/lib/rng/stateful_rng/stateful_rng.cpp +++ b/src/lib/rng/stateful_rng/stateful_rng.cpp @@ -112,7 +112,7 @@ void Stateful_RNG::reseed_check() if(!is_seeded()) { if(fork_detected) - throw Exception("Detected use of fork but cannot reseed DRBG"); + throw Invalid_State("Detected use of fork but cannot reseed DRBG"); else throw PRNG_Unseeded(name()); } diff --git a/src/lib/rng/system_rng/system_rng.cpp b/src/lib/rng/system_rng/system_rng.cpp index ae027d021..8abf8afdc 100644 --- a/src/lib/rng/system_rng/system_rng.cpp +++ b/src/lib/rng/system_rng/system_rng.cpp @@ -50,7 +50,7 @@ class System_RNG_Impl final : public RandomNumberGenerator { bool success = m_rtlgenrandom(buf, ULONG(len)) == TRUE; if(!success) - throw Exception("RtlGenRandom failed"); + throw System_Error("RtlGenRandom failed"); } void add_entropy(const uint8_t[], size_t) override { /* ignored */ } @@ -79,7 +79,7 @@ class System_RNG_Impl final : public RandomNumberGenerator BCRYPT_RNG_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0); if(ret != STATUS_SUCCESS) - throw Exception("System_RNG failed to acquire crypto provider"); + throw System_Error("System_RNG failed to acquire crypto provider", ret); } ~System_RNG_Impl() @@ -91,7 +91,7 @@ class System_RNG_Impl final : public RandomNumberGenerator { NTSTATUS ret = ::BCryptGenRandom(m_prov, static_cast<PUCHAR>(buf), static_cast<ULONG>(len), 0); if(ret != STATUS_SUCCESS) - throw Exception("System_RNG call to BCryptGenRandom failed"); + throw System_Error("System_RNG call to BCryptGenRandom failed", ret); } void add_entropy(const uint8_t in[], size_t length) override @@ -148,7 +148,7 @@ class System_RNG_Impl final : public RandomNumberGenerator { if(errno == EINTR) continue; - throw Exception("System_RNG getrandom failed error " + std::to_string(errno)); + throw System_Error("System_RNG getrandom failed", errno); } buf += got; @@ -194,7 +194,7 @@ class System_RNG_Impl final : public RandomNumberGenerator } if(m_fd < 0) - throw Exception("System_RNG failed to open RNG device"); + throw System_Error("System_RNG failed to open RNG device", errno); } ~System_RNG_Impl() @@ -224,10 +224,10 @@ void System_RNG_Impl::randomize(uint8_t buf[], size_t len) { if(errno == EINTR) continue; - throw Exception("System_RNG read failed error " + std::to_string(errno)); + throw System_Error("System_RNG read failed", errno); } if(got == 0) - throw Exception("System_RNG EOF on device"); // ?!? + throw System_Error("System_RNG EOF on device"); // ?!? buf += got; len -= got; @@ -264,7 +264,7 @@ void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len) return; // maybe just ignore any failure here and return? - throw Exception("System_RNG write failed error " + std::to_string(errno)); + throw System_Error("System_RNG write failed", errno); } input += got; diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp index e427c0288..8bb01a238 100644 --- a/src/lib/stream/rc4/rc4.cpp +++ b/src/lib/stream/rc4/rc4.cpp @@ -42,7 +42,7 @@ Key_Length_Specification RC4::key_spec() const void RC4::set_iv(const uint8_t*, size_t length) { if(length > 0) - throw Exception("RC4 does not support an IV"); + throw Invalid_IV_Length("RC4", length); } /* diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index a9da82f07..2d303a77e 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -212,7 +212,7 @@ Client_Hello::Client_Hello(Handshake_IO& io, void Client_Hello::update_hello_cookie(const Hello_Verify_Request& hello_verify) { if(!m_version.is_datagram_protocol()) - throw Exception("Cannot use hello cookie with stream protocol"); + throw Invalid_State("Cannot use hello cookie with stream protocol"); m_hello_cookie = hello_verify.cookie(); } diff --git a/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp b/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp index 45b3059f5..1959db266 100644 --- a/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp +++ b/src/lib/tls/sessions_sql/tls_session_manager_sql.cpp @@ -69,14 +69,14 @@ Session_Manager_SQL::Session_Manager_SQL(std::shared_ptr<SQL_Database> db, m_session_key.assign(x.begin() + 2, x.end()); if(check_val_created != check_val_db) - throw Exception("Session database password not valid"); + throw Invalid_Argument("Session database password not valid"); } } else { // maybe just zap the salts + sessions tables in this case? if(salts != 0) - throw Exception("Seemingly corrupted database, multiple salts found"); + throw Internal_Error("Seemingly corrupted TLS session db, multiple salts found"); // new database case diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp index 6919c36ca..28884c1e2 100644 --- a/src/lib/tls/tls_callbacks.cpp +++ b/src/lib/tls/tls_callbacks.cpp @@ -71,7 +71,10 @@ void TLS::Callbacks::tls_verify_cert_chain( ocsp_responses); if(!result.successful_validation()) - throw Exception("Certificate validation failure: " + result.result_string()); + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, + "Certificate validation failure: " + result.result_string()); + } } std::vector<uint8_t> TLS::Callbacks::tls_sign_message( diff --git a/src/lib/tls/tls_cbc/tls_cbc.cpp b/src/lib/tls/tls_cbc/tls_cbc.cpp index 23127642d..7376e655b 100644 --- a/src/lib/tls/tls_cbc/tls_cbc.cpp +++ b/src/lib/tls/tls_cbc/tls_cbc.cpp @@ -129,7 +129,7 @@ std::vector<uint8_t> TLS_CBC_HMAC_AEAD_Mode::assoc_data_with_len(uint16_t len) void TLS_CBC_HMAC_AEAD_Mode::set_associated_data(const uint8_t ad[], size_t ad_len) { if(ad_len != 13) - throw Exception("Invalid TLS AEAD associated data length"); + throw Invalid_Argument("Invalid TLS AEAD associated data length"); m_ad.assign(ad, ad + ad_len); } diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index 37f3ec415..d3d8f899d 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -132,11 +132,11 @@ Handshake_State& Channel::create_handshake_state(Protocol_Version version) Protocol_Version active_version = active->version(); if(active_version.is_datagram_protocol() != version.is_datagram_protocol()) - throw Exception("Active state using version " + - active_version.to_string() + - " cannot change to " + - version.to_string() + - " in pending"); + { + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Active state using version " + active_version.to_string() + + " cannot change to " + version.to_string() + " in pending"); + } } if(!m_sequence_numbers) @@ -190,7 +190,7 @@ void Channel::renegotiate(bool force_full_renegotiation) initiate_handshake(create_handshake_state(active->version()), force_full_renegotiation); else - throw Exception("Cannot renegotiate on inactive connection"); + throw Invalid_State("Cannot renegotiate on inactive connection"); } void Channel::change_cipher_spec_reader(Connection_Side side) @@ -550,7 +550,7 @@ void Channel::send_record_under_epoch(uint16_t epoch, uint8_t record_type, void Channel::send(const uint8_t buf[], size_t buf_size) { if(!is_active()) - throw Exception("Data cannot be sent on inactive TLS connection"); + throw Invalid_State("Data cannot be sent on inactive TLS connection"); send_record_array(sequence_numbers().current_write_epoch(), APPLICATION_DATA, buf, buf_size); @@ -679,7 +679,7 @@ SymmetricKey Channel::key_material_export(const std::string& label, { size_t context_size = context.length(); if(context_size > 0xFFFF) - throw Exception("key_material_export context is too long"); + throw Invalid_Argument("key_material_export context is too long"); salt.push_back(get_byte(0, static_cast<uint16_t>(context_size))); salt.push_back(get_byte(1, static_cast<uint16_t>(context_size))); salt += to_byte_vector(context); @@ -688,7 +688,9 @@ SymmetricKey Channel::key_material_export(const std::string& label, return prf->derive_key(length, master_secret, salt, to_byte_vector(label)); } else - throw Exception("Channel::key_material_export connection not active"); + { + throw Invalid_State("Channel::key_material_export connection not active"); + } } } diff --git a/src/lib/tls/tls_exceptn.h b/src/lib/tls/tls_exceptn.h index 572ff1885..e7d8c1963 100644 --- a/src/lib/tls/tls_exceptn.h +++ b/src/lib/tls/tls_exceptn.h @@ -16,7 +16,7 @@ namespace Botan { namespace TLS { /** -* Exception Base Class +* TLS Exception Base Class */ class BOTAN_PUBLIC_API(2,0) TLS_Exception : public Exception { @@ -27,6 +27,10 @@ class BOTAN_PUBLIC_API(2,0) TLS_Exception : public Exception const std::string& err_msg = "Unknown error") : Exception(err_msg), m_alert_type(type) {} + int error_code() const noexcept override { return static_cast<int>(m_alert_type); } + + ErrorType error_type() const noexcept override { return ErrorType::TLSError; } + private: Alert::Type m_alert_type; }; diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index c2d3ccf26..4c6c32d5d 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -486,7 +486,7 @@ std::vector<uint16_t> Policy::ciphersuite_list(Protocol_Version version, if(ciphersuites.empty()) { - throw Exception("Policy does not allow any available cipher suite"); + throw Invalid_State("Policy does not allow any available cipher suite"); } Ciphersuite_Preference_Ordering order(ciphers, macs, kex, sigs); diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp index b5ea33c07..ae807fcdc 100644 --- a/src/lib/tls/tls_record.cpp +++ b/src/lib/tls/tls_record.cpp @@ -90,7 +90,7 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, else if(our_side == false) m_aead->start(iv.bits_of()); #else - throw Exception("Negotiated disabled TLS CBC+HMAC ciphersuite"); + throw Internal_Error("Negotiated disabled TLS CBC+HMAC ciphersuite"); #endif } else diff --git a/src/lib/tls/tls_seq_numbers.h b/src/lib/tls/tls_seq_numbers.h index 1be280453..85077f5f5 100644 --- a/src/lib/tls/tls_seq_numbers.h +++ b/src/lib/tls/tls_seq_numbers.h @@ -79,7 +79,7 @@ class Datagram_Sequence_Numbers final : public Connection_Sequence_Numbers uint64_t next_read_sequence() override { - throw Exception("DTLS uses explicit sequence numbers"); + throw Invalid_State("DTLS uses explicit sequence numbers"); } bool already_seen(uint64_t sequence) const override diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp index 5c7a4b278..829899fbc 100644 --- a/src/lib/tls/tls_text_policy.cpp +++ b/src/lib/tls/tls_text_policy.cpp @@ -283,7 +283,7 @@ bool Text_Policy::get_bool(const std::string& key, bool def) const } else { - throw Exception("Invalid boolean '" + v + "'"); + throw Decoding_Error("Invalid boolean '" + v + "'"); } } diff --git a/src/lib/utils/assert.cpp b/src/lib/utils/assert.cpp index 31a35374a..b251a469e 100644 --- a/src/lib/utils/assert.cpp +++ b/src/lib/utils/assert.cpp @@ -48,7 +48,7 @@ void assertion_failure(const char* expr_str, format << "@" << file << ":" << line; - throw Exception(format.str()); + throw Internal_Error(format.str()); } } diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp index 1bbcffbdb..b32fe4b3a 100644 --- a/src/lib/utils/dyn_load/dyn_load.cpp +++ b/src/lib/utils/dyn_load/dyn_load.cpp @@ -23,8 +23,11 @@ namespace { void raise_runtime_loader_exception(const std::string& lib_name, const char* msg) { - throw Exception("Failed to load " + lib_name + ": " + - (msg ? msg : "Unknown error")); + const std::string ex_msg = + "Failed to load " + lib_name + ": " + + (msg ? msg : "Unknown error"); + + throw System_Error(ex_msg, 0); } } @@ -70,8 +73,8 @@ void* Dynamically_Loaded_Library::resolve_symbol(const std::string& symbol) #endif if(!addr) - throw Exception("Failed to resolve symbol " + symbol + - " in " + m_lib_name); + throw Invalid_Argument("Failed to resolve symbol " + symbol + + " in " + m_lib_name); return addr; } diff --git a/src/lib/utils/exceptn.cpp b/src/lib/utils/exceptn.cpp index cc6eb9f85..8fc86d3e7 100644 --- a/src/lib/utils/exceptn.cpp +++ b/src/lib/utils/exceptn.cpp @@ -105,6 +105,10 @@ Stream_IO_Error::Stream_IO_Error(const std::string& err) : Exception("I/O error: " + err) {} +System_Error::System_Error(const std::string& msg, int err_code) : + Exception(msg + " error code " + std::to_string(err_code)) + {} + Self_Test_Failure::Self_Test_Failure(const std::string& err) : Internal_Error("Self test failed: " + err) {} diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h index dfe428d72..bfff85618 100644 --- a/src/lib/utils/exceptn.h +++ b/src/lib/utils/exceptn.h @@ -1,6 +1,6 @@ /* * Exceptions -* (C) 1999-2009 Jack Lloyd +* (C) 1999-2009,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -15,22 +15,104 @@ namespace Botan { /** +* Different types of errors that might occur +*/ +enum class ErrorType { + /** Some unknown error */ + Unknown = 1, + /** An error while calling a system interface */ + SystemError, + /** An operation seems valid, but not supported by the current version */ + NotImplemented, + /** Memory allocation failure */ + OutOfMemory, + /** An internal error occurred */ + InternalError, + /** An I/O error occurred */ + IoError, + + /** Invalid object state */ + InvalidObjectState = 100, + /** A key was not set on an object when this is required */ + KeyNotSet, + /** The application provided an argument which is invalid */ + InvalidArgument, + /** A key with invalid length was provided */ + InvalidKeyLength, + /** A nonce with invalid length was provided */ + InvalidNonceLength, + /** An object type was requested but cannot be found */ + LookupError, + /** Encoding a message or datum failed */ + EncodingFailure, + /** Decoding a message or datum failed */ + DecodingFailure, + /** A TLS error (error_code will be the alert type) */ + TLSError, + /** An error during an HTTP operation */ + HttpError, + + /** An error when calling OpenSSL */ + OpenSSLError = 200, + /** An error when interacting with CommonCrypto API */ + CommonCryptoError, + /** An error when interacting with a PKCS11 device */ + Pkcs11Error, + /** An error when interacting with a TPM device */ + TPMError, + + /** An error when interacting with zlib */ + ZlibError = 300, + /** An error when interacting with bzip2 */ + Bzip2Error, + /** An error when interacting with lzma */ + LzmaError, + +}; + +/** * Base class for all exceptions thrown by the library */ class BOTAN_PUBLIC_API(2,0) Exception : public std::exception { public: - Exception(const char* prefix, const std::string& msg); - explicit Exception(const std::string& msg); + /** + * Return a descriptive string which is hopefully comprehensible to + * a developer. It will likely not be useful for an end user. + * + * The string has no particular format, and the content of exception + * messages may change from release to release. Thus the main use of this + * function is for logging or debugging. + */ const char* what() const noexcept override { return m_msg.c_str(); } + + /** + * Return the "type" of error which occurred. + */ + virtual ErrorType error_type() const noexcept { return Botan::ErrorType::Unknown; } + + /** + * Return an error code associated with this exception, or otherwise 0. + * + * The domain of this error varies depending on the source, for example on + * POSIX systems it might be errno, while on a Windows system it might be + * the result of GetLastError or WSAGetLastError. For error_type() is + * OpenSSLError, it will (if nonzero) be an OpenSSL error code from + * ERR_get_error. + */ + virtual int error_code() const noexcept { return 0; } + protected: + explicit Exception(const std::string& msg); + Exception(const char* prefix, const std::string& msg); Exception(const std::string& msg, const std::exception& e); + private: std::string m_msg; }; /** -* An invalid argument +* An invalid argument was provided to an API call. */ class BOTAN_PUBLIC_API(2,0) Invalid_Argument : public Exception { @@ -40,95 +122,126 @@ class BOTAN_PUBLIC_API(2,0) Invalid_Argument : public Exception explicit Invalid_Argument(const std::string& msg, const std::string& where); Invalid_Argument(const std::string& msg, const std::exception& e); + + ErrorType error_type() const noexcept override { return ErrorType::InvalidArgument; } }; /** -* Unsupported_Argument Exception -* -* An argument that is invalid because it is not supported by Botan. -* It might or might not be valid in another context like a standard. +* An invalid key length was used */ -class BOTAN_PUBLIC_API(2,0) Unsupported_Argument final : public Invalid_Argument +class BOTAN_PUBLIC_API(2,0) Invalid_Key_Length final : public Invalid_Argument { public: - explicit Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {} + Invalid_Key_Length(const std::string& name, size_t length); + ErrorType error_type() const noexcept override { return ErrorType::InvalidKeyLength; } }; /** -* Invalid_State Exception +* An invalid nonce length was used */ -class BOTAN_PUBLIC_API(2,0) Invalid_State : public Exception +class BOTAN_PUBLIC_API(2,0) Invalid_IV_Length final : public Invalid_Argument { public: - explicit Invalid_State(const std::string& err) : Exception(err) {} + Invalid_IV_Length(const std::string& mode, size_t bad_len); + ErrorType error_type() const noexcept override { return ErrorType::InvalidNonceLength; } }; -class BOTAN_PUBLIC_API(2,4) Key_Not_Set : public Invalid_State +/** +* Invalid_Algorithm_Name Exception +*/ +class BOTAN_PUBLIC_API(2,0) Invalid_Algorithm_Name final : public Invalid_Argument { public: - explicit Key_Not_Set(const std::string& algo); + explicit Invalid_Algorithm_Name(const std::string& name); }; /** -* Lookup_Error Exception +* Encoding_Error Exception +* +* This exception derives from Invalid_Argument for historical reasons, and it +* does not make any real sense for it to do so. In a future major release this +* exception type will derive directly from Exception instead. */ -class BOTAN_PUBLIC_API(2,0) Lookup_Error : public Exception +class BOTAN_PUBLIC_API(2,0) Encoding_Error final : public Invalid_Argument { public: - explicit Lookup_Error(const std::string& err) : Exception(err) {} + explicit Encoding_Error(const std::string& name); - Lookup_Error(const std::string& type, - const std::string& algo, - const std::string& provider); + ErrorType error_type() const noexcept override { return ErrorType::EncodingFailure; } }; /** -* Internal_Error Exception +* A decoding error occurred. +* +* This exception derives from Invalid_Argument for historical reasons, and it +* does not make any real sense for it to do so. In a future major release this +* exception type will derive directly from Exception instead. */ -class BOTAN_PUBLIC_API(2,0) Internal_Error : public Exception +class BOTAN_PUBLIC_API(2,0) Decoding_Error : public Invalid_Argument { public: - explicit Internal_Error(const std::string& err); + explicit Decoding_Error(const std::string& name); + + Decoding_Error(const std::string& name, const char* exception_message); + + Decoding_Error(const std::string& msg, const std::exception& e); + + ErrorType error_type() const noexcept override { return ErrorType::DecodingFailure; } }; /** -* Invalid_Key_Length Exception +* Invalid state was encountered. A request was made on an object while the +* object was in a state where the operation cannot be performed. */ -class BOTAN_PUBLIC_API(2,0) Invalid_Key_Length final : public Invalid_Argument +class BOTAN_PUBLIC_API(2,0) Invalid_State : public Exception { public: - Invalid_Key_Length(const std::string& name, size_t length); + explicit Invalid_State(const std::string& err) : Exception(err) {} + + ErrorType error_type() const noexcept override { return ErrorType::InvalidObjectState; } }; /** -* Invalid_IV_Length Exception +* A PRNG was called on to produce output while still unseeded */ -class BOTAN_PUBLIC_API(2,0) Invalid_IV_Length final : public Invalid_Argument +class BOTAN_PUBLIC_API(2,0) PRNG_Unseeded final : public Invalid_State { public: - Invalid_IV_Length(const std::string& mode, size_t bad_len); + explicit PRNG_Unseeded(const std::string& algo); }; /** -* PRNG_Unseeded Exception +* The key was not set on an object. This occurs with symmetric objects where +* an operation which requires the key is called prior to set_key being called. */ -class BOTAN_PUBLIC_API(2,0) PRNG_Unseeded final : public Invalid_State +class BOTAN_PUBLIC_API(2,4) Key_Not_Set : public Invalid_State { public: - explicit PRNG_Unseeded(const std::string& algo); + explicit Key_Not_Set(const std::string& algo); + + ErrorType error_type() const noexcept override { return ErrorType::KeyNotSet; } }; /** -* Policy_Violation Exception +* A request was made for some kind of object which could not be located */ -class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State +class BOTAN_PUBLIC_API(2,0) Lookup_Error : public Exception { public: - BOTAN_DEPRECATED("deprecated") explicit Policy_Violation(const std::string& err); + explicit Lookup_Error(const std::string& err) : Exception(err) {} + + Lookup_Error(const std::string& type, + const std::string& algo, + const std::string& provider); + + ErrorType error_type() const noexcept override { return ErrorType::LookupError; } }; /** * Algorithm_Not_Found Exception +* +* @warning This exception type will be removed in the future. Instead +* just catch Lookup_Error. */ class BOTAN_PUBLIC_API(2,0) Algorithm_Not_Found final : public Lookup_Error { @@ -137,66 +250,98 @@ class BOTAN_PUBLIC_API(2,0) Algorithm_Not_Found final : public Lookup_Error }; /** -* No_Provider_Found Exception +* Provider_Not_Found is thrown when a specific provider was requested +* but that provider is not available. +* +* @warning This exception type will be removed in the future. Instead +* just catch Lookup_Error. */ -class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception +class BOTAN_PUBLIC_API(2,0) Provider_Not_Found final : public Lookup_Error { public: - BOTAN_DEPRECATED("deprecated") explicit No_Provider_Found(const std::string& name); + Provider_Not_Found(const std::string& algo, const std::string& provider); }; /** -* Provider_Not_Found is thrown when a specific provider was requested -* but that provider is not available. +* An AEAD or MAC check detected a message modification */ -class BOTAN_PUBLIC_API(2,0) Provider_Not_Found final : public Lookup_Error +class BOTAN_PUBLIC_API(2,0) Integrity_Failure final : public Exception { public: - Provider_Not_Found(const std::string& algo, const std::string& provider); + explicit Integrity_Failure(const std::string& msg); + + ErrorType error_type() const noexcept override { return ErrorType::DecodingFailure; } }; /** -* Invalid_Algorithm_Name Exception +* An error occurred while operating on an IO stream */ -class BOTAN_PUBLIC_API(2,0) Invalid_Algorithm_Name final : public Invalid_Argument +class BOTAN_PUBLIC_API(2,0) Stream_IO_Error final : public Exception { public: - explicit Invalid_Algorithm_Name(const std::string& name); + explicit Stream_IO_Error(const std::string& err); + + ErrorType error_type() const noexcept override { return ErrorType::IoError; } }; /** -* Encoding_Error Exception +* System_Error +* +* This exception is thrown in the event of an error related to interacting +* with the operating system. +* +* This exception type also (optionally) captures an integer error code eg +* POSIX errno or Windows GetLastError. */ -class BOTAN_PUBLIC_API(2,0) Encoding_Error final : public Invalid_Argument +class BOTAN_PUBLIC_API(2,9) System_Error : public Exception { public: - explicit Encoding_Error(const std::string& name); + System_Error(const std::string& msg) : Exception(msg), m_error_code(0) {} + + System_Error(const std::string& msg, int err_code); + + ErrorType error_type() const noexcept override { return ErrorType::SystemError; } + + int error_code() const noexcept override { return m_error_code; } + + private: + int m_error_code; }; /** -* Decoding_Error Exception +* An internal error occurred. If observed, please file a bug. */ -class BOTAN_PUBLIC_API(2,0) Decoding_Error : public Invalid_Argument +class BOTAN_PUBLIC_API(2,0) Internal_Error : public Exception { public: - explicit Decoding_Error(const std::string& name); - - Decoding_Error(const std::string& name, const char* exception_message); + explicit Internal_Error(const std::string& err); - Decoding_Error(const std::string& msg, const std::exception& e); + ErrorType error_type() const noexcept override { return ErrorType::InternalError; } }; /** -* Integrity_Failure Exception +* Not Implemented Exception +* +* This is thrown in the situation where a requested operation is +* logically valid but is not implemented by this version of the library. */ -class BOTAN_PUBLIC_API(2,0) Integrity_Failure final : public Exception +class BOTAN_PUBLIC_API(2,0) Not_Implemented final : public Exception { public: - explicit Integrity_Failure(const std::string& msg); + explicit Not_Implemented(const std::string& err); + + ErrorType error_type() const noexcept override { return ErrorType::NotImplemented; } }; +/* + The following exception types are still in use for compatability reasons, + but are deprecated and will be removed in a future major release +*/ + /** -* Invalid_OID Exception +* An invalid OID string was used. +* +* This exception will be removed in a future major release. */ class BOTAN_PUBLIC_API(2,0) Invalid_OID final : public Decoding_Error { @@ -204,33 +349,58 @@ class BOTAN_PUBLIC_API(2,0) Invalid_OID final : public Decoding_Error explicit Invalid_OID(const std::string& oid); }; +/* + The following exception types are deprecated, no longer used, + and will be removed in a future major release +*/ + /** -* Stream_IO_Error Exception +* Self Test Failure Exception */ -class BOTAN_PUBLIC_API(2,0) Stream_IO_Error final : public Exception +class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error { public: - explicit Stream_IO_Error(const std::string& err); + BOTAN_DEPRECATED("no longer used") explicit Self_Test_Failure(const std::string& err); }; /** -* Self Test Failure Exception +* No_Provider_Found Exception */ -class BOTAN_PUBLIC_API(2,0) Self_Test_Failure final : public Internal_Error +class BOTAN_PUBLIC_API(2,0) No_Provider_Found final : public Exception { public: - BOTAN_DEPRECATED("deprecated") explicit Self_Test_Failure(const std::string& err); + BOTAN_DEPRECATED("no longer used") explicit No_Provider_Found(const std::string& name); }; /** -* Not Implemented Exception +* Policy_Violation Exception */ -class BOTAN_PUBLIC_API(2,0) Not_Implemented final : public Exception +class BOTAN_PUBLIC_API(2,0) Policy_Violation final : public Invalid_State { public: - explicit Not_Implemented(const std::string& err); + BOTAN_DEPRECATED("no longer used") explicit Policy_Violation(const std::string& err); + }; + +/** +* Unsupported_Argument Exception +* +* An argument that is invalid because it is not supported by Botan. +* It might or might not be valid in another context like a standard. +* +* This exception is no longer used, instead Not_Implemented is thrown. +*/ +class BOTAN_PUBLIC_API(2,0) Unsupported_Argument final : public Invalid_Argument + { + public: + BOTAN_DEPRECATED("no longer used") explicit Unsupported_Argument(const std::string& msg) : Invalid_Argument(msg) {} }; +template<typename E, typename... Args> +inline void do_throw_error(const char* file, int line, const char* func, Args... args) + { + throw E(file, line, func, args...); + } + } #endif diff --git a/src/lib/utils/http_util/http_util.cpp b/src/lib/utils/http_util/http_util.cpp index f5f9c0213..3fd08b5b8 100644 --- a/src/lib/utils/http_util/http_util.cpp +++ b/src/lib/utils/http_util/http_util.cpp @@ -36,7 +36,7 @@ std::string http_transact(const std::string& hostname, { socket = OS::open_socket(hostname, "http", timeout); if(!socket) - throw Exception("No socket support enabled in build"); + throw Not_Implemented("No socket support enabled in build"); } catch(std::exception& e) { diff --git a/src/lib/utils/http_util/http_util.h b/src/lib/utils/http_util/http_util.h index 9edd3d983..92a67e42b 100644 --- a/src/lib/utils/http_util/http_util.h +++ b/src/lib/utils/http_util/http_util.h @@ -20,6 +20,20 @@ namespace Botan { namespace HTTP { +/** +* HTTP_Error Exception +*/ +class BOTAN_PUBLIC_API(2,0) HTTP_Error final : public Exception + { + public: + explicit HTTP_Error(const std::string& msg) : + Exception("HTTP error " + msg) + {} + + ErrorType error_type() const noexcept override { return ErrorType::HttpError; } + + }; + class Response final { public: @@ -44,7 +58,7 @@ class Response final void throw_unless_ok() { if(status_code() != 200) - throw Exception("HTTP error: " + status_message()); + throw HTTP_Error(status_message()); } private: @@ -54,17 +68,6 @@ class Response final std::map<std::string, std::string> m_headers; }; -/** -* HTTP_Error Exception -*/ -class BOTAN_PUBLIC_API(2,0) HTTP_Error final : public Exception - { - public: - explicit HTTP_Error(const std::string& msg) : - Exception("HTTP error " + msg) - {} - }; - BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& o, const Response& resp); typedef std::function<std::string (const std::string&, const std::string&)> http_exch_fn; diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp index 0d98df867..ab9c73b0c 100644 --- a/src/lib/utils/os_utils.cpp +++ b/src/lib/utils/os_utils.cpp @@ -430,7 +430,7 @@ int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn) int rc = ::sigaction(SIGILL, &sigaction, &old_sigaction); if(rc != 0) - throw Exception("run_cpu_instruction_probe sigaction failed"); + throw System_Error("run_cpu_instruction_probe sigaction failed", errno); rc = sigsetjmp(g_sigill_jmp_buf, /*save sigs*/1); @@ -448,7 +448,7 @@ int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn) // Restore old SIGILL handler, if any rc = ::sigaction(SIGILL, &old_sigaction, nullptr); if(rc != 0) - throw Exception("run_cpu_instruction_probe sigaction restore failed"); + throw System_Error("run_cpu_instruction_probe sigaction restore failed", errno); #elif defined(BOTAN_TARGET_OS_IS_WINDOWS) && defined(BOTAN_TARGET_COMPILER_IS_MSVC) diff --git a/src/lib/utils/read_cfg.cpp b/src/lib/utils/read_cfg.cpp index bf68c0479..02f2e0ac8 100644 --- a/src/lib/utils/read_cfg.cpp +++ b/src/lib/utils/read_cfg.cpp @@ -49,7 +49,7 @@ std::map<std::string, std::string> read_cfg(std::istream& is) auto eq = s.find("="); if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) - throw Exception("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); + throw Decoding_Error("Bad read_cfg input '" + s + "' on line " + std::to_string(line)); const std::string key = clean_ws(s.substr(0, eq)); const std::string val = clean_ws(s.substr(eq + 1, std::string::npos)); diff --git a/src/lib/utils/safeint.h b/src/lib/utils/safeint.h index 377f13418..5c9ea4955 100644 --- a/src/lib/utils/safeint.h +++ b/src/lib/utils/safeint.h @@ -19,6 +19,8 @@ class BOTAN_PUBLIC_API(2,0) Integer_Overflow_Detected final : public Exception Integer_Overflow_Detected(const std::string& file, int line) : Exception("Integer overflow detected at " + file + ":" + std::to_string(line)) {} + + ErrorType error_type() const noexcept override { return ErrorType::InternalError; } }; inline size_t checked_add(size_t x, size_t y, const char* file, int line) diff --git a/src/lib/utils/socket/socket.cpp b/src/lib/utils/socket/socket.cpp index 39ffc7951..c9c37f2bb 100644 --- a/src/lib/utils/socket/socket.cpp +++ b/src/lib/utils/socket/socket.cpp @@ -73,7 +73,7 @@ class Asio_Socket final : public OS::Socket if(ec) throw boost::system::system_error(ec); if(ec || m_tcp.is_open() == false) - throw Exception("Connection to host " + hostname + " failed"); + throw System_Error("Connection to host " + hostname + " failed"); } void write(const uint8_t buf[], size_t len) override @@ -166,13 +166,13 @@ class BSD_Socket final : public OS::Socket if (::WSAStartup(wsa_version, &wsa_data) != 0) { - throw Exception("WSAStartup() failed: " + std::to_string(WSAGetLastError())); + throw System_Error("WSAStartup() failed", WSAGetLastError()); } if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) { ::WSACleanup(); - throw Exception("Could not find a usable version of Winsock.dll"); + throw System_Error("Could not find a usable version of Winsock.dll"); } } @@ -190,7 +190,7 @@ class BSD_Socket final : public OS::Socket static void set_nonblocking(socket_type s) { if(::fcntl(s, F_SETFL, O_NONBLOCK) < 0) - throw Exception("Setting socket to non-blocking state failed"); + throw System_Error("Setting socket to non-blocking state failed", errno); } static void socket_init() {} @@ -212,9 +212,11 @@ class BSD_Socket final : public OS::Socket hints.ai_socktype = SOCK_STREAM; addrinfo* res; - if(::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res) != 0) + int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res); + + if(rc != 0) { - throw Exception("Name resolution failed for " + hostname); + throw System_Error("Name resolution failed for " + hostname, rc); } for(addrinfo* rp = res; (m_socket == invalid_socket()) && (rp != nullptr); rp = rp->ai_next) @@ -252,7 +254,7 @@ class BSD_Socket final : public OS::Socket socklen_t len = sizeof(socket_error); if(::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&socket_error), &len) < 0) - throw Exception("Error calling getsockopt"); + throw System_Error("Error calling getsockopt", errno); if(socket_error != 0) { @@ -274,8 +276,8 @@ class BSD_Socket final : public OS::Socket if(m_socket == invalid_socket()) { - throw Exception("Connecting to " + hostname + - " for service " + service + " failed"); + throw System_Error("Connecting to " + hostname + + " for service " + service + " failed", errno); } } @@ -299,13 +301,12 @@ class BSD_Socket final : public OS::Socket int active = ::select(m_socket + 1, nullptr, &write_set, nullptr, &timeout); if(active == 0) - throw Exception("Timeout during socket write"); + throw System_Error("Timeout during socket write"); const size_t left = len - sent_so_far; socket_op_ret_type sent = ::send(m_socket, cast_uint8_ptr_to_char(&buf[sent_so_far]), left, 0); if(sent < 0) - throw Exception("Socket write failed with error '" + - std::string(::strerror(errno)) + "'"); + throw System_Error("Socket write failed", errno); else sent_so_far += static_cast<size_t>(sent); } @@ -321,13 +322,13 @@ class BSD_Socket final : public OS::Socket int active = ::select(m_socket + 1, &read_set, nullptr, nullptr, &timeout); if(active == 0) - throw Exception("Timeout during socket read"); + throw System_Error("Timeout during socket read"); socket_op_ret_type got = ::recv(m_socket, cast_uint8_ptr_to_char(buf), len, 0); if(got < 0) - throw Exception("Socket read failed with error '" + - std::string(::strerror(errno)) + "'"); + throw System_Error("Socket read failed", errno); + return static_cast<size_t>(got); } diff --git a/src/lib/x509/key_constraint.cpp b/src/lib/x509/key_constraint.cpp index dfadedac5..95a59d65f 100644 --- a/src/lib/x509/key_constraint.cpp +++ b/src/lib/x509/key_constraint.cpp @@ -93,7 +93,7 @@ void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, if((constraints & permitted) != constraints) { - throw Exception("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); + throw Invalid_Argument("Invalid " + name + " constraints " + key_constraints_to_string(constraints)); } } diff --git a/src/lib/x509/key_constraint.h b/src/lib/x509/key_constraint.h index 3d456f6c4..75f9fb82f 100644 --- a/src/lib/x509/key_constraint.h +++ b/src/lib/x509/key_constraint.h @@ -37,7 +37,7 @@ class Public_Key; * Check that key constraints are permitted for a specific public key. * @param pub_key the public key on which the constraints shall be enforced on * @param constraints the constraints that shall be enforced on the key -* @throw Exception if the given constraints are not permitted for this key +* @throw Invalid_Argument if the given constraints are not permitted for this key */ BOTAN_PUBLIC_API(2,0) void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, Key_Constraints constraints); diff --git a/src/lib/x509/ocsp.cpp b/src/lib/x509/ocsp.cpp index 115c4117a..62d814702 100644 --- a/src/lib/x509/ocsp.cpp +++ b/src/lib/x509/ocsp.cpp @@ -106,8 +106,11 @@ Response::Response(const uint8_t response_bits[], size_t response_bits_len) : response_outer.decode(resp_status, ENUMERATED, UNIVERSAL); + /* + * FIXME: properly decode error responses + */ if(resp_status != 0) - throw Exception("OCSP response status " + std::to_string(resp_status)); + throw Decoding_Error("OCSP response status " + std::to_string(resp_status)); if(response_outer.more_items()) { diff --git a/src/lib/x509/x509_crl.h b/src/lib/x509/x509_crl.h index 89925aa04..d52c98e9a 100644 --- a/src/lib/x509/x509_crl.h +++ b/src/lib/x509/x509_crl.h @@ -28,12 +28,15 @@ class BOTAN_PUBLIC_API(2,0) X509_CRL final : public X509_Object public: /** * This class represents CRL related errors. + * + * In a future major release this exception type will be removed and + * replaced with Decoding_Error */ - class BOTAN_PUBLIC_API(2,0) X509_CRL_Error final : public Exception + class BOTAN_PUBLIC_API(2,0) X509_CRL_Error final : public Decoding_Error { public: explicit X509_CRL_Error(const std::string& error) : - Exception("X509_CRL: " + error) {} + Decoding_Error("X509_CRL: " + error) {} }; /** diff --git a/src/lib/x509/x509_ext.h b/src/lib/x509/x509_ext.h index 48a9f338c..11e14e8d6 100644 --- a/src/lib/x509/x509_ext.h +++ b/src/lib/x509/x509_ext.h @@ -115,7 +115,7 @@ class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object } else { - throw Exception("Exception::get_extension_object_as dynamic_cast failed"); + throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); } } diff --git a/src/lib/x509/x509_obj.cpp b/src/lib/x509/x509_obj.cpp index 49d7fcc60..6c591bde7 100644 --- a/src/lib/x509/x509_obj.cpp +++ b/src/lib/x509/x509_obj.cpp @@ -170,7 +170,7 @@ std::string X509_Object::hash_used_for_signature() const bool X509_Object::check_signature(const Public_Key* pub_key) const { if(!pub_key) - throw Exception("No key provided for " + PEM_label() + " signature check"); + throw Invalid_Argument("No key provided for " + PEM_label() + " signature check"); std::unique_ptr<const Public_Key> key(pub_key); return check_signature(*key); } diff --git a/src/lib/x509/x509path.cpp b/src/lib/x509/x509path.cpp index 8e459e9d2..9fed87f60 100644 --- a/src/lib/x509/x509path.cpp +++ b/src/lib/x509/x509path.cpp @@ -452,7 +452,7 @@ PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate> { // Avoid creating a thread for this case future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const X509_CRL> { - throw Exception("No CRL distribution point for this certificate"); + throw Not_Implemented("No CRL distribution point for this certificate"); })); } else @@ -741,7 +741,7 @@ PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const if(cert_paths_out.empty()) { if(stats.empty()) - throw Exception("X509 path building failed for unknown reasons"); + throw Internal_Error("X509 path building failed for unknown reasons"); else // arbitrarily return the first error return stats[0]; @@ -1005,9 +1005,9 @@ Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status const X509_Certificate& Path_Validation_Result::trust_root() const { if(m_cert_path.empty()) - throw Exception("Path_Validation_Result::trust_root no path set"); + throw Invalid_State("Path_Validation_Result::trust_root no path set"); if(result() != Certificate_Status_Code::VERIFIED) - throw Exception("Path_Validation_Result::trust_root meaningless with invalid status"); + throw Invalid_State("Path_Validation_Result::trust_root meaningless with invalid status"); return *m_cert_path[m_cert_path.size()-1]; } diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 6777f85f4..180daf1d4 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -102,7 +102,7 @@ int main(int argc, char* argv[]) #if defined(BOTAN_HAS_OPENSSL) if(opts.provider().empty() || opts.provider() == "openssl") { - ::ERR_free_strings(); + ERR_free_strings(); ::ERR_remove_thread_state(nullptr); } #endif diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index aca2dbfb9..50c85eff6 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -214,12 +214,12 @@ class FFI_Unit_Tests final : public Test TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size())); TEST_FFI_OK(botan_rng_reseed, (rng, 256)); - TEST_FFI_RC(-20, botan_rng_reseed_from_rng, (rng, null_rng, 256)); + TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_reseed_from_rng, (rng, null_rng, 256)); if(rdrand_rng) { TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, rdrand_rng, 256)); } - TEST_FFI_RC(-20, botan_rng_get, (null_rng, outbuf.data(), outbuf.size())); + TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_get, (null_rng, outbuf.data(), outbuf.size())); TEST_FFI_OK(botan_rng_destroy, (rng)); } diff --git a/src/tests/test_pkcs11_low_level.cpp b/src/tests/test_pkcs11_low_level.cpp index ffe9dfc20..6dbd6ac0c 100644 --- a/src/tests/test_pkcs11_low_level.cpp +++ b/src/tests/test_pkcs11_low_level.cpp @@ -74,7 +74,7 @@ class RAII_LowLevel if(slots.empty()) { - throw Exception("No slot with attached token found"); + throw Test_Error("No slot with attached token found"); } return slots; @@ -100,7 +100,7 @@ class RAII_LowLevel { if(!m_is_session_open) { - throw Exception("no open session"); + throw Test_Error("no open session"); } return m_session_handle; } @@ -109,7 +109,7 @@ class RAII_LowLevel { if(!m_is_session_open) { - throw Exception("no open session"); + throw Test_Error("no open session"); } m_low_level.get()->C_CloseSession(m_session_handle); @@ -120,12 +120,12 @@ class RAII_LowLevel { if(!m_is_session_open) { - throw Exception("no open session"); + throw Test_Error("no open session"); } if(m_is_logged_in) { - throw Exception("Already logged in"); + throw Test_Error("Already logged in"); } m_low_level.get()->C_Login(m_session_handle, user_type, pin); @@ -136,7 +136,7 @@ class RAII_LowLevel { if(!m_is_logged_in) { - throw Exception("Not logged in"); + throw Test_Error("Not logged in"); } m_low_level.get()->C_Logout(m_session_handle); diff --git a/src/tests/test_rng.cpp b/src/tests/test_rng.cpp index 0b316335e..a7510b650 100644 --- a/src/tests/test_rng.cpp +++ b/src/tests/test_rng.cpp @@ -150,7 +150,7 @@ class Stateful_RNG_Tests : public Test size_t poll(Botan::RandomNumberGenerator&) override { - throw Botan::Exception("polling not available"); + throw Botan::Not_Implemented("polling not available"); } }; diff --git a/src/tests/test_rng.h b/src/tests/test_rng.h index 822536971..01fe89c92 100644 --- a/src/tests/test_rng.h +++ b/src/tests/test_rng.h @@ -122,7 +122,7 @@ class Fixed_Output_Position_RNG final : public Fixed_Output_RNG void add_entropy(const uint8_t*, size_t) override { - throw Botan::Exception("add_entropy() not supported by this RNG, test bug?"); + throw Test_Error("add_entropy() not supported by this RNG, test bug?"); } std::string name() const override @@ -148,7 +148,7 @@ class SeedCapturing_RNG final : public Botan::RandomNumberGenerator public: void randomize(uint8_t[], size_t) override { - throw Botan::Exception("SeedCapturing_RNG has no output"); + throw Test_Error("SeedCapturing_RNG has no output"); } bool accepts_input() const override { return true; } diff --git a/src/tests/test_tests.cpp b/src/tests/test_tests.cpp index 49a05d6ab..a7324eef8 100644 --- a/src/tests/test_tests.cpp +++ b/src/tests/test_tests.cpp @@ -143,7 +143,7 @@ class Test_Tests final : public Test { Test::Result test_result(testcase_name); test_result.test_throws("test_throws", "expected msg", - []() { throw Botan::Exception("not the message"); }); + []() { throw std::runtime_error("not the message"); }); verify_failure("test_throws", result, test_result); } diff --git a/src/tests/test_tss.cpp b/src/tests/test_tss.cpp index 714f08df6..139e2087d 100644 --- a/src/tests/test_tss.cpp +++ b/src/tests/test_tss.cpp @@ -40,8 +40,8 @@ class TSS_Recovery_Tests final : public Text_Based_Test shares.push_back(Botan::RTSS_Share(v.data(), v.size())); } - auto reconstructed_secret = Botan::RTSS_Share::reconstruct(shares); - result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret, input); + auto reconstructed_secret_all = Botan::RTSS_Share::reconstruct(shares); + result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret_all, input); if(header == "Invalid") result.test_failure("Invalid shares should not result in recovery"); @@ -127,8 +127,8 @@ class TSS_Generation_Tests final : public Text_Based_Test result.test_eq("Expected share", shares[i].data(), expected_shares[i]); } - auto reconstructed_secret = Botan::RTSS_Share::reconstruct(shares); - result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret, input); + auto reconstructed_secret_all = Botan::RTSS_Share::reconstruct(shares); + result.test_eq("Reconstructed secret correctly from all shares", reconstructed_secret_all, input); if(N != M) { diff --git a/src/tests/test_x509_path.cpp b/src/tests/test_x509_path.cpp index 57f2d8602..e86c7b70f 100644 --- a/src/tests/test_x509_path.cpp +++ b/src/tests/test_x509_path.cpp @@ -634,19 +634,17 @@ std::vector<Test::Result> BSI_Path_Validation_Tests::run() /* Some certificates are rejected when executing the X509_Certificate constructor * by throwing a Decoding_Error exception. */ - catch(const Botan::Decoding_Error& d) + catch(const Botan::Exception& e) { - result.test_eq(test_name + " path validation result", d.what(), - expected_result); - } - catch(const Botan::X509_CRL::X509_CRL_Error& e) - { - result.test_eq(test_name + " path validation result", e.what(), - expected_result); - } - catch(const std::exception& e) - { - result.test_failure(test_name, e.what()); + if(e.error_type() == Botan::ErrorType::DecodingFailure) + { + result.test_eq(test_name + " path validation result", e.what(), + expected_result); + } + else + { + result.test_failure(test_name, e.what()); + } } result.end_timer(); diff --git a/src/tests/tests.h b/src/tests/tests.h index 7a0e4e54e..d21acf6f9 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -45,6 +45,7 @@ class Test_Error final : public Botan::Exception { public: explicit Test_Error(const std::string& what) : Exception("Test error", what) {} + Botan::ErrorType error_type() const noexcept override { return Botan::ErrorType::Unknown; } }; class Test_Options |