diff options
Diffstat (limited to 'src/lib/engine/openssl')
-rw-r--r-- | src/lib/engine/openssl/bn_powm.cpp | 54 | ||||
-rw-r--r-- | src/lib/engine/openssl/bn_wrap.cpp | 116 | ||||
-rw-r--r-- | src/lib/engine/openssl/bn_wrap.h | 60 | ||||
-rw-r--r-- | src/lib/engine/openssl/info.txt | 25 | ||||
-rw-r--r-- | src/lib/engine/openssl/openssl_engine.h | 49 | ||||
-rw-r--r-- | src/lib/engine/openssl/ossl_arc4.cpp | 89 | ||||
-rw-r--r-- | src/lib/engine/openssl/ossl_bc.cpp | 248 | ||||
-rw-r--r-- | src/lib/engine/openssl/ossl_md.cpp | 150 | ||||
-rw-r--r-- | src/lib/engine/openssl/ossl_pk.cpp | 338 |
9 files changed, 1129 insertions, 0 deletions
diff --git a/src/lib/engine/openssl/bn_powm.cpp b/src/lib/engine/openssl/bn_powm.cpp new file mode 100644 index 000000000..ac06fbe77 --- /dev/null +++ b/src/lib/engine/openssl/bn_powm.cpp @@ -0,0 +1,54 @@ +/* +* OpenSSL Modular Exponentiation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/internal/bn_wrap.h> + +namespace Botan { + +namespace { + +/* +* OpenSSL Modular Exponentiator +*/ +class OpenSSL_Modular_Exponentiator : public Modular_Exponentiator + { + public: + void set_base(const BigInt& b) { base = b; } + void set_exponent(const BigInt& e) { exp = e; } + BigInt execute() const; + Modular_Exponentiator* copy() const + { return new OpenSSL_Modular_Exponentiator(*this); } + + OpenSSL_Modular_Exponentiator(const BigInt& n) : mod(n) {} + private: + OSSL_BN base, exp, mod; + OSSL_BN_CTX ctx; + }; + +/* +* Compute the result +*/ +BigInt OpenSSL_Modular_Exponentiator::execute() const + { + OSSL_BN r; + BN_mod_exp(r.ptr(), base.ptr(), exp.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + +} + +/* +* Return the OpenSSL-based modular exponentiator +*/ +Modular_Exponentiator* OpenSSL_Engine::mod_exp(const BigInt& n, + Power_Mod::Usage_Hints) const + { + return new OpenSSL_Modular_Exponentiator(n); + } + +} diff --git a/src/lib/engine/openssl/bn_wrap.cpp b/src/lib/engine/openssl/bn_wrap.cpp new file mode 100644 index 000000000..0a7e42368 --- /dev/null +++ b/src/lib/engine/openssl/bn_wrap.cpp @@ -0,0 +1,116 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/bn_wrap.h> + +namespace Botan { + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const BigInt& in) + { + m_bn = BN_new(); + secure_vector<byte> encoding = BigInt::encode_locked(in); + if(in != 0) + BN_bin2bn(&encoding[0], encoding.size(), m_bn); + } + +/* +* OSSL_BN Constructor +*/ +OSSL_BN::OSSL_BN(const byte in[], size_t length) + { + m_bn = BN_new(); + BN_bin2bn(in, length, m_bn); + } + +/* +* OSSL_BN Copy Constructor +*/ +OSSL_BN::OSSL_BN(const OSSL_BN& other) + { + m_bn = BN_dup(other.m_bn); + } + +/* +* OSSL_BN Destructor +*/ +OSSL_BN::~OSSL_BN() + { + BN_clear_free(m_bn); + } + +/* +* OSSL_BN Assignment Operator +*/ +OSSL_BN& OSSL_BN::operator=(const OSSL_BN& other) + { + BN_copy(m_bn, other.m_bn); + return (*this); + } + +/* +* Export the BIGNUM as a bytestring +*/ +void OSSL_BN::encode(byte out[], size_t length) const + { + BN_bn2bin(m_bn, out + (length - bytes())); + } + +/* +* Return the number of significant bytes +*/ +size_t OSSL_BN::bytes() const + { + return BN_num_bytes(m_bn); + } + +/* +* OpenSSL to BigInt Conversions +*/ +BigInt OSSL_BN::to_bigint() const + { + secure_vector<byte> out(bytes()); + BN_bn2bin(m_bn, &out[0]); + return BigInt::decode(out); + } + +/* +* OSSL_BN_CTX Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX() + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Copy Constructor +*/ +OSSL_BN_CTX::OSSL_BN_CTX(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + } + +/* +* OSSL_BN_CTX Destructor +*/ +OSSL_BN_CTX::~OSSL_BN_CTX() + { + BN_CTX_free(m_ctx); + } + +/* +* OSSL_BN_CTX Assignment Operator +*/ +OSSL_BN_CTX& OSSL_BN_CTX::operator=(const OSSL_BN_CTX&) + { + m_ctx = BN_CTX_new(); + return (*this); + } + +} diff --git a/src/lib/engine/openssl/bn_wrap.h b/src/lib/engine/openssl/bn_wrap.h new file mode 100644 index 000000000..12bcec152 --- /dev/null +++ b/src/lib/engine/openssl/bn_wrap.h @@ -0,0 +1,60 @@ +/* +* OpenSSL BN Wrapper +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OPENSSL_BN_WRAP_H__ +#define BOTAN_OPENSSL_BN_WRAP_H__ + +#include <botan/bigint.h> +#include <openssl/bn.h> + +namespace Botan { + +/** +* Lightweight OpenSSL BN wrapper. For internal use only. +*/ +class OSSL_BN + { + public: + BigInt to_bigint() const; + void encode(byte[], size_t) const; + size_t bytes() const; + + secure_vector<byte> to_bytes() const + { return BigInt::encode_locked(to_bigint()); } + + OSSL_BN& operator=(const OSSL_BN&); + + OSSL_BN(const OSSL_BN&); + OSSL_BN(const BigInt& = 0); + OSSL_BN(const byte[], size_t); + ~OSSL_BN(); + + BIGNUM* ptr() const { return m_bn; } + private: + BIGNUM* m_bn; + }; + +/** +* Lightweight OpenSSL BN_CTX wrapper. For internal use only. +*/ +class OSSL_BN_CTX + { + public: + OSSL_BN_CTX& operator=(const OSSL_BN_CTX&); + + OSSL_BN_CTX(); + OSSL_BN_CTX(const OSSL_BN_CTX&); + ~OSSL_BN_CTX(); + + BN_CTX* ptr() const { return m_ctx; } + private: + BN_CTX* m_ctx; + }; + +} + +#endif diff --git a/src/lib/engine/openssl/info.txt b/src/lib/engine/openssl/info.txt new file mode 100644 index 000000000..d500816d5 --- /dev/null +++ b/src/lib/engine/openssl/info.txt @@ -0,0 +1,25 @@ +define ENGINE_OPENSSL 20131128 + +load_on request + +<libs> +all -> crypto +</libs> + +<header:internal> +openssl_engine.h +bn_wrap.h +</header:internal> + +<source> +bn_powm.cpp +bn_wrap.cpp +ossl_arc4.cpp +ossl_bc.cpp +ossl_md.cpp +ossl_pk.cpp +</source> + +<requires> +bigint +</requires> diff --git a/src/lib/engine/openssl/openssl_engine.h b/src/lib/engine/openssl/openssl_engine.h new file mode 100644 index 000000000..90f315c00 --- /dev/null +++ b/src/lib/engine/openssl/openssl_engine.h @@ -0,0 +1,49 @@ +/* +* OpenSSL Engine +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENGINE_OPENSSL_H__ +#define BOTAN_ENGINE_OPENSSL_H__ + +#include <botan/engine.h> + +namespace Botan { + +/** +* OpenSSL Engine +*/ +class OpenSSL_Engine : public Engine + { + public: + std::string provider_name() const override { return "openssl"; } + + PK_Ops::Key_Agreement* + get_key_agreement_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Signature* + get_signature_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Verification* get_verify_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Encryption* get_encryption_op(const Public_Key& key, RandomNumberGenerator& rng) const override; + + PK_Ops::Decryption* get_decryption_op(const Private_Key& key, RandomNumberGenerator& rng) const override; + + Modular_Exponentiator* mod_exp(const BigInt&, + Power_Mod::Usage_Hints) const override; + + BlockCipher* find_block_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + StreamCipher* find_stream_cipher(const SCAN_Name&, + Algorithm_Factory&) const override; + + HashFunction* find_hash(const SCAN_Name&, Algorithm_Factory&) const override; + }; + +} + +#endif diff --git a/src/lib/engine/openssl/ossl_arc4.cpp b/src/lib/engine/openssl/ossl_arc4.cpp new file mode 100644 index 000000000..0eb404af1 --- /dev/null +++ b/src/lib/engine/openssl/ossl_arc4.cpp @@ -0,0 +1,89 @@ +/* +* OpenSSL RC4 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/parsing.h> +#include <openssl/rc4.h> + +namespace Botan { + +namespace { + +/** +* RC4 as implemented by OpenSSL +*/ +class RC4_OpenSSL : public StreamCipher + { + public: + void clear() { clear_mem(&state, 1); } + + std::string name() const; + StreamCipher* clone() const { return new RC4_OpenSSL(SKIP); } + + Key_Length_Specification key_spec() const + { + return Key_Length_Specification(1, 32); + } + + + RC4_OpenSSL(size_t s = 0) : SKIP(s) { clear(); } + ~RC4_OpenSSL() { clear(); } + private: + void cipher(const byte[], byte[], size_t); + void key_schedule(const byte[], size_t); + + const size_t SKIP; + RC4_KEY state; + }; + +/* +* Return the name of this type +*/ +std::string RC4_OpenSSL::name() const + { + if(SKIP == 0) return "RC4"; + if(SKIP == 256) return "MARK-4"; + else return "RC4_skip(" + std::to_string(SKIP) + ")"; + } + +/* +* RC4 Key Schedule +*/ +void RC4_OpenSSL::key_schedule(const byte key[], size_t length) + { + RC4_set_key(&state, length, key); + byte dummy = 0; + for(size_t i = 0; i != SKIP; ++i) + RC4(&state, 1, &dummy, &dummy); + } + +/* +* RC4 Encryption +*/ +void RC4_OpenSSL::cipher(const byte in[], byte out[], size_t length) + { + RC4(&state, length, in, out); + } + +} + +/** +* Look for an OpenSSL-supported stream cipher (RC4) +*/ +StreamCipher* +OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { + if(request.algo_name() == "RC4") + return new RC4_OpenSSL(request.arg_as_integer(0, 0)); + if(request.algo_name() == "RC4_drop") + return new RC4_OpenSSL(768); + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_bc.cpp b/src/lib/engine/openssl/ossl_bc.cpp new file mode 100644 index 000000000..b3b509c36 --- /dev/null +++ b/src/lib/engine/openssl/ossl_bc.cpp @@ -0,0 +1,248 @@ +/* +* OpenSSL Block Cipher +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <openssl/evp.h> + +namespace Botan { + +namespace { + +/* +* EVP Block Cipher +*/ +class EVP_BlockCipher : public BlockCipher + { + public: + void clear(); + std::string name() const { return cipher_name; } + BlockCipher* clone() const; + + size_t block_size() const { return block_sz; } + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&); + + EVP_BlockCipher(const EVP_CIPHER*, const std::string&, + size_t, size_t, size_t); + + Key_Length_Specification key_spec() const { return cipher_key_spec; } + + ~EVP_BlockCipher(); + private: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + void key_schedule(const byte[], size_t); + + size_t block_sz; + Key_Length_Specification cipher_key_spec; + std::string cipher_name; + mutable EVP_CIPHER_CTX encrypt, decrypt; + }; + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(EVP_CIPHER_key_length(algo)), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Constructor +*/ +EVP_BlockCipher::EVP_BlockCipher(const EVP_CIPHER* algo, + const std::string& algo_name, + size_t key_min, size_t key_max, + size_t key_mod) : + block_sz(EVP_CIPHER_block_size(algo)), + cipher_key_spec(key_min, key_max, key_mod), + cipher_name(algo_name) + { + if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE) + throw Invalid_Argument("EVP_BlockCipher: Non-ECB EVP was passed in"); + + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +/* +* EVP Block Cipher Destructor +*/ +EVP_BlockCipher::~EVP_BlockCipher() + { + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + } + +/* +* Encrypt a block +*/ +void EVP_BlockCipher::encrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_EncryptUpdate(&encrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Decrypt a block +*/ +void EVP_BlockCipher::decrypt_n(const byte in[], byte out[], + size_t blocks) const + { + int out_len = 0; + EVP_DecryptUpdate(&decrypt, out, &out_len, in, blocks * block_sz); + } + +/* +* Set the key +*/ +void EVP_BlockCipher::key_schedule(const byte key[], size_t length) + { + secure_vector<byte> full_key(key, key + length); + + if(cipher_name == "TripleDES" && length == 16) + { + full_key += std::make_pair(key, 8); + } + else + if(EVP_CIPHER_CTX_set_key_length(&encrypt, length) == 0 || + EVP_CIPHER_CTX_set_key_length(&decrypt, length) == 0) + throw Invalid_Argument("EVP_BlockCipher: Bad key length for " + + cipher_name); + + if(cipher_name == "RC2") + { + EVP_CIPHER_CTX_ctrl(&encrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + EVP_CIPHER_CTX_ctrl(&decrypt, EVP_CTRL_SET_RC2_KEY_BITS, length*8, 0); + } + + EVP_EncryptInit_ex(&encrypt, 0, 0, &full_key[0], 0); + EVP_DecryptInit_ex(&decrypt, 0, 0, &full_key[0], 0); + } + +/* +* Return a clone of this object +*/ +BlockCipher* EVP_BlockCipher::clone() const + { + return new EVP_BlockCipher(EVP_CIPHER_CTX_cipher(&encrypt), + cipher_name, + cipher_key_spec.minimum_keylength(), + cipher_key_spec.maximum_keylength(), + cipher_key_spec.keylength_multiple()); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_BlockCipher::clear() + { + const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(&encrypt); + + EVP_CIPHER_CTX_cleanup(&encrypt); + EVP_CIPHER_CTX_cleanup(&decrypt); + EVP_CIPHER_CTX_init(&encrypt); + EVP_CIPHER_CTX_init(&decrypt); + EVP_EncryptInit_ex(&encrypt, algo, 0, 0, 0); + EVP_DecryptInit_ex(&decrypt, algo, 0, 0, 0); + EVP_CIPHER_CTX_set_padding(&encrypt, 0); + EVP_CIPHER_CTX_set_padding(&decrypt, 0); + } + +} + +/* +* Look for an algorithm with this name +*/ +BlockCipher* +OpenSSL_Engine::find_block_cipher(const SCAN_Name& request, + Algorithm_Factory&) const + { +#define HANDLE_EVP_CIPHER(NAME, EVP) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME); + +#define HANDLE_EVP_CIPHER_KEYLEN(NAME, EVP, MIN, MAX, MOD) \ + if(request.algo_name() == NAME && request.arg_count() == 0) \ + return new EVP_BlockCipher(EVP, NAME, MIN, MAX, MOD); + +#if !defined(OPENSSL_NO_AES) + /* + Using OpenSSL's AES causes crashes inside EVP on x86-64 with OpenSSL 0.9.8g + cause is unknown + */ + HANDLE_EVP_CIPHER("AES-128", EVP_aes_128_ecb()); + HANDLE_EVP_CIPHER("AES-192", EVP_aes_192_ecb()); + HANDLE_EVP_CIPHER("AES-256", EVP_aes_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_DES) + HANDLE_EVP_CIPHER("DES", EVP_des_ecb()); + HANDLE_EVP_CIPHER_KEYLEN("TripleDES", EVP_des_ede3_ecb(), 16, 24, 8); +#endif + +#if !defined(OPENSSL_NO_BF) + HANDLE_EVP_CIPHER_KEYLEN("Blowfish", EVP_bf_ecb(), 1, 56, 1); +#endif + +#if !defined(OPENSSL_NO_CAST) + HANDLE_EVP_CIPHER_KEYLEN("CAST-128", EVP_cast5_ecb(), 1, 16, 1); +#endif + +#if !defined(OPENSSL_NO_CAMELLIA) + HANDLE_EVP_CIPHER("Camellia-128", EVP_camellia_128_ecb()); + HANDLE_EVP_CIPHER("Camellia-192", EVP_camellia_192_ecb()); + HANDLE_EVP_CIPHER("Camellia-256", EVP_camellia_256_ecb()); +#endif + +#if !defined(OPENSSL_NO_RC2) + HANDLE_EVP_CIPHER_KEYLEN("RC2", EVP_rc2_ecb(), 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_RC5) && 0 + if(request.algo_name() == "RC5") + if(request.arg_as_integer(0, 12) == 12) + return new EVP_BlockCipher(EVP_rc5_32_12_16_ecb(), + "RC5(12)", 1, 32, 1); +#endif + +#if !defined(OPENSSL_NO_IDEA) && 0 + HANDLE_EVP_CIPHER("IDEA", EVP_idea_ecb()); +#endif + +#if !defined(OPENSSL_NO_SEED) + HANDLE_EVP_CIPHER("SEED", EVP_seed_ecb()); +#endif + +#undef HANDLE_EVP_CIPHER +#undef HANDLE_EVP_CIPHER_KEYLEN + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_md.cpp b/src/lib/engine/openssl/ossl_md.cpp new file mode 100644 index 000000000..e09a68a8e --- /dev/null +++ b/src/lib/engine/openssl/ossl_md.cpp @@ -0,0 +1,150 @@ +/* +* OpenSSL Hash Functions +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <openssl/evp.h> + +namespace Botan { + +namespace { + +/* +* EVP Hash Function +*/ +class EVP_HashFunction : public HashFunction + { + public: + void clear(); + std::string name() const { return algo_name; } + HashFunction* clone() const; + + size_t output_length() const + { + return EVP_MD_size(EVP_MD_CTX_md(&md)); + } + + size_t hash_block_size() const + { + return EVP_MD_block_size(EVP_MD_CTX_md(&md)); + } + + EVP_HashFunction(const EVP_MD*, const std::string&); + ~EVP_HashFunction(); + private: + void add_data(const byte[], size_t); + void final_result(byte[]); + + std::string algo_name; + EVP_MD_CTX md; + }; + +/* +* Update an EVP Hash Calculation +*/ +void EVP_HashFunction::add_data(const byte input[], size_t length) + { + EVP_DigestUpdate(&md, input, length); + } + +/* +* Finalize an EVP Hash Calculation +*/ +void EVP_HashFunction::final_result(byte output[]) + { + EVP_DigestFinal_ex(&md, output, 0); + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Clear memory of sensitive data +*/ +void EVP_HashFunction::clear() + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Return a clone of this object +*/ +HashFunction* EVP_HashFunction::clone() const + { + const EVP_MD* algo = EVP_MD_CTX_md(&md); + return new EVP_HashFunction(algo, name()); + } + +/* +* Create an EVP hash function +*/ +EVP_HashFunction::EVP_HashFunction(const EVP_MD* algo, + const std::string& name) : + algo_name(name) + { + EVP_MD_CTX_init(&md); + EVP_DigestInit_ex(&md, algo, 0); + } + +/* +* Destroy an EVP hash function +*/ +EVP_HashFunction::~EVP_HashFunction() + { + EVP_MD_CTX_cleanup(&md); + } + +} + +/* +* Look for an algorithm with this name +*/ +HashFunction* OpenSSL_Engine::find_hash(const SCAN_Name& request, + Algorithm_Factory&) const + { +#if !defined(OPENSSL_NO_SHA) + if(request.algo_name() == "SHA-160") + return new EVP_HashFunction(EVP_sha1(), "SHA-160"); +#endif + +#if !defined(OPENSSL_NO_SHA256) + if(request.algo_name() == "SHA-224") + return new EVP_HashFunction(EVP_sha224(), "SHA-224"); + if(request.algo_name() == "SHA-256") + return new EVP_HashFunction(EVP_sha256(), "SHA-256"); +#endif + +#if !defined(OPENSSL_NO_SHA512) + if(request.algo_name() == "SHA-384") + return new EVP_HashFunction(EVP_sha384(), "SHA-384"); + if(request.algo_name() == "SHA-512") + return new EVP_HashFunction(EVP_sha512(), "SHA-512"); +#endif + +#if !defined(OPENSSL_NO_MD2) + if(request.algo_name() == "MD2") + return new EVP_HashFunction(EVP_md2(), "MD2"); +#endif + +#if !defined(OPENSSL_NO_MD4) + if(request.algo_name() == "MD4") + return new EVP_HashFunction(EVP_md4(), "MD4"); +#endif + +#if !defined(OPENSSL_NO_MD5) + if(request.algo_name() == "MD5") + return new EVP_HashFunction(EVP_md5(), "MD5"); +#endif + +#if !defined(OPENSSL_NO_RIPEMD) + if(request.algo_name() == "RIPEMD-160") + return new EVP_HashFunction(EVP_ripemd160(), "RIPEMD-160"); +#endif + + return 0; + } + +} diff --git a/src/lib/engine/openssl/ossl_pk.cpp b/src/lib/engine/openssl/ossl_pk.cpp new file mode 100644 index 000000000..cbe03d7b3 --- /dev/null +++ b/src/lib/engine/openssl/ossl_pk.cpp @@ -0,0 +1,338 @@ +/* +* OpenSSL PK operations +* (C) 1999-2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/internal/openssl_engine.h> +#include <botan/internal/bn_wrap.h> + +#if defined(BOTAN_HAS_RSA) + #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_DSA) + #include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include <botan/ecdsa.h> + #include <openssl/ecdsa.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +namespace Botan { + +namespace { + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) +class OSSL_DH_KA_Operation : public PK_Ops::Key_Agreement + { + public: + OSSL_DH_KA_Operation(const DH_PrivateKey& dh) : + x(dh.get_x()), p(dh.group_p()) {} + + secure_vector<byte> agree(const byte w[], size_t w_len) + { + OSSL_BN i(w, w_len), r; + BN_mod_exp(r.ptr(), i.ptr(), x.ptr(), p.ptr(), ctx.ptr()); + return r.to_bytes(); + } + + private: + const OSSL_BN x, p; + OSSL_BN_CTX ctx; + }; +#endif + +#if defined(BOTAN_HAS_DSA) + +class OSSL_DSA_Signature_Operation : public PK_Ops::Signature + { + public: + OSSL_DSA_Signature_Operation(const DSA_PrivateKey& dsa) : + x(dsa.get_x()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng); + private: + const OSSL_BN x, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +secure_vector<byte> +OSSL_DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, + RandomNumberGenerator& rng) + { + const size_t q_bytes = (q_bits + 7) / 8; + + rng.add_entropy(msg, msg_len); + + BigInt k_bn; + do + k_bn.randomize(rng, q_bits); + while(k_bn >= q.to_bigint()); + + OSSL_BN i(msg, msg_len); + OSSL_BN k(k_bn); + + OSSL_BN r; + BN_mod_exp(r.ptr(), g.ptr(), k.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(r.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + + BN_mod_inverse(k.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + OSSL_BN s; + BN_mul(s.ptr(), x.ptr(), r.ptr(), ctx.ptr()); + BN_add(s.ptr(), s.ptr(), i.ptr()); + BN_mod_mul(s.ptr(), s.ptr(), k.ptr(), q.ptr(), ctx.ptr()); + + if(BN_is_zero(r.ptr()) || BN_is_zero(s.ptr())) + throw Internal_Error("OpenSSL_DSA_Op::sign: r or s was zero"); + + secure_vector<byte> output(2*q_bytes); + r.encode(&output[0], q_bytes); + s.encode(&output[q_bytes], q_bytes); + return output; + } + +class OSSL_DSA_Verification_Operation : public PK_Ops::Verification + { + public: + OSSL_DSA_Verification_Operation(const DSA_PublicKey& dsa) : + y(dsa.get_y()), + p(dsa.group_p()), + q(dsa.group_q()), + g(dsa.group_g()), + q_bits(dsa.group_q().bits()) {} + + size_t message_parts() const { return 2; } + size_t message_part_size() const { return (q_bits + 7) / 8; } + size_t max_input_bits() const { return q_bits; } + + bool with_recovery() const { return false; } + + bool verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len); + private: + const OSSL_BN y, p, q, g; + const OSSL_BN_CTX ctx; + size_t q_bits; + }; + +bool OSSL_DSA_Verification_Operation::verify(const byte msg[], size_t msg_len, + const byte sig[], size_t sig_len) + { + const size_t q_bytes = q.bytes(); + + if(sig_len != 2*q_bytes || msg_len > q_bytes) + return false; + + OSSL_BN r(sig, q_bytes); + OSSL_BN s(sig + q_bytes, q_bytes); + OSSL_BN i(msg, msg_len); + + if(BN_is_zero(r.ptr()) || BN_cmp(r.ptr(), q.ptr()) >= 0) + return false; + if(BN_is_zero(s.ptr()) || BN_cmp(s.ptr(), q.ptr()) >= 0) + return false; + + if(BN_mod_inverse(s.ptr(), s.ptr(), q.ptr(), ctx.ptr()) == 0) + return false; + + OSSL_BN si; + BN_mod_mul(si.ptr(), s.ptr(), i.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(si.ptr(), g.ptr(), si.ptr(), p.ptr(), ctx.ptr()); + + OSSL_BN sr; + BN_mod_mul(sr.ptr(), s.ptr(), r.ptr(), q.ptr(), ctx.ptr()); + BN_mod_exp(sr.ptr(), y.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + + BN_mod_mul(si.ptr(), si.ptr(), sr.ptr(), p.ptr(), ctx.ptr()); + BN_nnmod(si.ptr(), si.ptr(), q.ptr(), ctx.ptr()); + + if(BN_cmp(si.ptr(), r.ptr()) == 0) + return true; + return false; + + return false; + } + +#endif + +#if defined(BOTAN_HAS_RSA) + +class OSSL_RSA_Private_Operation : public PK_Ops::Signature, + public PK_Ops::Decryption + { + public: + OSSL_RSA_Private_Operation(const RSA_PrivateKey& rsa) : + mod(rsa.get_n()), + p(rsa.get_p()), + q(rsa.get_q()), + d1(rsa.get_d1()), + d2(rsa.get_d2()), + c(rsa.get_c()), + n_bits(rsa.get_n().bits()) + {} + + size_t max_input_bits() const { return (n_bits - 1); } + + secure_vector<byte> sign(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + BigInt x = private_op(m); + return BigInt::encode_1363(x, (n_bits + 7) / 8); + } + + secure_vector<byte> decrypt(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(private_op(m)); + } + + private: + BigInt private_op(const BigInt& m) const; + + const OSSL_BN mod, p, q, d1, d2, c; + const OSSL_BN_CTX ctx; + size_t n_bits; + }; + +BigInt OSSL_RSA_Private_Operation::private_op(const BigInt& m) const + { + OSSL_BN j1, j2, h(m); + + BN_mod_exp(j1.ptr(), h.ptr(), d1.ptr(), p.ptr(), ctx.ptr()); + BN_mod_exp(j2.ptr(), h.ptr(), d2.ptr(), q.ptr(), ctx.ptr()); + BN_sub(h.ptr(), j1.ptr(), j2.ptr()); + BN_mod_mul(h.ptr(), h.ptr(), c.ptr(), p.ptr(), ctx.ptr()); + BN_mul(h.ptr(), h.ptr(), q.ptr(), ctx.ptr()); + BN_add(h.ptr(), h.ptr(), j2.ptr()); + return h.to_bigint(); + } + +class OSSL_RSA_Public_Operation : public PK_Ops::Verification, + public PK_Ops::Encryption + { + public: + OSSL_RSA_Public_Operation(const RSA_PublicKey& rsa) : + n(rsa.get_n()), e(rsa.get_e()), mod(rsa.get_n()) + {} + + size_t max_input_bits() const { return (n.bits() - 1); } + bool with_recovery() const { return true; } + + secure_vector<byte> encrypt(const byte msg[], size_t msg_len, + RandomNumberGenerator&) + { + BigInt m(msg, msg_len); + return BigInt::encode_1363(public_op(m), n.bytes()); + } + + secure_vector<byte> verify_mr(const byte msg[], size_t msg_len) + { + BigInt m(msg, msg_len); + return BigInt::encode_locked(public_op(m)); + } + + private: + BigInt public_op(const BigInt& m) const + { + if(m >= n) + throw Invalid_Argument("RSA public op - input is too large"); + + OSSL_BN m_bn(m), r; + BN_mod_exp(r.ptr(), m_bn.ptr(), e.ptr(), mod.ptr(), ctx.ptr()); + return r.to_bigint(); + } + + const BigInt& n; + const OSSL_BN e, mod; + const OSSL_BN_CTX ctx; + }; + +#endif + +} + +PK_Ops::Key_Agreement* +OpenSSL_Engine::get_key_agreement_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(const DH_PrivateKey* dh = dynamic_cast<const DH_PrivateKey*>(&key)) + return new OSSL_DH_KA_Operation(*dh); +#endif + + return 0; + } + +PK_Ops::Signature* +OpenSSL_Engine::get_signature_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PrivateKey* s = dynamic_cast<const DSA_PrivateKey*>(&key)) + return new OSSL_DSA_Signature_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Verification* +OpenSSL_Engine::get_verify_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + +#if defined(BOTAN_HAS_DSA) + if(const DSA_PublicKey* s = dynamic_cast<const DSA_PublicKey*>(&key)) + return new OSSL_DSA_Verification_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Encryption* +OpenSSL_Engine::get_encryption_op(const Public_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PublicKey* s = dynamic_cast<const RSA_PublicKey*>(&key)) + return new OSSL_RSA_Public_Operation(*s); +#endif + + return 0; + } + +PK_Ops::Decryption* +OpenSSL_Engine::get_decryption_op(const Private_Key& key, RandomNumberGenerator&) const + { +#if defined(BOTAN_HAS_RSA) + if(const RSA_PrivateKey* s = dynamic_cast<const RSA_PrivateKey*>(&key)) + return new OSSL_RSA_Private_Operation(*s); +#endif + + return 0; + } + +} |