aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-08-02 16:53:38 -0400
committerJack Lloyd <[email protected]>2017-08-02 16:53:38 -0400
commit230b7ad5a259631dba617aba596ce7619a24ca17 (patch)
tree36a2141cc63d3715d3c7c654eebe3fcf291ad182 /src
parent5a9b5c2c2f32909ab7963307291827ed7bd2d102 (diff)
parent825c23811f480d3c3646ded125c9e7b7dc9feb8f (diff)
Merge GH #1094 Add initial BearSSL provider
Diffstat (limited to 'src')
-rw-r--r--src/lib/hash/hash.cpp17
-rw-r--r--src/lib/prov/bearssl/bearssl.h50
-rw-r--r--src/lib/prov/bearssl/bearssl_ec.cpp209
-rw-r--r--src/lib/prov/bearssl/bearssl_hash.cpp120
-rw-r--r--src/lib/prov/bearssl/info.txt13
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.cpp34
-rw-r--r--src/tests/test_pubkey.cpp4
7 files changed, 444 insertions, 3 deletions
diff --git a/src/lib/hash/hash.cpp b/src/lib/hash/hash.cpp
index c8dd58a66..bd162ff2c 100644
--- a/src/lib/hash/hash.cpp
+++ b/src/lib/hash/hash.cpp
@@ -88,6 +88,10 @@
#include <botan/blake2b.h>
#endif
+#if defined(BOTAN_HAS_BEARSSL)
+ #include <botan/internal/bearssl.h>
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
#include <botan/internal/openssl.h>
#endif
@@ -108,6 +112,17 @@ std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
}
#endif
+#if defined(BOTAN_HAS_BEARSSL)
+ if(provider.empty() || provider == "bearssl")
+ {
+ if(auto hash = make_bearssl_hash(algo_spec))
+ return hash;
+
+ if(!provider.empty())
+ return nullptr;
+ }
+#endif
+
// TODO: CommonCrypto hashes
if(provider.empty() == false && provider != "base")
@@ -323,7 +338,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", "openssl"});
+ return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl"});
}
}
diff --git a/src/lib/prov/bearssl/bearssl.h b/src/lib/prov/bearssl/bearssl.h
new file mode 100644
index 000000000..1ba7d2dc6
--- /dev/null
+++ b/src/lib/prov/bearssl/bearssl.h
@@ -0,0 +1,50 @@
+/*
+* Utils for calling BearSSL
+* (C) 2015,2016 Jack Lloyd
+* (C) 2017 Patrick Wildt
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_INTERNAL_BEARSSL_H__
+#define BOTAN_INTERNAL_BEARSSL_H__
+
+#include <botan/pk_ops_fwd.h>
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <memory>
+#include <string>
+
+namespace Botan {
+
+class HashFunction;
+
+class BearSSL_Error : public Exception
+ {
+ public:
+ BearSSL_Error(const std::string& what) :
+ Exception(what + " failed") {}
+ };
+
+/* Hash */
+
+std::unique_ptr<HashFunction>
+make_bearssl_hash(const std::string& name);
+
+/* ECDSA */
+
+#if defined(BOTAN_HAS_ECDSA)
+
+class ECDSA_PublicKey;
+class ECDSA_PrivateKey;
+
+std::unique_ptr<PK_Ops::Verification>
+make_bearssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params);
+std::unique_ptr<PK_Ops::Signature>
+make_bearssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params);
+
+#endif
+
+}
+
+#endif
diff --git a/src/lib/prov/bearssl/bearssl_ec.cpp b/src/lib/prov/bearssl/bearssl_ec.cpp
new file mode 100644
index 000000000..fe661f357
--- /dev/null
+++ b/src/lib/prov/bearssl/bearssl_ec.cpp
@@ -0,0 +1,209 @@
+/*
+* ECDSA via BearSSL
+* (C) 2015,2016 Jack Lloyd
+* (C) 2017 Patrick Wildt
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/exceptn.h>
+#include <botan/hash.h>
+#include <botan/scan_name.h>
+#include <botan/internal/bearssl.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+ #include <botan/der_enc.h>
+ #include <botan/pkcs8.h>
+ #include <botan/oids.h>
+ #include <botan/internal/pk_ops_impl.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+extern "C" {
+ #include <bearssl_hash.h>
+ #include <bearssl_ec.h>
+}
+
+namespace Botan {
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+namespace {
+
+int BearSSL_EC_curve_for(const OID& oid)
+ {
+ if(oid.empty())
+ return -1;
+
+ const std::string name = OIDS::lookup(oid);
+
+ if(name == "secp256r1")
+ return BR_EC_secp256r1;
+ if(name == "secp384r1")
+ return BR_EC_secp384r1;
+ if(name == "secp521r1")
+ return BR_EC_secp521r1;
+
+ return -1;
+ }
+
+const br_hash_class *BearSSL_hash_class_for(const std::string& emsa)
+ {
+ if (emsa == "EMSA1(SHA-1)")
+ return &br_sha1_vtable;
+ if (emsa == "EMSA1(SHA-224)")
+ return &br_sha224_vtable;
+ if (emsa == "EMSA1(SHA-256)")
+ return &br_sha256_vtable;
+ if (emsa == "EMSA1(SHA-384)")
+ return &br_sha384_vtable;
+ if (emsa == "EMSA1(SHA-512)")
+ return &br_sha512_vtable;
+
+ return nullptr;
+ }
+}
+
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+
+namespace {
+
+class BearSSL_ECDSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ BearSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa) :
+ m_order_bits(ecdsa.domain().get_order().bits())
+ {
+ const int curve = BearSSL_EC_curve_for(ecdsa.domain().get_oid());
+ if (curve < 0)
+ throw Lookup_Error("BearSSL ECDSA does not support this curve");
+
+ m_hash = BearSSL_hash_class_for(emsa);
+ if (m_hash == nullptr)
+ throw Lookup_Error("BearSSL ECDSA does not support EMSA " + emsa);
+
+ const SCAN_Name req(emsa);
+ m_hf = make_bearssl_hash(req.arg(0));
+ if (m_hf == nullptr)
+ throw Lookup_Error("BearSSL ECDSA does not support hash " + req.arg(0));
+
+ const secure_vector<uint8_t> enc = EC2OSP(ecdsa.public_point(), PointGFp::UNCOMPRESSED);
+ m_key.qlen = enc.size();
+ m_key.q = new uint8_t[m_key.qlen];
+ memcpy(m_key.q, enc.data(), m_key.qlen);
+ m_key.curve = curve;
+ }
+
+ void update(const uint8_t msg[], size_t msg_len) override
+ {
+ m_hf->update(msg, msg_len);
+ }
+
+ bool is_valid_signature(const uint8_t sig[], size_t sig_len) override
+ {
+ const size_t order_bytes = (m_order_bits + 7) / 8;
+ if (sig_len != 2 * order_bytes)
+ return false;
+ secure_vector<uint8_t> msg = m_hf->final();
+
+ br_ecdsa_vrfy engine = br_ecdsa_vrfy_raw_get_default();
+ if (!engine(&br_ec_prime_i31, msg.data(), msg.size(), &m_key, sig, sig_len))
+ return false;
+
+ return true;
+ }
+
+ size_t max_input_bits() const { return m_order_bits; }
+
+ ~BearSSL_ECDSA_Verification_Operation()
+ {
+ delete m_key.q;
+ }
+
+ private:
+ br_ec_public_key m_key;
+ std::unique_ptr<HashFunction> m_hf;
+ const br_hash_class *m_hash;
+ size_t m_order_bits;
+ };
+
+class BearSSL_ECDSA_Signing_Operation : public PK_Ops::Signature
+ {
+ public:
+ BearSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) :
+ m_order_bits(ecdsa.domain().get_order().bits())
+ {
+ const int curve = BearSSL_EC_curve_for(ecdsa.domain().get_oid());
+ if(curve < 0)
+ throw Lookup_Error("BearSSL ECDSA does not support this curve");
+
+ m_hash = BearSSL_hash_class_for(emsa);
+ if (m_hash == nullptr)
+ throw Lookup_Error("BearSSL ECDSA does not support EMSA " + emsa);
+
+ const SCAN_Name req(emsa);
+ m_hf = make_bearssl_hash(req.arg(0));
+ if (m_hf == nullptr)
+ throw Lookup_Error("BearSSL ECDSA does not support hash " + req.arg(0));
+
+ m_key.xlen = ecdsa.private_value().bytes();
+ m_key.x = new uint8_t[m_key.xlen];
+ ecdsa.private_value().binary_encode(m_key.x);
+ m_key.curve = curve;
+ }
+
+ void update(const uint8_t msg[], size_t msg_len) override
+ {
+ m_hf->update(msg, msg_len);
+ }
+
+ secure_vector<uint8_t> sign(RandomNumberGenerator&) override
+ {
+ const size_t order_bytes = (m_order_bits + 7) / 8;
+ secure_vector<uint8_t> sigval(2*order_bytes);
+
+ br_ecdsa_sign engine = br_ecdsa_sign_raw_get_default();
+ size_t sign_len = engine(&br_ec_prime_i31, m_hash, m_hf->final().data(), &m_key, sigval.data());
+ if (sign_len == 0)
+ throw BearSSL_Error("br_ecdsa_sign");
+
+ sigval.resize(sign_len);
+ return sigval;
+ }
+
+ size_t max_input_bits() const { return m_order_bits; }
+
+ ~BearSSL_ECDSA_Signing_Operation()
+ {
+ delete m_key.x;
+ }
+
+ private:
+ br_ec_private_key m_key;
+ std::unique_ptr<HashFunction> m_hf;
+ const br_hash_class *m_hash;
+ size_t m_order_bits;
+ };
+
+}
+
+std::unique_ptr<PK_Ops::Verification>
+make_bearssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params)
+ {
+ return std::unique_ptr<PK_Ops::Verification>(new BearSSL_ECDSA_Verification_Operation(key, params));
+ }
+
+std::unique_ptr<PK_Ops::Signature>
+make_bearssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params)
+ {
+ return std::unique_ptr<PK_Ops::Signature>(new BearSSL_ECDSA_Signing_Operation(key, params));
+ }
+
+#endif
+
+}
diff --git a/src/lib/prov/bearssl/bearssl_hash.cpp b/src/lib/prov/bearssl/bearssl_hash.cpp
new file mode 100644
index 000000000..9620d6d70
--- /dev/null
+++ b/src/lib/prov/bearssl/bearssl_hash.cpp
@@ -0,0 +1,120 @@
+/*
+* BearSSL Hash Functions
+* (C) 1999-2007,2015 Jack Lloyd
+* (C) 2017 Patrick Wildt
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/hash.h>
+#include <botan/internal/bearssl.h>
+#include <unordered_map>
+
+extern "C" {
+ #include <bearssl_hash.h>
+}
+
+namespace Botan {
+
+namespace {
+
+class BearSSL_HashFunction : public HashFunction
+ {
+ public:
+ void clear() override
+ {
+ m_ctx.vtable->init(&m_ctx.vtable);
+ }
+
+ std::string provider() const override { return "bearssl"; }
+ std::string name() const override { return m_name; }
+
+ HashFunction* clone() const override
+ {
+ return new BearSSL_HashFunction(m_ctx.vtable, m_name);
+ }
+
+ std::unique_ptr<HashFunction> copy_state() const override
+ {
+ std::unique_ptr<BearSSL_HashFunction> copy(new BearSSL_HashFunction(m_ctx.vtable, m_name));
+ memcpy(&copy->m_ctx, &m_ctx, sizeof(m_ctx));
+ return std::move(copy);
+ }
+
+ size_t output_length() const override
+ {
+ return (m_ctx.vtable->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ }
+
+ size_t hash_block_size() const override
+ {
+ return 1 << ((m_ctx.vtable->desc >> BR_HASHDESC_LBLEN_OFF) & BR_HASHDESC_LBLEN_MASK);
+ }
+
+ BearSSL_HashFunction(const br_hash_class *hash, const std::string name)
+ {
+ m_name = name;
+ hash->init(&m_ctx.vtable);
+ }
+
+ ~BearSSL_HashFunction()
+ {
+ }
+
+ private:
+ void add_data(const uint8_t input[], size_t length) override
+ {
+ m_ctx.vtable->update(&m_ctx.vtable, input, length);
+ }
+
+ void final_result(uint8_t output[]) override
+ {
+ m_ctx.vtable->out(&m_ctx.vtable, output);
+ m_ctx.vtable->init(&m_ctx.vtable);
+ }
+
+ std::string m_name;
+ br_hash_compat_context m_ctx;
+ };
+
+}
+
+std::unique_ptr<HashFunction>
+make_bearssl_hash(const std::string& name)
+ {
+#define MAKE_BEARSSL_HASH(vtable) \
+ std::unique_ptr<HashFunction>(new BearSSL_HashFunction(vtable, name))
+
+#if defined(BOTAN_HAS_SHA2_32)
+ if(name == "SHA-224")
+ return MAKE_BEARSSL_HASH(&br_sha224_vtable);
+ if(name == "SHA-256")
+ return MAKE_BEARSSL_HASH(&br_sha256_vtable);
+#endif
+
+#if defined(BOTAN_HAS_SHA2_64)
+ if(name == "SHA-384")
+ return MAKE_BEARSSL_HASH(&br_sha384_vtable);
+ if(name == "SHA-512")
+ return MAKE_BEARSSL_HASH(&br_sha512_vtable);
+#endif
+
+#if defined(BOTAN_HAS_SHA1)
+ if(name == "SHA-160" || name == "SHA-1")
+ return MAKE_BEARSSL_HASH(&br_sha1_vtable);
+#endif
+
+#if defined(BOTAN_HAS_MD5)
+ if(name == "MD5")
+ return MAKE_BEARSSL_HASH(&br_md5_vtable);
+#endif
+
+#if defined(BOTAN_HAS_PARALLEL_HASH)
+ if(name == "Parallel(MD5,SHA-160)")
+ return MAKE_BEARSSL_HASH(&br_md5sha1_vtable);
+#endif
+
+ return nullptr;
+ }
+
+}
diff --git a/src/lib/prov/bearssl/info.txt b/src/lib/prov/bearssl/info.txt
new file mode 100644
index 000000000..cf38a1fe7
--- /dev/null
+++ b/src/lib/prov/bearssl/info.txt
@@ -0,0 +1,13 @@
+<defines>
+BEARSSL -> 20170628
+</defines>
+
+load_on vendor
+
+<header:internal>
+bearssl.h
+</header:internal>
+
+<libs>
+all!windows -> bearssl
+</libs>
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index bb65fb138..72551c8c7 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -18,6 +18,10 @@
#include <botan/rfc6979.h>
#endif
+#if defined(BOTAN_HAS_BEARSSL)
+ #include <botan/internal/bearssl.h>
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
#include <botan/internal/openssl.h>
#endif
@@ -156,6 +160,21 @@ std::unique_ptr<PK_Ops::Verification>
ECDSA_PublicKey::create_verification_op(const std::string& params,
const std::string& provider) const
{
+#if defined(BOTAN_HAS_BEARSSL)
+ if(provider == "bearssl" || provider.empty())
+ {
+ try
+ {
+ return make_bearssl_ecdsa_ver_op(*this, params);
+ }
+ catch(Lookup_Error& e)
+ {
+ if(provider == "bearssl")
+ throw;
+ }
+ }
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
if(provider == "openssl" || provider.empty())
{
@@ -182,6 +201,21 @@ ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
const std::string& params,
const std::string& provider) const
{
+#if defined(BOTAN_HAS_BEARSSL)
+ if(provider == "bearssl" || provider.empty())
+ {
+ try
+ {
+ return make_bearssl_ecdsa_sig_op(*this, params);
+ }
+ catch(Lookup_Error& e)
+ {
+ if(provider == "bearssl")
+ throw;
+ }
+ }
+#endif
+
#if defined(BOTAN_HAS_OPENSSL)
if(provider == "openssl" || provider.empty())
{
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
index a38b7d3f3..d25bf8d68 100644
--- a/src/tests/test_pubkey.cpp
+++ b/src/tests/test_pubkey.cpp
@@ -82,9 +82,9 @@ void check_invalid_ciphertexts(Test::Result& result,
" invalid ciphertexts, rejected " + std::to_string(ciphertext_rejected));
}
-std::vector<std::string> PK_Test::possible_providers(const std::string&)
+std::vector<std::string> PK_Test::possible_providers(const std::string& params)
{
- return Test::provider_filter({ "base", "openssl", "tpm" });
+ return Test::provider_filter({ "base", "bearssl", "openssl", "tpm" });
}
Test::Result