diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2018-03-02 10:54:19 -0500 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2018-03-02 10:54:19 -0500 |
commit | cbb11dfa02428333b589055229b08dc5771b5114 (patch) | |
tree | 20daa9c29a9d76051f2168e357d54a0c82fef776 | |
parent | 11b5a50f035fa74f3f529b4f094db540d6623a04 (diff) | |
download | mongo-cbb11dfa02428333b589055229b08dc5771b5114.tar.gz |
SERVER-32742 Implement SHA-1, SHA-256, and HMAC crypto support with Windows BCrypt
-rw-r--r-- | SConstruct | 4 | ||||
-rw-r--r-- | src/mongo/crypto/SConscript | 18 | ||||
-rw-r--r-- | src/mongo/crypto/sha_block_tom.cpp | 2 | ||||
-rw-r--r-- | src/mongo/crypto/sha_block_windows.cpp | 185 |
4 files changed, 190 insertions, 19 deletions
diff --git a/SConstruct b/SConstruct index 9c91e48611f..34f7f8eb863 100644 --- a/SConstruct +++ b/SConstruct @@ -2888,9 +2888,7 @@ def doConfigure(myenv): if conf.env.TargetOSIs('windows'): ssl_provider = 'windows' env.SetConfigHeaderDefine("MONGO_CONFIG_SSL_PROVIDER", "SSL_PROVIDER_WINDOWS") - - # TODO: Implement native crypto for windows, for now use tom - conf.env.Append( MONGO_CRYPTO=["tom"] ) + conf.env.Append( MONGO_CRYPTO=["windows"] ) elif conf.env.TargetOSIs('darwin', 'macOS'): conf.env.Append( MONGO_CRYPTO=["apple"] ) diff --git a/src/mongo/crypto/SConscript b/src/mongo/crypto/SConscript index 381405abd94..ee4c4ff7f03 100644 --- a/src/mongo/crypto/SConscript +++ b/src/mongo/crypto/SConscript @@ -23,7 +23,7 @@ env.Library('sha256_block', ]) if "tom" in env["MONGO_CRYPTO"]: - tomEnv = env.Clone(); + tomEnv = env.Clone() tomEnv.InjectThirdPartyIncludePaths(libraries=['tomcrypt']) tomEnv.Append( CPPDEFINES=[ @@ -46,20 +46,10 @@ if "tom" in env["MONGO_CRYPTO"]: ] ) -env.Library('sha_block_openssl', - source=[ - 'sha_block_openssl.cpp' - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/base', - 'sha1_block', - 'sha256_block', - ]) - -if env.TargetOSIs('darwin', 'macOS'): - env.Library('sha_block_apple', +else: + env.Library('sha_block_${MONGO_CRYPTO}', source=[ - 'sha_block_apple.cpp', + 'sha_block_${MONGO_CRYPTO}.cpp' ], LIBDEPS=[ '$BUILD_DIR/mongo/base', diff --git a/src/mongo/crypto/sha_block_tom.cpp b/src/mongo/crypto/sha_block_tom.cpp index 4908f5ffe20..20e11d34ce8 100644 --- a/src/mongo/crypto/sha_block_tom.cpp +++ b/src/mongo/crypto/sha_block_tom.cpp @@ -35,10 +35,8 @@ #include "mongo/util/assert_util.h" #ifdef MONGO_CONFIG_SSL -#if MONGO_CONFIG_SSL_PROVIDER != SSL_PROVIDER_WINDOWS #error This file should not be included if compiling with SSL support #endif -#endif #include "tomcrypt.h" diff --git a/src/mongo/crypto/sha_block_windows.cpp b/src/mongo/crypto/sha_block_windows.cpp new file mode 100644 index 00000000000..64f8c1f1334 --- /dev/null +++ b/src/mongo/crypto/sha_block_windows.cpp @@ -0,0 +1,185 @@ +/** + * Copyright (C) 2018 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include <initializer_list> + +#include "mongo/crypto/sha1_block.h" +#include "mongo/crypto/sha256_block.h" + +#include "mongo/config.h" +#include "mongo/util/assert_util.h" + +namespace mongo { + +namespace { + +/** + * Class to load singleton instances of each SHA algorithm. + */ +class BCryptHashLoader { +public: + BCryptHashLoader() { + loadAlgo(&_algoSHA1, BCRYPT_SHA1_ALGORITHM, false); + loadAlgo(&_algoSHA256, BCRYPT_SHA256_ALGORITHM, false); + + loadAlgo(&_algoSHA1Hmac, BCRYPT_SHA1_ALGORITHM, true); + loadAlgo(&_algoSHA256Hmac, BCRYPT_SHA256_ALGORITHM, true); + } + + ~BCryptHashLoader() { + invariant(BCryptCloseAlgorithmProvider(_algoSHA256, 0) == STATUS_SUCCESS); + invariant(BCryptCloseAlgorithmProvider(_algoSHA1, 0) == STATUS_SUCCESS); + invariant(BCryptCloseAlgorithmProvider(_algoSHA256Hmac, 0) == STATUS_SUCCESS); + invariant(BCryptCloseAlgorithmProvider(_algoSHA1Hmac, 0) == STATUS_SUCCESS); + } + + BCRYPT_ALG_HANDLE getAlgoSHA256() { + return _algoSHA256; + } + + BCRYPT_ALG_HANDLE getAlgoSHA1() { + return _algoSHA1; + } + + BCRYPT_ALG_HANDLE getAlgoSHA256Hmac() { + return _algoSHA256Hmac; + }; + + BCRYPT_ALG_HANDLE getAlgoSHA1Hmac() { + return _algoSHA1Hmac; + }; + +private: + void loadAlgo(BCRYPT_ALG_HANDLE* algo, const wchar_t* name, bool isHmac) { + invariant( + BCryptOpenAlgorithmProvider( + algo, name, MS_PRIMITIVE_PROVIDER, isHmac ? BCRYPT_ALG_HANDLE_HMAC_FLAG : 0) == + STATUS_SUCCESS); + } + +private: + BCRYPT_ALG_HANDLE _algoSHA256; + BCRYPT_ALG_HANDLE _algoSHA1; + BCRYPT_ALG_HANDLE _algoSHA256Hmac; + BCRYPT_ALG_HANDLE _algoSHA1Hmac; +}; + +static BCryptHashLoader& getBCryptHashLoader() { + static BCryptHashLoader* loader = new BCryptHashLoader(); + return *loader; +} + +/** + * Computes a SHA hash of 'input'. + */ +template <typename HashType> +HashType computeHashImpl(BCRYPT_ALG_HANDLE algo, std::initializer_list<ConstDataRange> input) { + HashType output; + + BCRYPT_HASH_HANDLE hHash; + + fassert(50725, + BCryptCreateHash(algo, &hHash, NULL, 0, NULL, 0, 0) == STATUS_SUCCESS && + + std::all_of(begin(input), + end(input), + [&](const auto& i) { + return BCryptHashData( + hHash, + reinterpret_cast<PUCHAR>(const_cast<char*>(i.data())), + i.length(), + 0) == STATUS_SUCCESS; + }) && + + BCryptFinishHash(hHash, output.data(), output.size(), 0) == STATUS_SUCCESS && + + BCryptDestroyHash(hHash) == STATUS_SUCCESS); + + return output; +} + +/** + * Computes a HMAC SHA'd keyed hash of 'input' using the key 'key', writes output into 'output'. + */ +template <typename HashType> +void computeHmacImpl(BCRYPT_ALG_HANDLE algo, + const uint8_t* key, + size_t keyLen, + const uint8_t* input, + size_t inputLen, + HashType* const output) { + invariant(key && input); + + BCRYPT_HASH_HANDLE hHash; + + fassert(50726, + BCryptCreateHash(algo, &hHash, NULL, 0, const_cast<PUCHAR>(key), keyLen, 0) == + STATUS_SUCCESS && + + BCryptHashData(hHash, const_cast<PUCHAR>(input), inputLen, 0) == STATUS_SUCCESS && + + BCryptFinishHash(hHash, output->data(), output->size(), 0) == STATUS_SUCCESS && + + BCryptDestroyHash(hHash) == STATUS_SUCCESS); +} + +} // namespace + +SHA1BlockTraits::HashType SHA1BlockTraits::computeHash( + std::initializer_list<ConstDataRange> input) { + return computeHashImpl<SHA1BlockTraits::HashType>(getBCryptHashLoader().getAlgoSHA1(), + std::move(input)); +} + +SHA256BlockTraits::HashType SHA256BlockTraits::computeHash( + std::initializer_list<ConstDataRange> input) { + return computeHashImpl<SHA256BlockTraits::HashType>(getBCryptHashLoader().getAlgoSHA256(), + std::move(input)); +} + +void SHA1BlockTraits::computeHmac(const uint8_t* key, + size_t keyLen, + const uint8_t* input, + size_t inputLen, + HashType* const output) { + return computeHmacImpl<HashType>( + getBCryptHashLoader().getAlgoSHA1Hmac(), key, keyLen, input, inputLen, output); +} + +void SHA256BlockTraits::computeHmac(const uint8_t* key, + size_t keyLen, + const uint8_t* input, + size_t inputLen, + HashType* const output) { + return computeHmacImpl<HashType>( + getBCryptHashLoader().getAlgoSHA256Hmac(), key, keyLen, input, inputLen, output); +} + +} // namespace mongo |