diff options
author | Jack Lloyd <[email protected]> | 2016-01-04 02:42:24 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-01-04 02:42:24 -0500 |
commit | b2722fd321dcefcfc7111cc8185bb9cdc3f5e112 (patch) | |
tree | d8c184508348206591f5eb8dd1680239c6fa18b0 /src/lib/prov | |
parent | e61e64e37393be1827a9db27c95e4cc9d4af43dd (diff) |
Add ECDH via OpenSSL
Expose provider param in PK_Key_Agreement API
Handle multiple providers in key agreement tests
Fix some funky formatting of P-521 EC points in ecdh.vec which was
being rejected by OpenSSL; for whatever reason the CAVS file had
the affine coords with far more leading zeros than necessary.
Diffstat (limited to 'src/lib/prov')
-rw-r--r-- | src/lib/prov/openssl/openssl.h | 1 | ||||
-rw-r--r-- | src/lib/prov/openssl/openssl_ec.cpp (renamed from src/lib/prov/openssl/openssl_ecdsa.cpp) | 127 |
2 files changed, 113 insertions, 15 deletions
diff --git a/src/lib/prov/openssl/openssl.h b/src/lib/prov/openssl/openssl.h index 05d3e953f..ebaa2b756 100644 --- a/src/lib/prov/openssl/openssl.h +++ b/src/lib/prov/openssl/openssl.h @@ -29,6 +29,7 @@ class OpenSSL_Error : public Exception #define BOTAN_OPENSSL_RSA_PRIO 90 #define BOTAN_OPENSSL_ECDSA_PRIO 90 +#define BOTAN_OPENSSL_ECDH_PRIO 90 } diff --git a/src/lib/prov/openssl/openssl_ecdsa.cpp b/src/lib/prov/openssl/openssl_ec.cpp index 8b1af24db..74d8f744a 100644 --- a/src/lib/prov/openssl/openssl_ecdsa.cpp +++ b/src/lib/prov/openssl/openssl_ec.cpp @@ -1,29 +1,49 @@ /* -* ECDSA via OpenSSL -* (C) 2015 Jack Lloyd +* ECDSA and ECDH via OpenSSL +* (C) 2015,2016 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ +#include <iostream> #include <botan/internal/openssl.h> -#include <openssl/x509.h> -#if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA) +#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_utils.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include <botan/ecdsa.h> +#endif -#include <botan/der_enc.h> -#include <botan/ecdsa.h> -#include <botan/pkcs8.h> -#include <botan/oids.h> -#include <botan/internal/pk_utils.h> +#if defined(BOTAN_HAS_ECDH) + #include <botan/ecdh.h> +#endif -#include <openssl/ecdsa.h> -#include <openssl/ec.h> +#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 { namespace { +#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO) + secure_vector<byte> PKCS8_for_openssl(const EC_PrivateKey& ec) { const PointGFp& pub_key = ec.public_point(); @@ -49,13 +69,11 @@ int OpenSSL_EC_nid_for(const OID& oid) return -1; static const std::map<std::string, int> nid_map = { - //{ "secp160r1", NID_secp160r1 }, - //{ "secp160r2", NID_secp160r2 }, { "secp192r1", NID_X9_62_prime192v1 }, { "secp224r1", NID_secp224r1 }, { "secp256r1", NID_X9_62_prime256v1 }, { "secp384r1", NID_secp384r1 }, - { "secp521r1", NID_secp521r1 } + { "secp521r1", NID_secp521r1 }, // TODO: OpenSSL 1.0.2 added brainpool curves }; @@ -67,6 +85,10 @@ int OpenSSL_EC_nid_for(const OID& oid) return -1; } +#endif + +#if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA) + class OpenSSL_ECDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA { public: @@ -200,8 +222,83 @@ BOTAN_REGISTER_TYPE(PK_Ops::Signature, OpenSSL_ECDSA_Signing_Operation, "ECDSA", OpenSSL_ECDSA_Signing_Operation::make, "openssl", BOTAN_OPENSSL_ECDSA_PRIO); +#endif + +#if defined(BOTAN_HAS_ECDH) && !defined(OPENSSL_NO_ECDH) + +class OpenSSL_ECDH_KA_Operation : public PK_Ops::Key_Agreement_with_KDF + { + public: + typedef ECDH_PrivateKey Key_Type; + + static OpenSSL_ECDH_KA_Operation* make(const Spec& spec) + { + if(const ECDH_PrivateKey* ecdh = dynamic_cast<const ECDH_PrivateKey*>(&spec.key())) + { + const int nid = OpenSSL_EC_nid_for(ecdh->domain().get_oid()); + if(nid > 0) + return new OpenSSL_ECDH_KA_Operation(*ecdh, spec.padding()); + } + + return nullptr; + } + + 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) + { + const secure_vector<byte> der = PKCS8_for_openssl(ecdh); + const byte* der_ptr = der.data(); + m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size())); + if(!m_ossl_ec) + throw OpenSSL_Error("d2i_ECPrivateKey"); + } + + secure_vector<byte> raw_agree(const byte 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<byte> out(out_len); + EC_POINT* pub_key = ::EC_POINT_new(group); + + if(!pub_key) + throw OpenSSL_Error("EC_POINT_new"); + + const int os2ecp_rc = + ::EC_POINT_oct2point(group, pub_key, w, w_len, nullptr); + + if(os2ecp_rc != 1) + throw OpenSSL_Error("EC_POINT_oct2point"); + + const int ecdh_rc = ::ECDH_compute_key(out.data(), + out.size(), + pub_key, + m_ossl_ec.get(), + /*KDF*/nullptr); + + if(ecdh_rc <= 0) + throw OpenSSL_Error("ECDH_compute_key"); + + 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_order_bits = 0; + }; + +BOTAN_REGISTER_TYPE(PK_Ops::Key_Agreement, OpenSSL_ECDH_KA_Operation, "ECDH", + OpenSSL_ECDH_KA_Operation::make, + "openssl", BOTAN_OPENSSL_ECDH_PRIO); + +#endif + } } -#endif |