diff options
-rwxr-xr-x | configure.py | 2 | ||||
-rw-r--r-- | news.rst | 2 | ||||
-rw-r--r-- | src/lib/hash/hash.cpp | 20 | ||||
-rw-r--r-- | src/lib/prov/commoncrypto/commoncrypto.h | 36 | ||||
-rw-r--r-- | src/lib/prov/commoncrypto/commoncrypto_hash.cpp | 139 | ||||
-rw-r--r-- | src/lib/prov/commoncrypto/info.txt | 9 | ||||
-rw-r--r-- | src/tests/test_pubkey.cpp | 4 |
7 files changed, 206 insertions, 6 deletions
diff --git a/configure.py b/configure.py index b03802e56..24f74e134 100755 --- a/configure.py +++ b/configure.py @@ -523,7 +523,7 @@ def process_command_line(args): # pylint: disable=too-many-locals,too-many-state help='minimize build') # Should be derived from info.txt but this runs too early - third_party = ['bearssl', 'boost', 'bzip2', 'lzma', 'openssl', 'sqlite3', 'zlib', 'tpm'] + third_party = ['bearssl', 'boost', 'bzip2', 'lzma', 'openssl', 'commoncrypto', 'sqlite3', 'zlib', 'tpm'] for mod in third_party: mods_group.add_option('--with-%s' % (mod), @@ -4,6 +4,8 @@ Release Notes Version 2.8.0, Not Yet Released ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +* CommonCrypto hashing support (MD4, MD5, SHA, SHA224, SHA256, SHA384, SHA512) + * Support for negotiating TLS versions 1.0 and 1.1 is disabled in the default TLS policy. In addition, support for negotiating TLS ciphersuites using CBC or CCM mode is disabled by default. Applications which need to interop with old diff --git a/src/lib/hash/hash.cpp b/src/lib/hash/hash.cpp index e30d00080..ad1a1bf0c 100644 --- a/src/lib/hash/hash.cpp +++ b/src/lib/hash/hash.cpp @@ -101,11 +101,27 @@ #include <botan/internal/openssl.h> #endif +#if defined(BOTAN_HAS_COMMONCRYPTO) + #include <botan/internal/commoncrypto.h> +#endif + namespace Botan { std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec, const std::string& provider) { + +#if defined(BOTAN_HAS_COMMONCRYPTO) + if(provider.empty() || provider == "commoncrypto") + { + if(auto hash = make_commoncrypto_hash(algo_spec)) + return hash; + + if(!provider.empty()) + return nullptr; + } +#endif + #if defined(BOTAN_HAS_OPENSSL) if(provider.empty() || provider == "openssl") { @@ -128,8 +144,6 @@ std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec, } #endif - // TODO: CommonCrypto hashes - if(provider.empty() == false && provider != "base") return nullptr; // unknown provider @@ -354,7 +368,7 @@ HashFunction::create_or_throw(const std::string& algo, std::vector<std::string> HashFunction::providers(const std::string& algo_spec) { - return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl"}); + return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl", "commoncrypto"}); } } diff --git a/src/lib/prov/commoncrypto/commoncrypto.h b/src/lib/prov/commoncrypto/commoncrypto.h new file mode 100644 index 000000000..da4adc8bf --- /dev/null +++ b/src/lib/prov/commoncrypto/commoncrypto.h @@ -0,0 +1,36 @@ +/* +* Utils for calling CommonCrypto +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_INTERNAL_COMMONCRYPTO_H_ +#define BOTAN_INTERNAL_COMMONCRYPTO_H_ + +#include <botan/pk_ops_fwd.h> +#include <botan/secmem.h> +#include <botan/exceptn.h> +#include <memory> +#include <string> + +#include <CommonCrypto/CommonCrypto.h> + +namespace Botan { + +class HashFunction; + +class BOTAN_PUBLIC_API(2,0) CommonCrypto_Error final : public Exception + { + public: + CommonCrypto_Error(const std::string& what) : + Exception(what + " failed.") {} + }; + +/* Hash */ + +std::unique_ptr<HashFunction> make_commoncrypto_hash(const std::string& name); + +} + +#endif diff --git a/src/lib/prov/commoncrypto/commoncrypto_hash.cpp b/src/lib/prov/commoncrypto/commoncrypto_hash.cpp new file mode 100644 index 000000000..81afa0e01 --- /dev/null +++ b/src/lib/prov/commoncrypto/commoncrypto_hash.cpp @@ -0,0 +1,139 @@ +/* +* CommonCrypto Hash Functions +* (C) 2018 Jose Pereira +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/hash.h> +#include <botan/internal/commoncrypto.h> + +#include <unordered_map> + +namespace Botan { + +namespace { + +template <class CTX> +class CommonCrypto_HashFunction final : public HashFunction + { + public: + + struct digest_config_t { + std::string name; + size_t digestLength; + size_t blockSize; + int (*init)(CTX *); + int (*update)(CTX *, const void *, CC_LONG len); + int (*final)(unsigned char *, CTX*); + }; + + void clear() override + { + if(m_info.init(&m_ctx) != 1) + throw CommonCrypto_Error("CC_" + m_info.name + "_Init"); + } + + std::string provider() const override { return "commoncrypto"; } + std::string name() const override { return m_info.name; } + + HashFunction* clone() const override + { + return new CommonCrypto_HashFunction(m_info); + } + + std::unique_ptr<HashFunction> copy_state() const override + { + return std::unique_ptr<CommonCrypto_HashFunction>( + new CommonCrypto_HashFunction(m_info, m_ctx)); + } + + size_t output_length() const override + { + return m_info.digestLength; + } + + size_t hash_block_size() const override + { + return m_info.blockSize; + } + + CommonCrypto_HashFunction(const digest_config_t& info) : + m_info(info) + { + clear(); + } + + CommonCrypto_HashFunction(const digest_config_t& info, const CTX &ctx) : + m_ctx(ctx), m_info(info) {} + + private: + void add_data(const uint8_t input[], size_t length) override + { + if(m_info.update(&m_ctx, input, length) != 1) + throw CommonCrypto_Error("CC_" + m_info.name + "_Update"); + } + + void final_result(uint8_t output[]) override + { + if(m_info.final(output, &m_ctx) != 1) + throw CommonCrypto_Error("CC_" + m_info.name + "_Final"); + clear(); + } + + CTX m_ctx; + digest_config_t m_info; + }; +} + +std::unique_ptr<HashFunction> +make_commoncrypto_hash(const std::string& name) + { +#define MAKE_COMMONCRYPTO_HASH_3(name, hash, ctx) \ + std::unique_ptr<HashFunction>( \ + new CommonCrypto_HashFunction<CC_ ## ctx ## _CTX >({ \ + name, \ + CC_ ## hash ## _DIGEST_LENGTH, \ + CC_ ## hash ## _BLOCK_BYTES, \ + CC_ ## hash ## _Init, \ + CC_ ## hash ## _Update, \ + CC_ ## hash ## _Final \ + })); + +#define MAKE_COMMONCRYPTO_HASH_2(name, id) \ + MAKE_COMMONCRYPTO_HASH_3(name, id, id) + +#define MAKE_COMMONCRYPTO_HASH_1(id) \ + MAKE_COMMONCRYPTO_HASH_2(#id, id) + +#if defined(BOTAN_HAS_SHA2_32) + if(name == "SHA-224") + return MAKE_COMMONCRYPTO_HASH_3(name, SHA224, SHA256); + if(name == "SHA-256") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA256); +#endif +#if defined(BOTAN_HAS_SHA2_64) + if(name == "SHA-384") + return MAKE_COMMONCRYPTO_HASH_3(name, SHA384, SHA512); + if(name == "SHA-512") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA512); +#endif + +#if defined(BOTAN_HAS_SHA1) + if(name == "SHA-160" || name == "SHA-1" || name == "SHA1") + return MAKE_COMMONCRYPTO_HASH_2(name, SHA1); +#endif + +#if defined(BOTAN_HAS_MD5) + if(name == "MD5") + return MAKE_COMMONCRYPTO_HASH_1(MD5); + #endif + +#if defined(BOTAN_HAS_MD4) + if(name == "MD4") + return MAKE_COMMONCRYPTO_HASH_1(MD4); +#endif + return nullptr; + } + +} diff --git a/src/lib/prov/commoncrypto/info.txt b/src/lib/prov/commoncrypto/info.txt new file mode 100644 index 000000000..00dfb27ae --- /dev/null +++ b/src/lib/prov/commoncrypto/info.txt @@ -0,0 +1,9 @@ +<defines> +COMMONCRYPTO -> 20180903 +</defines> + +load_on vendor + +<header:internal> +commoncrypto.h +</header:internal> diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp index 20bdc73ac..80b95b70b 100644 --- a/src/tests/test_pubkey.cpp +++ b/src/tests/test_pubkey.cpp @@ -93,7 +93,7 @@ std::string PK_Test::choose_padding(const VarMap& vars, std::vector<std::string> PK_Test::possible_providers(const std::string& /*params*/) { - return Test::provider_filter({ "base", "bearssl", "openssl", "tpm" }); + return Test::provider_filter({ "base", "commoncrypto", "bearssl", "openssl", "tpm" }); } Test::Result @@ -531,7 +531,7 @@ std::vector<std::string> PK_Key_Generation_Test::possible_providers( const std::string& algo) { std::vector<std::string> pk_provider = - Botan::probe_provider_private_key(algo, { "base", "openssl", "tpm" }); + Botan::probe_provider_private_key(algo, { "base", "commoncrypto", "openssl", "tpm" }); return Test::provider_filter(pk_provider); } |