diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f3e8f5..e00f7a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,5 +305,12 @@ if(WIN32) endif(WIN32) +SET(POST_BUILD_STEP_COMMANDS ${POST_BUILD_STEP_COMMANDS} + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OPENSSL_ROOT_DIR}/ssl/openssl.cnf" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/openssl.cnf") + +ADD_CUSTOM_COMMAND(TARGET fc POST_BUILD ${POST_BUILD_STEP_COMMANDS} + COMMENT "Copying OpenSSL/ssl/openssl.cnf into target directory." +) + MESSAGE(STATUS "Finished fc module configuration...") diff --git a/include/fc/crypto/bigint.hpp b/include/fc/crypto/bigint.hpp index e4fdd8b..debc869 100644 --- a/include/fc/crypto/bigint.hpp +++ b/include/fc/crypto/bigint.hpp @@ -11,7 +11,7 @@ namespace fc { public: bigint( const std::vector& bige ); bigint( const char* bige, uint32_t l ); - bigint( unsigned long i ); + bigint(uint64_t value); bigint( ); bigint( const bigint& c ); bigint( bigint&& c ); diff --git a/include/fc/crypto/openssl.hpp b/include/fc/crypto/openssl.hpp index f21ee3c..0bf0fe8 100644 --- a/include/fc/crypto/openssl.hpp +++ b/include/fc/crypto/openssl.hpp @@ -15,6 +15,7 @@ */ namespace fc { + class path; template struct ssl_wrapper @@ -55,6 +56,13 @@ namespace fc ~ssl_bignum() { BN_free(obj); } }; + /** Allows to explicitly specify OpenSSL configuration file path to be loaded at OpenSSL library init. + If not set OpenSSL will try to load the conf. file (openssl.cnf) from the path it was + configured with what caused serious Keyhotee startup bugs on some Win7 machines. + \warning to be effective this method should be used before any part using OpenSSL, especially + before init_openssl call + */ + void store_configuration_path(const path& filePath); int init_openssl(); } // namespace fc diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp index 26c464b..8e51519 100644 --- a/src/crypto/aes.cpp +++ b/src/crypto/aes.cpp @@ -10,17 +10,20 @@ namespace fc { -static int init = init_openssl(); - struct aes_encoder::impl { evp_cipher_ctx ctx; }; -aes_encoder::aes_encoder(){} +aes_encoder::aes_encoder() +{ + static int init = init_openssl(); +} + aes_encoder::~aes_encoder() { } + void aes_encoder::init( const fc::sha256& key, const fc::uint128& init_value ) { my->ctx.obj = EVP_CIPHER_CTX_new(); @@ -80,7 +83,11 @@ struct aes_decoder::impl evp_cipher_ctx ctx; }; -aes_decoder::aes_decoder(){} +aes_decoder::aes_decoder() + { + static int init = init_openssl(); + } + void aes_decoder::init( const fc::sha256& key, const fc::uint128& init_value ) { my->ctx.obj = EVP_CIPHER_CTX_new(); diff --git a/src/crypto/bigint.cpp b/src/crypto/bigint.cpp index 0682992..b76ba92 100644 --- a/src/crypto/bigint.cpp +++ b/src/crypto/bigint.cpp @@ -6,6 +6,16 @@ #include +#ifdef _MSC_VER +# include +# define bswap_64(x) _byteswap_uint64(x) +#elif defined(__APPLE__) +# include +# define bswap_64(x) OSSwapInt64(x) +#else +# include +#endif + namespace fc { bigint::bigint( const char* bige, uint32_t l ) { n = BN_bin2bn( (const unsigned char*)bige, l, NULL ); @@ -28,9 +38,10 @@ namespace fc { return BN_dup( n ); } - bigint::bigint( unsigned long i ) - :n(BN_new()) { - BN_set_word( n, i ); + bigint::bigint(uint64_t value) + { + uint64_t big_endian_value = bswap_64(value); + n = BN_bin2bn((const unsigned char*)&big_endian_value, sizeof(big_endian_value), NULL); } bigint::bigint( const bigint& c ) { @@ -47,7 +58,15 @@ namespace fc { } bool bigint::is_negative()const { return BN_is_negative(n); } - int64_t bigint::to_int64()const { return BN_get_word(n); } + + int64_t bigint::to_int64() const + { + FC_ASSERT(BN_num_bits(n) <= 63); + size_t size = BN_num_bytes(n); + uint64_t abs_value = 0; + BN_bn2bin(n, (unsigned char*)&abs_value + (sizeof(uint64_t) - size)); + return BN_is_negative(n) ? -(int64_t)bswap_64(abs_value) : bswap_64(abs_value); + } int64_t bigint::log2()const { return BN_num_bits(n); } bool bigint::operator < ( const bigint& c )const { diff --git a/src/crypto/elliptic.cpp b/src/crypto/elliptic.cpp index ac79aed..dd3c4cb 100644 --- a/src/crypto/elliptic.cpp +++ b/src/crypto/elliptic.cpp @@ -10,8 +10,6 @@ #include namespace fc { namespace ecc { - static int init = init_openssl(); - namespace detail { class public_key_impl @@ -20,7 +18,9 @@ namespace fc { namespace ecc { public_key_impl() :_key(nullptr) { + static int init = init_openssl(); } + ~public_key_impl() { if( _key != nullptr ) @@ -40,6 +40,7 @@ namespace fc { namespace ecc { private_key_impl() :_key(nullptr) { + static int init = init_openssl(); } ~private_key_impl() { diff --git a/src/crypto/openssl.cpp b/src/crypto/openssl.cpp index ae43cfb..82e453c 100644 --- a/src/crypto/openssl.cpp +++ b/src/crypto/openssl.cpp @@ -1,20 +1,37 @@ #include + +#include + +#include + +#include + namespace fc { struct openssl_scope { + static path _configurationFilePath; openssl_scope() { ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); - OPENSSL_config(NULL); + const boost::filesystem::path& boostPath = _configurationFilePath; + OPENSSL_config(boostPath.empty() ? nullptr : _configurationFilePath.to_native_ansi_path().c_str()); } + ~openssl_scope() { EVP_cleanup(); ERR_free_strings(); } }; + + path openssl_scope::_configurationFilePath; + + void store_configuration_path(const path& filePath) + { + openssl_scope::_configurationFilePath = filePath; + } int init_openssl() { diff --git a/src/crypto/rand.cpp b/src/crypto/rand.cpp index 313ba75..7235ab6 100644 --- a/src/crypto/rand.cpp +++ b/src/crypto/rand.cpp @@ -6,10 +6,10 @@ namespace fc { -static int init = init_openssl(); - void rand_bytes(char* buf, int count) { + static int init = init_openssl(); + int result = RAND_bytes((unsigned char*)buf, count); if (result != 1) FC_THROW("Error calling OpenSSL's RAND_bytes(): ${code}", ("code", (uint32_t)ERR_get_error())); @@ -17,6 +17,8 @@ void rand_bytes(char* buf, int count) void rand_pseudo_bytes(char* buf, int count) { + static int init = init_openssl(); + int result = RAND_pseudo_bytes((unsigned char*)buf, count); if (result == -1) FC_THROW("Error calling OpenSSL's RAND_pseudo_bytes(): ${code}", ("code", (uint32_t)ERR_get_error()));