aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-05-03 10:13:25 -0400
committerJack Lloyd <[email protected]>2017-05-03 10:13:25 -0400
commit7f4f579db4408253c60c52b8f5bbe2b64aa88f1d (patch)
tree5c7f9973252360cbea24c50c0f6848efd86df3f2 /src
parent7cfdb78e5267ba542e9a8248cbec5f34033b6e42 (diff)
parent17afb2681aa704d8241f4dcaeb949d806ba8df09 (diff)
Merge GH #1035 Support generating RSA keys with OpenSSL
Diffstat (limited to 'src')
-rw-r--r--src/lib/prov/openssl/openssl.h3
-rw-r--r--src/lib/prov/openssl/openssl_rsa.cpp36
-rw-r--r--src/lib/pubkey/pk_algs.cpp36
-rw-r--r--src/lib/pubkey/pk_algs.h7
-rw-r--r--src/tests/test_pubkey.cpp196
-rw-r--r--src/tests/test_pubkey.h2
-rw-r--r--src/tests/tests.cpp10
-rw-r--r--src/tests/tests.h2
8 files changed, 195 insertions, 97 deletions
diff --git a/src/lib/prov/openssl/openssl.h b/src/lib/prov/openssl/openssl.h
index 3cd39113b..37e8f9d4b 100644
--- a/src/lib/prov/openssl/openssl.h
+++ b/src/lib/prov/openssl/openssl.h
@@ -27,6 +27,7 @@ class BlockCipher;
class Cipher_Mode;
class StreamCipher;
class HashFunction;
+class RandomNumberGenerator;
enum Cipher_Dir : int;
class OpenSSL_Error : public Exception
@@ -67,6 +68,8 @@ 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
diff --git a/src/lib/prov/openssl/openssl_rsa.cpp b/src/lib/prov/openssl/openssl_rsa.cpp
index 22cd6eb96..8c25d00ef 100644
--- a/src/lib/prov/openssl/openssl_rsa.cpp
+++ b/src/lib/prov/openssl/openssl_rsa.cpp
@@ -1,6 +1,7 @@
/*
* RSA operations provided by OpenSSL
* (C) 2015 Jack Lloyd
+* (C) 2017 Alexander Bluhm
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,6 +11,7 @@
#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>
@@ -19,6 +21,7 @@
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/err.h>
+#include <openssl/rand.h>
namespace Botan {
@@ -247,6 +250,39 @@ 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");
+ if(!BN_set_word(bn.get(), RSA_F4))
+ throw OpenSSL_Error("BN_set_word");
+
+ std::unique_ptr<RSA, std::function<void (RSA*)>> rsa(RSA_new(), RSA_free);
+ if(!rsa)
+ throw OpenSSL_Error("RSA_new");
+ if(!RSA_generate_key_ex(rsa.get(), rsa_bits, bn.get(), NULL))
+ throw OpenSSL_Error("RSA_generate_key_ex");
+
+ uint8_t* der = NULL;
+ int bytes = i2d_RSAPrivateKey(rsa.get(), &der);
+ if(bytes < 0)
+ throw OpenSSL_Error("i2d_RSAPrivateKey");
+
+ const secure_vector<uint8_t> keydata(der, der + bytes);
+ memset(der, 0, bytes);
+ free(der);
+ return std::unique_ptr<Botan::RSA_PrivateKey>
+ (new RSA_PrivateKey(AlgorithmIdentifier(), keydata));
+ }
}
#endif // BOTAN_HAS_RSA
diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp
index 1e1fd739a..19d7361b4 100644
--- a/src/lib/pubkey/pk_algs.cpp
+++ b/src/lib/pubkey/pk_algs.cpp
@@ -56,6 +56,10 @@
#include <botan/xmss.h>
#endif
+#if defined(BOTAN_HAS_OPENSSL)
+ #include <botan/internal/openssl.h>
+#endif
+
namespace Botan {
std::unique_ptr<Public_Key>
@@ -203,7 +207,8 @@ load_private_key(const AlgorithmIdentifier& alg_id,
std::unique_ptr<Private_Key>
create_private_key(const std::string& alg_name,
RandomNumberGenerator& rng,
- const std::string& params)
+ const std::string& params,
+ const std::string& provider)
{
/*
* Default paramaters are chosen for work factor > 2**128 where possible
@@ -218,6 +223,17 @@ create_private_key(const std::string& alg_name,
if(alg_name == "RSA")
{
const size_t rsa_bits = (params.empty() ? 3072 : to_u32bit(params));
+#if defined(BOTAN_HAS_OPENSSL)
+ if(provider.empty() || provider == "openssl")
+ {
+ std::unique_ptr<Botan::Private_Key> pk;
+ if(pk = make_openssl_rsa_private_key(rng, rsa_bits))
+ return pk;
+
+ if(!provider.empty())
+ return nullptr;
+ }
+#endif
return std::unique_ptr<Private_Key>(new RSA_PrivateKey(rng, rsa_bits));
}
#endif
@@ -311,4 +327,22 @@ create_private_key(const std::string& alg_name,
return std::unique_ptr<Private_Key>();
}
+std::vector<std::string>
+probe_provider_private_key(const std::string& alg_name,
+ const std::vector<std::string> possible)
+ {
+ std::vector<std::string> providers;
+ for(auto&& prov : possible)
+ {
+ if(prov == "base" ||
+#if defined(BOTAN_HAS_OPENSSL)
+ (prov == "openssl" && alg_name == "RSA") ||
+#endif
+ 0)
+ {
+ providers.push_back(prov); // available
+ }
+ }
+ return providers;
+ }
}
diff --git a/src/lib/pubkey/pk_algs.h b/src/lib/pubkey/pk_algs.h
index 04248459b..5deded423 100644
--- a/src/lib/pubkey/pk_algs.h
+++ b/src/lib/pubkey/pk_algs.h
@@ -33,7 +33,12 @@ load_private_key(const AlgorithmIdentifier& alg_id,
BOTAN_DLL std::unique_ptr<Private_Key>
create_private_key(const std::string& algo_name,
RandomNumberGenerator& rng,
- const std::string& algo_params = "");
+ const std::string& algo_params = "",
+ const std::string& provider = "");
+
+BOTAN_DLL std::vector<std::string>
+probe_provider_private_key(const std::string& algo_name,
+ const std::vector<std::string> possible);
}
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
index 95cff74a3..a38b7d3f3 100644
--- a/src/tests/test_pubkey.cpp
+++ b/src/tests/test_pubkey.cpp
@@ -402,6 +402,14 @@ Test::Result PK_Key_Agreement_Test::run_one_test(const std::string& header, cons
return result;
}
+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" });
+ return Test::provider_filter(pk_provider);
+ }
+
std::vector<Test::Result> PK_Key_Generation_Test::run()
{
std::vector<Test::Result> results;
@@ -412,115 +420,125 @@ std::vector<Test::Result> PK_Key_Generation_Test::run()
Test::Result result(report_name + " keygen");
+ const std::vector<std::string> providers = possible_providers(algo_name());
+
+ if(providers.empty())
+ {
+ result.note_missing("provider key generation " + algo_name());
+ }
+
result.start_timer();
- std::unique_ptr<Botan::Private_Key> key_p =
- Botan::create_private_key(algo_name(), Test::rng(), param);
+ for(auto&& prov : providers)
+ {
+ std::unique_ptr<Botan::Private_Key> key_p =
+ Botan::create_private_key(algo_name(), Test::rng(), param, prov);
- const Botan::Private_Key& key = *key_p;
+ const Botan::Private_Key& key = *key_p;
- result.confirm("Key passes self tests", key.check_key(Test::rng(), true));
+ result.confirm("Key passes self tests", key.check_key(Test::rng(), true));
- result.test_gte("Key has reasonable estimated strength (lower)", key.estimated_strength(), 64);
- result.test_lt("Key has reasonable estimated strength (upper)", key.estimated_strength(), 512);
+ result.test_gte("Key has reasonable estimated strength (lower)", key.estimated_strength(), 64);
+ result.test_lt("Key has reasonable estimated strength (upper)", key.estimated_strength(), 512);
- // Test PEM public key round trips OK
- try
- {
- Botan::DataSource_Memory data_src(Botan::X509::PEM_encode(key));
- std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
+ // Test PEM public key round trips OK
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::X509::PEM_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
- result.confirm("recovered public key from private", loaded.get() != nullptr);
- result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip PEM public key", e.what());
- }
+ result.confirm("recovered public key from private", loaded.get() != nullptr);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip PEM public key", e.what());
+ }
- // Test DER public key round trips OK
- try
- {
- Botan::DataSource_Memory data_src(Botan::X509::BER_encode(key));
- std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
+ // Test DER public key round trips OK
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::X509::BER_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::X509::load_key(data_src));
- result.confirm("recovered public key from private", loaded.get() != nullptr);
- result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip BER public key", e.what());
- }
+ result.confirm("recovered public key from private", loaded.get() != nullptr);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip BER public key", e.what());
+ }
- // Test PEM private key round trips OK
- try
- {
- Botan::DataSource_Memory data_src(Botan::PKCS8::PEM_encode(key));
- std::unique_ptr<Botan::Private_Key> loaded(
- Botan::PKCS8::load_key(data_src, Test::rng()));
+ // Test PEM private key round trips OK
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::PKCS8::PEM_encode(key));
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng()));
- result.confirm("recovered private key from PEM blob", loaded.get() != nullptr);
- result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip PEM private key", e.what());
- }
+ result.confirm("recovered private key from PEM blob", loaded.get() != nullptr);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip PEM private key", e.what());
+ }
- try
- {
- Botan::DataSource_Memory data_src(Botan::PKCS8::BER_encode(key));
- std::unique_ptr<Botan::Public_Key> loaded(Botan::PKCS8::load_key(data_src, Test::rng()));
+ try
+ {
+ Botan::DataSource_Memory data_src(Botan::PKCS8::BER_encode(key));
+ std::unique_ptr<Botan::Public_Key> loaded(Botan::PKCS8::load_key(data_src, Test::rng()));
- result.confirm("recovered public key from private", loaded.get() != nullptr);
- result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip BER private key", e.what());
- }
+ result.confirm("recovered public key from private", loaded.get() != nullptr);
+ result.test_eq("public key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("public key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip BER private key", e.what());
+ }
- const std::string passphrase = Test::random_password();
+ const std::string passphrase = Test::random_password();
- try
- {
- Botan::DataSource_Memory data_src(
- Botan::PKCS8::PEM_encode(key, Test::rng(), passphrase,
- std::chrono::milliseconds(10)));
+ try
+ {
+ Botan::DataSource_Memory data_src(
+ Botan::PKCS8::PEM_encode(key, Test::rng(), passphrase,
+ std::chrono::milliseconds(10)));
- std::unique_ptr<Botan::Private_Key> loaded(
- Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
- result.confirm("recovered private key from encrypted blob", loaded.get() != nullptr);
- result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip encrypted PEM private key", e.what());
- }
+ result.confirm("recovered private key from encrypted blob", loaded.get() != nullptr);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip encrypted PEM private key", e.what());
+ }
- try
- {
- Botan::DataSource_Memory data_src(
- Botan::PKCS8::BER_encode(key, Test::rng(), passphrase,
- std::chrono::milliseconds(10)));
+ try
+ {
+ Botan::DataSource_Memory data_src(
+ Botan::PKCS8::BER_encode(key, Test::rng(), passphrase,
+ std::chrono::milliseconds(10)));
- std::unique_ptr<Botan::Private_Key> loaded(
- Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
+ std::unique_ptr<Botan::Private_Key> loaded(
+ Botan::PKCS8::load_key(data_src, Test::rng(), passphrase));
- result.confirm("recovered private key from BER blob", loaded.get() != nullptr);
- result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
- result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
- }
- catch(std::exception& e)
- {
- result.test_failure("roundtrip encrypted BER private key", e.what());
- }
+ result.confirm("recovered private key from BER blob", loaded.get() != nullptr);
+ result.test_eq("reloaded key has same type", loaded->algo_name(), key.algo_name());
+ result.test_eq("private key passes checks", loaded->check_key(Test::rng(), false), true);
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure("roundtrip encrypted BER private key", e.what());
+ }
+ }
result.end_timer();
results.push_back(result);
diff --git a/src/tests/test_pubkey.h b/src/tests/test_pubkey.h
index 88a3d1c45..4a2ca6866 100644
--- a/src/tests/test_pubkey.h
+++ b/src/tests/test_pubkey.h
@@ -171,6 +171,8 @@ class PK_Key_Generation_Test : public Test
virtual std::vector<std::string> keygen_params() const = 0;
virtual std::string algo_name() const = 0;
+
+ std::vector<std::string> possible_providers(const std::string&) override;
};
void check_invalid_signatures(Test::Result& result,
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index 78c579140..2252cb221 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -366,6 +366,11 @@ bool Test::Result::test_rc(const std::string& func, int expected, int rc)
return test_success();
}
+std::vector<std::string> Test::possible_providers(const std::string&)
+ {
+ return Test::provider_filter({ "base" });
+ }
+
//static
std::string Test::format_time(uint64_t ns)
{
@@ -912,11 +917,6 @@ parse_cpuid_bits(const std::vector<std::string>& tok)
}
-std::vector<std::string> Text_Based_Test::possible_providers(const std::string&)
- {
- return Test::provider_filter({ "base" });
- }
-
bool Text_Based_Test::skip_this_test(const std::string& /*header*/,
const VarMap& /*vars*/)
{
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 4e992e0d6..0673705d9 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -352,6 +352,7 @@ class Test
virtual std::vector<Test::Result> run() = 0;
virtual ~Test() = default;
+ virtual std::vector<std::string> possible_providers(const std::string&);
static std::vector<Test::Result> run_test(const std::string& what, bool fail_if_missing);
@@ -463,7 +464,6 @@ class Text_Based_Test : public Test
virtual Test::Result run_one_test(const std::string& header,
const VarMap& vars) = 0;
// Called before run_one_test
- virtual std::vector<std::string> possible_providers(const std::string&);
virtual bool skip_this_test(const std::string& header,
const VarMap& vars);