summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/prov/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/prov/openssl')
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/info.txt21
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl.h118
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp234
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp383
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp136
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp233
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp93
-rw-r--r--comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp312
8 files changed, 1530 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/prov/openssl/info.txt b/comm/third_party/botan/src/lib/prov/openssl/info.txt
new file mode 100644
index 0000000000..32e71a8481
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/info.txt
@@ -0,0 +1,21 @@
+<defines>
+OPENSSL -> 20151219
+</defines>
+
+load_on vendor
+
+<header:internal>
+openssl.h
+</header:internal>
+
+<libs>
+all!windows -> crypto
+windows -> libeay32
+</libs>
+
+<requires>
+block
+stream
+modes
+pubkey
+</requires>
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl.h b/comm/third_party/botan/src/lib/prov/openssl/openssl.h
new file mode 100644
index 0000000000..a68dda5af0
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl.h
@@ -0,0 +1,118 @@
+/*
+* Utils for calling OpenSSL
+* (C) 2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_INTERNAL_OPENSSL_H_
+#define BOTAN_INTERNAL_OPENSSL_H_
+
+#include <botan/pk_ops_fwd.h>
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <memory>
+#include <string>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#if defined(BOTAN_HAS_RC4)
+#include <openssl/rc4.h>
+#endif
+
+namespace Botan {
+
+class BlockCipher;
+class Cipher_Mode;
+class StreamCipher;
+class HashFunction;
+class RandomNumberGenerator;
+enum Cipher_Dir : int;
+
+class BOTAN_PUBLIC_API(2,0) OpenSSL_Error final : public Exception
+ {
+ public:
+ OpenSSL_Error(const std::string& what, int err) :
+ 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 */
+
+std::unique_ptr<BlockCipher>
+make_openssl_block_cipher(const std::string& name);
+
+/* Cipher Modes */
+
+Cipher_Mode*
+make_openssl_cipher_mode(const std::string& name, Cipher_Dir direction);
+
+/* Hash */
+
+std::unique_ptr<HashFunction>
+make_openssl_hash(const std::string& name);
+
+/* RSA */
+
+#if defined(BOTAN_HAS_RSA)
+
+class RSA_PublicKey;
+class RSA_PrivateKey;
+
+std::unique_ptr<PK_Ops::Encryption>
+make_openssl_rsa_enc_op(const RSA_PublicKey& key, const std::string& params);
+std::unique_ptr<PK_Ops::Decryption>
+make_openssl_rsa_dec_op(const RSA_PrivateKey& key, const std::string& params);
+
+std::unique_ptr<PK_Ops::Verification>
+make_openssl_rsa_ver_op(const RSA_PublicKey& key, const std::string& params);
+std::unique_ptr<PK_Ops::Signature>
+make_openssl_rsa_sig_op(const RSA_PrivateKey& key, const std::string& params);
+std::unique_ptr<RSA_PrivateKey>
+make_openssl_rsa_private_key(RandomNumberGenerator& rng, size_t rsa_bits);
+
+#endif
+
+/* ECDSA */
+
+#if defined(BOTAN_HAS_ECDSA)
+
+class ECDSA_PublicKey;
+class ECDSA_PrivateKey;
+
+std::unique_ptr<PK_Ops::Verification>
+make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params);
+std::unique_ptr<PK_Ops::Signature>
+make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params);
+
+#endif
+
+/* ECDH */
+
+#if defined(BOTAN_HAS_ECDH)
+
+class ECDH_PrivateKey;
+
+std::unique_ptr<PK_Ops::Key_Agreement>
+make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params);
+
+#endif
+
+#if defined(BOTAN_HAS_RC4)
+
+std::unique_ptr<StreamCipher>
+make_openssl_rc4(size_t skip);
+
+#endif
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp
new file mode 100644
index 0000000000..7f9bdcf6c5
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_block.cpp
@@ -0,0 +1,234 @@
+/*
+* Block Ciphers via OpenSSL
+* (C) 1999-2010,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/block_cipher.h>
+#include <botan/internal/openssl.h>
+#include <openssl/evp.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_BlockCipher final : public BlockCipher
+ {
+ public:
+ OpenSSL_BlockCipher(const std::string& name,
+ const EVP_CIPHER* cipher);
+
+ OpenSSL_BlockCipher(const std::string& name,
+ const EVP_CIPHER* cipher,
+ size_t kl_min, size_t kl_max, size_t kl_mod);
+
+ ~OpenSSL_BlockCipher();
+
+ void clear() override;
+ std::string provider() const override { return "openssl"; }
+ std::string name() const override { return m_cipher_name; }
+ BlockCipher* clone() const override;
+
+ size_t block_size() const override { return m_block_sz; }
+
+ Key_Length_Specification key_spec() const override { return m_cipher_key_spec; }
+
+ void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ 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", ERR_get_error());
+ }
+
+ void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const override
+ {
+ 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", ERR_get_error());
+ }
+
+ void key_schedule(const uint8_t key[], size_t key_len) override;
+
+ size_t m_block_sz;
+ Key_Length_Specification m_cipher_key_spec;
+ std::string m_cipher_name;
+ EVP_CIPHER_CTX *m_encrypt;
+ EVP_CIPHER_CTX *m_decrypt;
+ bool m_key_set;
+ };
+
+OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
+ const EVP_CIPHER* algo) :
+ m_block_sz(EVP_CIPHER_block_size(algo)),
+ m_cipher_key_spec(EVP_CIPHER_key_length(algo)),
+ m_cipher_name(algo_name),
+ m_key_set(false)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
+
+ 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", 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", ERR_get_error());
+ if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
+ 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", ERR_get_error());
+ if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
+ throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
+ }
+
+OpenSSL_BlockCipher::OpenSSL_BlockCipher(const std::string& algo_name,
+ const EVP_CIPHER* algo,
+ size_t key_min,
+ size_t key_max,
+ size_t key_mod) :
+ m_block_sz(EVP_CIPHER_block_size(algo)),
+ m_cipher_key_spec(key_min, key_max, key_mod),
+ m_cipher_name(algo_name),
+ m_key_set(false)
+ {
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_ECB_MODE)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Non-ECB EVP was passed in");
+
+ 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", 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", ERR_get_error());
+ if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
+ 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", ERR_get_error());
+ if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
+ throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
+ }
+
+OpenSSL_BlockCipher::~OpenSSL_BlockCipher()
+ {
+ EVP_CIPHER_CTX_cleanup(m_encrypt);
+ EVP_CIPHER_CTX_cleanup(m_decrypt);
+
+ EVP_CIPHER_CTX_free(m_encrypt);
+ EVP_CIPHER_CTX_free(m_decrypt);
+ }
+
+/*
+* Set the key
+*/
+void OpenSSL_BlockCipher::key_schedule(const uint8_t key[], size_t length)
+ {
+ secure_vector<uint8_t> full_key(key, key + length);
+
+ if(m_cipher_name == "TripleDES" && length == 16)
+ {
+ full_key += std::make_pair(key, 8);
+ }
+ else
+ {
+ if(EVP_CIPHER_CTX_set_key_length(m_encrypt, length) == 0 ||
+ EVP_CIPHER_CTX_set_key_length(m_decrypt, length) == 0)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Bad key length for " +
+ m_cipher_name);
+ }
+
+ if(!EVP_EncryptInit_ex(m_encrypt, nullptr, nullptr, full_key.data(), nullptr))
+ 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", ERR_get_error());
+
+ m_key_set = true;
+ }
+
+/*
+* Return a clone of this object
+*/
+BlockCipher* OpenSSL_BlockCipher::clone() const
+ {
+ return new OpenSSL_BlockCipher(m_cipher_name,
+ EVP_CIPHER_CTX_cipher(m_encrypt),
+ m_cipher_key_spec.minimum_keylength(),
+ m_cipher_key_spec.maximum_keylength(),
+ m_cipher_key_spec.keylength_multiple());
+ }
+
+/*
+* Clear memory of sensitive data
+*/
+void OpenSSL_BlockCipher::clear()
+ {
+ const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_encrypt);
+
+ m_key_set = false;
+
+ if(!EVP_CIPHER_CTX_cleanup(m_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", 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", ERR_get_error());
+ if(!EVP_DecryptInit_ex(m_decrypt, algo, nullptr, nullptr, nullptr))
+ 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", ERR_get_error());
+ if(!EVP_CIPHER_CTX_set_padding(m_decrypt, 0))
+ throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding decrypt", ERR_get_error());
+ }
+
+}
+
+std::unique_ptr<BlockCipher>
+make_openssl_block_cipher(const std::string& name)
+ {
+#define MAKE_OPENSSL_BLOCK(evp_fn) \
+ std::unique_ptr<BlockCipher>(new OpenSSL_BlockCipher(name, evp_fn()))
+#define MAKE_OPENSSL_BLOCK_KEYLEN(evp_fn, kl_min, kl_max, kl_mod) \
+ std::unique_ptr<BlockCipher>(new OpenSSL_BlockCipher(name, evp_fn(), kl_min, kl_max, kl_mod))
+
+#if defined(BOTAN_HAS_AES) && !defined(OPENSSL_NO_AES)
+ if(name == "AES-128")
+ return MAKE_OPENSSL_BLOCK(EVP_aes_128_ecb);
+ if(name == "AES-192")
+ return MAKE_OPENSSL_BLOCK(EVP_aes_192_ecb);
+ if(name == "AES-256")
+ return MAKE_OPENSSL_BLOCK(EVP_aes_256_ecb);
+#endif
+
+#if defined(BOTAN_HAS_CAMELLIA) && !defined(OPENSSL_NO_CAMELLIA)
+ if(name == "Camellia-128")
+ return MAKE_OPENSSL_BLOCK(EVP_camellia_128_ecb);
+ if(name == "Camellia-192")
+ return MAKE_OPENSSL_BLOCK(EVP_camellia_192_ecb);
+ if(name == "Camellia-256")
+ return MAKE_OPENSSL_BLOCK(EVP_camellia_256_ecb);
+#endif
+
+#if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES)
+ if(name == "TripleDES")
+ return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
+#endif
+
+ return nullptr;
+ }
+
+}
+
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp
new file mode 100644
index 0000000000..3f691f68ac
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_ec.cpp
@@ -0,0 +1,383 @@
+/*
+* ECDSA and ECDH via OpenSSL
+* (C) 2015,2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/openssl.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ #include <botan/der_enc.h>
+ #include <botan/pkcs8.h>
+ #include <botan/internal/pk_ops_impl.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ #include <botan/ecdh.h>
+#endif
+
+#include <openssl/x509.h>
+#include <openssl/objects.h>
+
+#if !defined(OPENSSL_NO_EC)
+ #include <openssl/ec.h>
+#endif
+
+#if !defined(OPENSSL_NO_ECDSA)
+ #include <openssl/ecdsa.h>
+#endif
+
+#if !defined(OPENSSL_NO_ECDH)
+ #include <openssl/ecdh.h>
+#endif
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+namespace {
+
+secure_vector<uint8_t> PKCS8_for_openssl(const EC_PrivateKey& ec)
+ {
+ const PointGFp& pub_key = ec.public_point();
+ const BigInt& priv_key = ec.private_value();
+
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(static_cast<size_t>(1))
+ .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), OCTET_STRING)
+ .start_cons(ASN1_Tag(0), PRIVATE)
+ .raw_bytes(ec.domain().DER_encode(EC_DOMPAR_ENC_OID))
+ .end_cons()
+ .start_cons(ASN1_Tag(1), PRIVATE)
+ .encode(pub_key.encode(PointGFp::UNCOMPRESSED), BIT_STRING)
+ .end_cons()
+ .end_cons()
+ .get_contents();
+ }
+
+int OpenSSL_EC_curve_builtin(int nid)
+ {
+ // the NID macro is still defined even though the curve may not be
+ // supported, so we need to check the list of builtin curves at runtime
+ EC_builtin_curve builtin_curves[100];
+ size_t num = 0;
+
+ if (!(num = EC_get_builtin_curves(builtin_curves, sizeof(builtin_curves))))
+ {
+ return -1;
+ }
+
+ for(size_t i = 0; i < num; ++i)
+ {
+ if(builtin_curves[i].nid == nid)
+ {
+ return nid;
+ }
+ }
+
+ return -1;
+ }
+
+int OpenSSL_EC_nid_for(const OID& oid)
+ {
+ if(oid.empty())
+ return -1;
+
+ const std::string name = oid.to_formatted_string();
+
+ if(name == "secp192r1")
+ return OpenSSL_EC_curve_builtin(NID_X9_62_prime192v1);
+ if(name == "secp224r1")
+ return OpenSSL_EC_curve_builtin(NID_secp224r1);
+ if(name == "secp256r1")
+ return OpenSSL_EC_curve_builtin(NID_X9_62_prime256v1);
+ if(name == "secp384r1")
+ return OpenSSL_EC_curve_builtin(NID_secp384r1);
+ if(name == "secp521r1")
+ return OpenSSL_EC_curve_builtin(NID_secp521r1);
+
+ // OpenSSL 1.0.2 added brainpool curves
+#if OPENSSL_VERSION_NUMBER >= 0x1000200fL
+ if(name == "brainpool160r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP160r1);
+ if(name == "brainpool192r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP192r1);
+ if(name == "brainpool224r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP224r1);
+ if(name == "brainpool256r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP256r1);
+ if(name == "brainpool320r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP320r1);
+ if(name == "brainpool384r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP384r1);
+ if(name == "brainpool512r1")
+ return OpenSSL_EC_curve_builtin(NID_brainpoolP512r1);
+#endif
+
+ return -1;
+ }
+
+}
+
+#endif
+
+#if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA)
+
+namespace {
+
+class OpenSSL_ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
+ {
+ public:
+ OpenSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa, int nid) :
+ PK_Ops::Verification_with_EMSA(emsa), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
+ {
+ std::unique_ptr<::EC_GROUP, std::function<void (::EC_GROUP*)>> grp(::EC_GROUP_new_by_curve_name(nid),
+ ::EC_GROUP_free);
+
+ if(!grp)
+ 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", 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", ERR_get_error());
+
+ const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
+ m_order_bits = ::EC_GROUP_get_degree(group);
+ }
+
+ size_t max_input_bits() const override { return m_order_bits; }
+
+ bool with_recovery() const override { return false; }
+
+ bool verify(const uint8_t msg[], size_t msg_len,
+ const uint8_t sig_bytes[], size_t sig_len) override
+ {
+ const size_t order_bytes = (m_order_bits + 7) / 8;
+ if(sig_len != 2 * order_bytes)
+ return false;
+
+ std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
+ sig.reset(::ECDSA_SIG_new());
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ sig->r = BN_bin2bn(sig_bytes , sig_len / 2, sig->r);
+ sig->s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, sig->s);
+#else
+ 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", ERR_get_error());
+
+ ECDSA_SIG_set0(sig.get(), r, s);
+#endif
+
+ const int res = ECDSA_do_verify(msg, msg_len, sig.get(), m_ossl_ec.get());
+ if(res < 0)
+ {
+ int err = ERR_get_error();
+
+ bool hard_error = true;
+
+#if defined(EC_R_BAD_SIGNATURE)
+ if(ERR_GET_REASON(err) == EC_R_BAD_SIGNATURE)
+ hard_error = false;
+#endif
+#if defined(EC_R_POINT_AT_INFINITY)
+ if(ERR_GET_REASON(err) == EC_R_POINT_AT_INFINITY)
+ hard_error = false;
+#endif
+#if defined(ECDSA_R_BAD_SIGNATURE)
+ if(ERR_GET_REASON(err) == ECDSA_R_BAD_SIGNATURE)
+ hard_error = false;
+#endif
+
+ if(hard_error)
+ throw OpenSSL_Error("ECDSA_do_verify", err);
+ }
+ return (res == 1);
+ }
+
+ private:
+ std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
+ size_t m_order_bits = 0;
+ };
+
+class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA
+ {
+ public:
+ OpenSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) :
+ PK_Ops::Signature_with_EMSA(emsa),
+ m_ossl_ec(nullptr, ::EC_KEY_free)
+ {
+ const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdsa);
+ 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", ERR_get_error());
+
+ const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
+ m_order_bits = ::EC_GROUP_get_degree(group);
+ m_order_bytes = (m_order_bits + 7) / 8;
+ }
+
+ size_t signature_length() const override { return 2*m_order_bytes; }
+
+ secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
+ RandomNumberGenerator&) override
+ {
+ std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
+ sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get()));
+
+ if(!sig)
+ throw OpenSSL_Error("ECDSA_do_sign", ERR_get_error());
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ const BIGNUM* r = sig->r;
+ const BIGNUM* s = sig->s;
+#else
+ const BIGNUM* r;
+ const BIGNUM* s;
+ ECDSA_SIG_get0(sig.get(), &r, &s);
+#endif
+
+ const size_t r_bytes = BN_num_bytes(r);
+ const size_t s_bytes = BN_num_bytes(s);
+ secure_vector<uint8_t> sigval(2*m_order_bytes);
+ BN_bn2bin(r, &sigval[m_order_bytes - r_bytes]);
+ BN_bn2bin(s, &sigval[2*m_order_bytes - s_bytes]);
+ return sigval;
+ }
+
+ size_t max_input_bits() const override { return m_order_bits; }
+
+ private:
+ std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
+ size_t m_order_bits;
+ size_t m_order_bytes;
+ };
+
+}
+
+std::unique_ptr<PK_Ops::Verification>
+make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params)
+ {
+ const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
+ if(nid < 0)
+ {
+ throw Lookup_Error("OpenSSL ECDSA does not support this curve");
+ }
+
+ try
+ {
+ return std::unique_ptr<PK_Ops::Verification>(new OpenSSL_ECDSA_Verification_Operation(key, params, nid));
+ }
+ catch(OpenSSL_Error&)
+ {
+ throw Lookup_Error("OpenSSL ECDSA does not support this key");
+ }
+ }
+
+std::unique_ptr<PK_Ops::Signature>
+make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params)
+ {
+ const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
+ if(nid < 0)
+ {
+ throw Lookup_Error("OpenSSL ECDSA does not support this curve");
+ }
+ return std::unique_ptr<PK_Ops::Signature>(new OpenSSL_ECDSA_Signing_Operation(key, params));
+ }
+
+#endif
+
+#if defined(BOTAN_HAS_ECDH) && !defined(OPENSSL_NO_ECDH)
+
+namespace {
+
+class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
+ {
+ public:
+
+ OpenSSL_ECDH_KA_Operation(const ECDH_PrivateKey& ecdh, const std::string& kdf) :
+ PK_Ops::Key_Agreement_with_KDF(kdf), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
+ {
+ m_value_size = ecdh.domain().get_p_bytes();
+ const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdh);
+ 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", ERR_get_error());
+ }
+
+ size_t agreed_value_size() const override { return m_value_size; }
+
+ secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override
+ {
+ const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
+ const size_t out_len = (::EC_GROUP_get_degree(group) + 7) / 8;
+ secure_vector<uint8_t> out(out_len);
+
+ std::unique_ptr<EC_POINT, std::function<void (EC_POINT*)>> pub_key(
+ ::EC_POINT_new(group), ::EC_POINT_free);
+
+ if(!pub_key)
+ throw OpenSSL_Error("EC_POINT_new", ERR_get_error());
+
+ const int os2ecp_rc =
+ ::EC_POINT_oct2point(group, pub_key.get(), w, w_len, nullptr);
+
+ if(os2ecp_rc != 1)
+ throw OpenSSL_Error("EC_POINT_oct2point", ERR_get_error());
+
+ const int ecdh_rc = ::ECDH_compute_key(out.data(),
+ out.size(),
+ pub_key.get(),
+ m_ossl_ec.get(),
+ /*KDF*/nullptr);
+
+ if(ecdh_rc <= 0)
+ throw OpenSSL_Error("ECDH_compute_key", ERR_get_error());
+
+ const size_t ecdh_sz = static_cast<size_t>(ecdh_rc);
+
+ if(ecdh_sz > out.size())
+ throw Internal_Error("OpenSSL ECDH returned more than requested");
+
+ out.resize(ecdh_sz);
+ return out;
+ }
+
+ private:
+ std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
+ size_t m_value_size;
+ };
+
+}
+
+std::unique_ptr<PK_Ops::Key_Agreement>
+make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params)
+ {
+ const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
+ if(nid < 0)
+ {
+ throw Lookup_Error("OpenSSL ECDH does not support this curve");
+ }
+
+ return std::unique_ptr<PK_Ops::Key_Agreement>(new OpenSSL_ECDH_KA_Operation(key, params));
+ }
+
+#endif
+
+}
+
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp
new file mode 100644
index 0000000000..9a56228c7b
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_hash.cpp
@@ -0,0 +1,136 @@
+/*
+* OpenSSL Hash Functions
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/hash.h>
+#include <botan/internal/openssl.h>
+#include <openssl/evp.h>
+#include <unordered_map>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_HashFunction final : public HashFunction
+ {
+ public:
+ void clear() override
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(m_md);
+ if(!EVP_DigestInit_ex(m_md, algo, nullptr))
+ throw OpenSSL_Error("EVP_DigestInit_ex", ERR_get_error());
+ }
+
+ std::string provider() const override { return "openssl"; }
+ std::string name() const override { return m_name; }
+
+ HashFunction* clone() const override
+ {
+ const EVP_MD* algo = EVP_MD_CTX_md(m_md);
+ return new OpenSSL_HashFunction(name(), algo);
+ }
+
+ std::unique_ptr<HashFunction> copy_state() const override
+ {
+ std::unique_ptr<OpenSSL_HashFunction> copy(new OpenSSL_HashFunction(m_name, nullptr));
+ EVP_MD_CTX_copy(copy->m_md, m_md);
+ return std::unique_ptr<HashFunction>(copy.release());
+ }
+
+ size_t output_length() const override
+ {
+ return EVP_MD_size(EVP_MD_CTX_md(m_md));
+ }
+
+ size_t hash_block_size() const override
+ {
+ return EVP_MD_block_size(EVP_MD_CTX_md(m_md));
+ }
+
+ OpenSSL_HashFunction(const std::string& name, const EVP_MD* md) : m_name(name)
+ {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ m_md = EVP_MD_CTX_create();
+#else
+ m_md = EVP_MD_CTX_new();
+#endif
+
+ if(m_md == nullptr)
+ 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", ERR_get_error());
+ }
+
+ OpenSSL_HashFunction(EVP_MD_CTX* ctx) : m_md(ctx)
+ {
+ }
+
+ ~OpenSSL_HashFunction()
+ {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ EVP_MD_CTX_destroy(m_md);
+#else
+ EVP_MD_CTX_free(m_md);
+#endif
+ }
+
+ private:
+ void add_data(const uint8_t input[], size_t length) override
+ {
+ if(!EVP_DigestUpdate(m_md, input, length))
+ 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", 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", ERR_get_error());
+ }
+
+ std::string m_name;
+ EVP_MD_CTX* m_md;
+ };
+
+}
+
+std::unique_ptr<HashFunction>
+make_openssl_hash(const std::string& name)
+ {
+#define MAKE_OPENSSL_HASH(fn) \
+ std::unique_ptr<HashFunction>(new OpenSSL_HashFunction(name, fn ()))
+
+#if defined(BOTAN_HAS_SHA2_32) && !defined(OPENSSL_NO_SHA256)
+ if(name == "SHA-224")
+ return MAKE_OPENSSL_HASH(EVP_sha224);
+ if(name == "SHA-256")
+ return MAKE_OPENSSL_HASH(EVP_sha256);
+#endif
+
+#if defined(BOTAN_HAS_SHA2_64) && !defined(OPENSSL_NO_SHA512)
+ if(name == "SHA-384")
+ return MAKE_OPENSSL_HASH(EVP_sha384);
+ if(name == "SHA-512")
+ return MAKE_OPENSSL_HASH(EVP_sha512);
+#endif
+
+#if defined(BOTAN_HAS_SHA1) && !defined(OPENSSL_NO_SHA)
+ if(name == "SHA-160" || name == "SHA-1" || name == "SHA1")
+ return MAKE_OPENSSL_HASH(EVP_sha1);
+#endif
+
+#if defined(BOTAN_HAS_MD5) && !defined(OPENSSL_NO_MD5)
+ if(name == "MD5")
+ return MAKE_OPENSSL_HASH(EVP_md5);
+ #endif
+
+ return nullptr;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp
new file mode 100644
index 0000000000..81f8413a2a
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_mode.cpp
@@ -0,0 +1,233 @@
+/*
+* Cipher Modes via OpenSSL
+* (C) 1999-2010,2015 Jack Lloyd
+* (C) 2017 Alexander Bluhm (genua GmbH)
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/cipher_mode.h>
+#include <botan/internal/rounding.h>
+#include <botan/internal/openssl.h>
+#include <openssl/evp.h>
+#include <limits.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_Cipher_Mode final : public Cipher_Mode
+ {
+ public:
+ OpenSSL_Cipher_Mode(const std::string& name,
+ const EVP_CIPHER* cipher,
+ Cipher_Dir direction);
+ ~OpenSSL_Cipher_Mode();
+
+ std::string provider() const override { return "openssl"; }
+ std::string name() const override { return m_mode_name; }
+
+ void start_msg(const uint8_t nonce[], size_t nonce_len) override;
+ size_t process(uint8_t msg[], size_t msg_len) override;
+ void finish(secure_vector<uint8_t>& final_block, size_t offset0) override;
+ size_t output_length(size_t input_length) const override;
+ size_t update_granularity() const override;
+ size_t minimum_final_size() const override;
+ size_t default_nonce_length() const override;
+ bool valid_nonce_length(size_t nonce_len) const override;
+ void clear() override;
+ void reset() override;
+ Key_Length_Specification key_spec() const override;
+
+ private:
+ void key_schedule(const uint8_t key[], size_t length) override;
+
+ const std::string m_mode_name;
+ const Cipher_Dir m_direction;
+ size_t m_block_size;
+ EVP_CIPHER_CTX* m_cipher;
+ bool m_key_set;
+ bool m_nonce_set;
+ };
+
+OpenSSL_Cipher_Mode::OpenSSL_Cipher_Mode(const std::string& name,
+ const EVP_CIPHER* algo,
+ Cipher_Dir direction) :
+ m_mode_name(name),
+ m_direction(direction),
+ m_key_set(false),
+ m_nonce_set(false)
+ {
+ m_block_size = EVP_CIPHER_block_size(algo);
+
+ if(EVP_CIPHER_mode(algo) != EVP_CIPH_CBC_MODE)
+ throw Invalid_Argument("OpenSSL_BlockCipher: Non-CBC EVP was passed in");
+
+ m_cipher = EVP_CIPHER_CTX_new();
+ if (m_cipher == nullptr)
+ 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", ERR_get_error());
+ if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0))
+ throw OpenSSL_Error("EVP_CIPHER_CTX_set_padding", ERR_get_error());
+ }
+
+OpenSSL_Cipher_Mode::~OpenSSL_Cipher_Mode()
+ {
+ EVP_CIPHER_CTX_free(m_cipher);
+ }
+
+void OpenSSL_Cipher_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
+ {
+ verify_key_set(m_key_set);
+
+ if(!valid_nonce_length(nonce_len))
+ throw Invalid_IV_Length(name(), nonce_len);
+
+ if(nonce_len)
+ {
+ if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, nullptr, nonce, -1))
+ 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", ERR_get_error());
+ }
+ // otherwise existing CBC state left unchanged
+
+ m_nonce_set = true;
+ }
+
+size_t OpenSSL_Cipher_Mode::process(uint8_t msg[], size_t msg_len)
+ {
+ verify_key_set(m_key_set);
+ BOTAN_STATE_CHECK(m_nonce_set);
+
+ if(msg_len == 0)
+ return 0;
+ if(msg_len > INT_MAX)
+ throw Internal_Error("msg_len overflow");
+ int outl = msg_len;
+ secure_vector<uint8_t> out(outl);
+
+ if(!EVP_CipherUpdate(m_cipher, out.data(), &outl, msg, msg_len))
+ throw OpenSSL_Error("EVP_CipherUpdate", ERR_get_error());
+ copy_mem(msg, out.data(), outl);
+ return outl;
+ }
+
+void OpenSSL_Cipher_Mode::finish(secure_vector<uint8_t>& buffer,
+ size_t offset)
+ {
+ verify_key_set(m_key_set);
+ BOTAN_STATE_CHECK(m_nonce_set);
+
+ BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
+ uint8_t* buf = buffer.data() + offset;
+ const size_t buf_size = buffer.size() - offset;
+
+ size_t written = process(buf, buf_size);
+ int outl = buf_size - written;
+ secure_vector<uint8_t> out(outl);
+
+ if(!EVP_CipherFinal_ex(m_cipher, out.data(), &outl))
+ throw OpenSSL_Error("EVP_CipherFinal_ex", ERR_get_error());
+ copy_mem(buf + written, out.data(), outl);
+ written += outl;
+ buffer.resize(offset + written);
+ }
+
+size_t OpenSSL_Cipher_Mode::update_granularity() const
+ {
+ return m_block_size * BOTAN_BLOCK_CIPHER_PAR_MULT;
+ }
+
+size_t OpenSSL_Cipher_Mode::minimum_final_size() const
+ {
+ return 0; // no padding
+ }
+
+size_t OpenSSL_Cipher_Mode::default_nonce_length() const
+ {
+ return m_block_size;
+ }
+
+bool OpenSSL_Cipher_Mode::valid_nonce_length(size_t nonce_len) const
+ {
+ return (nonce_len == 0 || nonce_len == m_block_size);
+ }
+
+size_t OpenSSL_Cipher_Mode::output_length(size_t input_length) const
+ {
+ if(input_length == 0)
+ return m_block_size;
+ else
+ return round_up(input_length, m_block_size);
+ }
+
+void OpenSSL_Cipher_Mode::clear()
+ {
+ m_key_set = false;
+ m_nonce_set = false;
+
+ const EVP_CIPHER* algo = EVP_CIPHER_CTX_cipher(m_cipher);
+
+ if(!EVP_CIPHER_CTX_cleanup(m_cipher))
+ 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", ERR_get_error());
+ if(!EVP_CIPHER_CTX_set_padding(m_cipher, 0))
+ 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", ERR_get_error());
+ m_nonce_set = false;
+ }
+
+Key_Length_Specification OpenSSL_Cipher_Mode::key_spec() const
+ {
+ return Key_Length_Specification(EVP_CIPHER_CTX_key_length(m_cipher));
+ }
+
+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", ERR_get_error());
+ if(!EVP_CipherInit_ex(m_cipher, nullptr, nullptr, key, nullptr, -1))
+ throw OpenSSL_Error("EVP_CipherInit_ex key", ERR_get_error());
+ m_key_set = true;
+ m_nonce_set = false;
+ }
+
+}
+
+Cipher_Mode*
+make_openssl_cipher_mode(const std::string& name, Cipher_Dir direction)
+ {
+#define MAKE_OPENSSL_MODE(evp_fn) \
+ new OpenSSL_Cipher_Mode(name, (evp_fn)(), direction)
+
+#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_MODE_CBC) && !defined(OPENSSL_NO_AES)
+ if(name == "AES-128/CBC/NoPadding")
+ return MAKE_OPENSSL_MODE(EVP_aes_128_cbc);
+ if(name == "AES-192/CBC/NoPadding")
+ return MAKE_OPENSSL_MODE(EVP_aes_192_cbc);
+ if(name == "AES-256/CBC/NoPadding")
+ return MAKE_OPENSSL_MODE(EVP_aes_256_cbc);
+#endif
+
+#undef MAKE_OPENSSL_MODE
+ return nullptr;
+ }
+
+}
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp
new file mode 100644
index 0000000000..dbda890f82
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_rc4.cpp
@@ -0,0 +1,93 @@
+/*
+* OpenSSL RC4
+* (C) 1999-2007,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/stream_cipher.h>
+
+#if defined(BOTAN_HAS_OPENSSL) && defined(BOTAN_HAS_RC4)
+
+#include <botan/internal/openssl.h>
+#include <botan/parsing.h>
+#include <botan/exceptn.h>
+#include <openssl/rc4.h>
+
+namespace Botan {
+
+namespace {
+
+class OpenSSL_RC4 final : public StreamCipher
+ {
+ public:
+ void clear() override { clear_mem(&m_rc4, 1); m_key_set = false; }
+
+ std::string provider() const override { return "openssl"; }
+
+ std::string name() const override
+ {
+ switch(m_skip)
+ {
+ case 0:
+ return "RC4";
+ case 256:
+ return "MARK-4";
+ default:
+ return "RC4(" + std::to_string(m_skip) + ")";
+ }
+ }
+
+ StreamCipher* clone() const override { return new OpenSSL_RC4(m_skip); }
+
+ Key_Length_Specification key_spec() const override
+ {
+ return Key_Length_Specification(1, 32);
+ }
+
+ explicit OpenSSL_RC4(size_t skip = 0) : m_skip(skip) { clear(); }
+ ~OpenSSL_RC4() { clear(); }
+
+ void set_iv(const uint8_t*, size_t len) override
+ {
+ if(len > 0)
+ throw Invalid_IV_Length("RC4", len);
+ }
+
+ void seek(uint64_t) override
+ {
+ throw Not_Implemented("RC4 does not support seeking");
+ }
+ private:
+ void cipher(const uint8_t in[], uint8_t out[], size_t length) override
+ {
+ verify_key_set(m_key_set);
+ ::RC4(&m_rc4, length, in, out);
+ }
+
+ void key_schedule(const uint8_t key[], size_t length) override
+ {
+ ::RC4_set_key(&m_rc4, length, key);
+ uint8_t d = 0;
+ for(size_t i = 0; i != m_skip; ++i)
+ ::RC4(&m_rc4, 1, &d, &d);
+ m_key_set = true;
+ }
+
+ size_t m_skip;
+ RC4_KEY m_rc4;
+ bool m_key_set;
+ };
+
+}
+
+std::unique_ptr<StreamCipher>
+make_openssl_rc4(size_t skip)
+ {
+ return std::unique_ptr<StreamCipher>(new OpenSSL_RC4(skip));
+ }
+
+
+}
+
+#endif
diff --git a/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp b/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp
new file mode 100644
index 0000000000..6744b35b2c
--- /dev/null
+++ b/comm/third_party/botan/src/lib/prov/openssl/openssl_rsa.cpp
@@ -0,0 +1,312 @@
+/*
+* RSA operations provided by OpenSSL
+* (C) 2015 Jack Lloyd
+* (C) 2017 Alexander Bluhm
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/openssl.h>
+
+#if defined(BOTAN_HAS_RSA)
+
+#include <botan/rsa.h>
+#include <botan/rng.h>
+#include <botan/internal/pk_ops_impl.h>
+#include <botan/internal/ct_utils.h>
+
+#include <functional>
+#include <memory>
+#include <cstdlib>
+
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <limits.h>
+
+namespace Botan {
+
+namespace {
+
+std::pair<int, size_t> get_openssl_enc_pad(const std::string& eme)
+ {
+ if(eme == "Raw")
+ return std::make_pair(RSA_NO_PADDING, 0);
+ else if(eme == "EME-PKCS1-v1_5")
+ return std::make_pair(RSA_PKCS1_PADDING, 11);
+ else if(eme == "OAEP(SHA-1)" || eme == "EME1(SHA-1)")
+ return std::make_pair(RSA_PKCS1_OAEP_PADDING, 41);
+ else
+ throw Lookup_Error("OpenSSL RSA does not support EME " + eme);
+ }
+
+class OpenSSL_RSA_Encryption_Operation final : public PK_Ops::Encryption
+ {
+ public:
+
+ OpenSSL_RSA_Encryption_Operation(const RSA_PublicKey& rsa, int pad, size_t pad_overhead) :
+ m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad)
+ {
+ const std::vector<uint8_t> der = rsa.public_key_bits();
+ 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", ERR_get_error());
+
+ m_bits = 8 * (n_size() - pad_overhead) - 1;
+ }
+
+ size_t ciphertext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); }
+
+ size_t max_input_bits() const override { return m_bits; };
+
+ secure_vector<uint8_t> encrypt(const uint8_t msg[], size_t msg_len,
+ RandomNumberGenerator&) override
+ {
+ const size_t mod_sz = n_size();
+
+ if(msg_len > mod_sz)
+ throw Invalid_Argument("Input too large for RSA key");
+
+ secure_vector<uint8_t> outbuf(mod_sz);
+
+ secure_vector<uint8_t> inbuf;
+
+ if(m_padding == RSA_NO_PADDING)
+ {
+ inbuf.resize(mod_sz);
+ copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len);
+ }
+ else
+ {
+ inbuf.assign(msg, msg + msg_len);
+ }
+
+ 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", ERR_get_error());
+
+ return outbuf;
+ }
+
+ private:
+ size_t n_size() const { return ::RSA_size(m_openssl_rsa.get()); }
+ std::unique_ptr<RSA, std::function<void (RSA*)>> m_openssl_rsa;
+ size_t m_bits = 0;
+ int m_padding = 0;
+ };
+
+class OpenSSL_RSA_Decryption_Operation final : public PK_Ops::Decryption
+ {
+ public:
+
+ OpenSSL_RSA_Decryption_Operation(const RSA_PrivateKey& rsa, int pad) :
+ m_openssl_rsa(nullptr, ::RSA_free), m_padding(pad)
+ {
+ const secure_vector<uint8_t> der = rsa.private_key_bits();
+ 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", ERR_get_error());
+ }
+
+ size_t plaintext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); }
+
+ secure_vector<uint8_t> decrypt(uint8_t& valid_mask,
+ const uint8_t msg[], size_t msg_len) override
+ {
+ secure_vector<uint8_t> buf(::RSA_size(m_openssl_rsa.get()));
+ int rc = ::RSA_private_decrypt(msg_len, msg, buf.data(), m_openssl_rsa.get(), m_padding);
+ if(rc < 0 || static_cast<size_t>(rc) > buf.size())
+ {
+ valid_mask = 0;
+ buf.resize(0);
+ }
+ else
+ {
+ valid_mask = 0xFF;
+ buf.resize(rc);
+ }
+
+ if(m_padding == RSA_NO_PADDING)
+ {
+ return CT::strip_leading_zeros(buf);
+ }
+
+ return buf;
+ }
+
+ private:
+ std::unique_ptr<RSA, std::function<void (RSA*)>> m_openssl_rsa;
+ int m_padding = 0;
+ };
+
+class OpenSSL_RSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
+ {
+ public:
+
+ OpenSSL_RSA_Verification_Operation(const RSA_PublicKey& rsa, const std::string& emsa) :
+ PK_Ops::Verification_with_EMSA(emsa),
+ m_openssl_rsa(nullptr, ::RSA_free)
+ {
+ const std::vector<uint8_t> der = rsa.public_key_bits();
+ 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", ERR_get_error());
+ }
+
+ size_t max_input_bits() const override
+ {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ return ::BN_num_bits(m_openssl_rsa->n) - 1;
+#else
+ return ::RSA_bits(m_openssl_rsa.get()) - 1;
+#endif
+ }
+
+ bool with_recovery() const override { return true; }
+
+ secure_vector<uint8_t> verify_mr(const uint8_t msg[], size_t msg_len) override
+ {
+ const size_t mod_sz = ::RSA_size(m_openssl_rsa.get());
+
+ if(msg_len > mod_sz)
+ throw Invalid_Argument("OpenSSL RSA verify input too large");
+
+ secure_vector<uint8_t> inbuf(mod_sz);
+
+ if(msg_len > 0)
+ copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len);
+
+ secure_vector<uint8_t> outbuf(mod_sz);
+
+ int rc = ::RSA_public_decrypt(inbuf.size(), inbuf.data(), outbuf.data(),
+ m_openssl_rsa.get(), RSA_NO_PADDING);
+ if(rc < 0)
+ throw Invalid_Argument("RSA_public_decrypt");
+
+ return CT::strip_leading_zeros(outbuf);
+ }
+ private:
+ std::unique_ptr<RSA, std::function<void (RSA*)>> m_openssl_rsa;
+ };
+
+class OpenSSL_RSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA
+ {
+ public:
+
+ OpenSSL_RSA_Signing_Operation(const RSA_PrivateKey& rsa, const std::string& emsa) :
+ PK_Ops::Signature_with_EMSA(emsa),
+ m_openssl_rsa(nullptr, ::RSA_free)
+ {
+ const secure_vector<uint8_t> der = rsa.private_key_bits();
+ 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", ERR_get_error());
+ }
+
+ size_t signature_length() const override { return ::RSA_size(m_openssl_rsa.get()); }
+
+ secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
+ RandomNumberGenerator&) override
+ {
+ const size_t mod_sz = ::RSA_size(m_openssl_rsa.get());
+
+ if(msg_len > mod_sz)
+ throw Invalid_Argument("OpenSSL RSA sign input too large");
+
+ secure_vector<uint8_t> inbuf(mod_sz);
+ copy_mem(&inbuf[mod_sz - msg_len], msg, msg_len);
+
+ secure_vector<uint8_t> outbuf(mod_sz);
+
+ 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", ERR_get_error());
+
+ return outbuf;
+ }
+
+ size_t max_input_bits() const override
+ {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ return ::BN_num_bits(m_openssl_rsa->n) - 1;
+#else
+ return ::RSA_bits(m_openssl_rsa.get()) - 1;
+#endif
+ }
+
+ private:
+ std::unique_ptr<RSA, std::function<void (RSA*)>> m_openssl_rsa;
+ };
+
+}
+
+std::unique_ptr<PK_Ops::Encryption>
+make_openssl_rsa_enc_op(const RSA_PublicKey& key, const std::string& params)
+ {
+ auto pad_info = get_openssl_enc_pad(params);
+ return std::unique_ptr<PK_Ops::Encryption>(
+ new OpenSSL_RSA_Encryption_Operation(key, pad_info.first, pad_info.second));
+ }
+
+std::unique_ptr<PK_Ops::Decryption>
+make_openssl_rsa_dec_op(const RSA_PrivateKey& key, const std::string& params)
+ {
+ auto pad_info = get_openssl_enc_pad(params);
+ return std::unique_ptr<PK_Ops::Decryption>(new OpenSSL_RSA_Decryption_Operation(key, pad_info.first));
+ }
+
+std::unique_ptr<PK_Ops::Verification>
+make_openssl_rsa_ver_op(const RSA_PublicKey& key, const std::string& params)
+ {
+ return std::unique_ptr<PK_Ops::Verification>(new OpenSSL_RSA_Verification_Operation(key, params));
+ }
+
+std::unique_ptr<PK_Ops::Signature>
+make_openssl_rsa_sig_op(const RSA_PrivateKey& key, const std::string& params)
+ {
+ return std::unique_ptr<PK_Ops::Signature>(new OpenSSL_RSA_Signing_Operation(key, params));
+ }
+
+std::unique_ptr<RSA_PrivateKey>
+make_openssl_rsa_private_key(RandomNumberGenerator& rng, size_t rsa_bits)
+ {
+ if (rsa_bits > INT_MAX)
+ throw Internal_Error("rsa_bits overflow");
+
+ secure_vector<uint8_t> seed(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ rng.randomize(seed.data(), seed.size());
+ RAND_seed(seed.data(), seed.size());
+
+ std::unique_ptr<BIGNUM, std::function<void (BIGNUM*)>> bn(BN_new(), BN_free);
+ if(!bn)
+ throw OpenSSL_Error("BN_new", ERR_get_error());
+ if(!BN_set_word(bn.get(), RSA_F4))
+ 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", ERR_get_error());
+ if(!RSA_generate_key_ex(rsa.get(), rsa_bits, bn.get(), nullptr))
+ 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", ERR_get_error());
+
+ const secure_vector<uint8_t> keydata(der, der + bytes);
+ secure_scrub_memory(der, bytes);
+ std::free(der);
+ return std::unique_ptr<Botan::RSA_PrivateKey>
+ (new RSA_PrivateKey(AlgorithmIdentifier(), keydata));
+ }
+}
+
+#endif // BOTAN_HAS_RSA