summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Benvenuto <mark.benvenuto@mongodb.com>2018-03-02 10:54:19 -0500
committerMark Benvenuto <mark.benvenuto@mongodb.com>2018-03-02 10:54:19 -0500
commitcbb11dfa02428333b589055229b08dc5771b5114 (patch)
tree20daa9c29a9d76051f2168e357d54a0c82fef776
parent11b5a50f035fa74f3f529b4f094db540d6623a04 (diff)
downloadmongo-cbb11dfa02428333b589055229b08dc5771b5114.tar.gz
SERVER-32742 Implement SHA-1, SHA-256, and HMAC crypto support with Windows BCrypt
-rw-r--r--SConstruct4
-rw-r--r--src/mongo/crypto/SConscript18
-rw-r--r--src/mongo/crypto/sha_block_tom.cpp2
-rw-r--r--src/mongo/crypto/sha_block_windows.cpp185
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