Skip to content

CDRIVER-5634: SCRAM-SHA-256 FIPS Compliance #1684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f1e3b7f
Initial try using library pbkdf2 functions
Julia-Garland Jul 26, 2024
411d487
Simplier + backwards compatible SHA for OpenSSL
Julia-Garland Jul 26, 2024
58af888
Copy pass and salt for cng_pbkdf
Julia-Garland Jul 26, 2024
d0f67b2
crypto-cng typing fix
Julia-Garland Jul 26, 2024
dd51195
Nicer formatting
Julia-Garland Jul 26, 2024
517735b
Bump _WIN32_WINNT to Windows 7
Julia-Garland Aug 2, 2024
897431b
Make _scram_hash_size part of private scram api
Julia-Garland Aug 2, 2024
6e41018
Revert prev commit + use original implementation if not def
Julia-Garland Aug 2, 2024
62008e1
Refactor duplicate code
Julia-Garland Aug 5, 2024
951f1e4
Update mongoc-config.h.in
Julia-Garland Aug 5, 2024
4770171
Move bcrypt check above config generation
Julia-Garland Aug 5, 2024
11925c0
Remove accidental whitespace
Julia-Garland Aug 7, 2024
3c067d0
Change free to bson_free
Julia-Garland Aug 7, 2024
e068125
Use bson_strndup
Julia-Garland Aug 7, 2024
5ba32c2
Use size_t for array length
Julia-Garland Aug 7, 2024
aa0e89a
Rename key_len to output_len
Julia-Garland Aug 7, 2024
a85e0de
Formatting
Julia-Garland Aug 7, 2024
df8bbac
Fixed output_len deletion in wrong call
Julia-Garland Aug 7, 2024
b8a7ea5
Change return types to bool
Julia-Garland Aug 8, 2024
ee7e095
Update bcrypt check in cmake
Julia-Garland Aug 8, 2024
221eb3e
Fail _hash_size on unexpected algos
Julia-Garland Aug 8, 2024
f0c5ba0
Format
Julia-Garland Aug 8, 2024
eca2835
Dually define _bcrypt_derive_key_pbkdf2
Julia-Garland Aug 8, 2024
1ca9507
Proper calls to diff versions of _bcrypt_derive_key_pbkdf2
Julia-Garland Aug 8, 2024
5d558c2
Comments for _bcrypt_derive_key_pbkdf2
Julia-Garland Aug 8, 2024
a068ae9
Formatting
Julia-Garland Aug 8, 2024
58b1bdf
Pass hash size to pbkdf2
Julia-Garland Aug 8, 2024
fe0d0f1
Pass hash_size to manual bcrupt pbkdf
Julia-Garland Aug 8, 2024
a81440e
Use CommonCrypto error codes
Julia-Garland Aug 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libbson/src/bson/bson-compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@


#ifdef BSON_OS_WIN32
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0601)
#undef _WIN32_WINNT
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#define _WIN32_WINNT 0x0601
#endif
#ifndef NOMINMAX
#define NOMINMAX
Expand Down
15 changes: 15 additions & 0 deletions src/libmongoc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,21 @@ else ()
set (MONGOC_HAVE_SS_FAMILY 1)
endif ()

# Check if BCryptDeriveKeyPBKDF2 is defined in bcrypt.h
if (WIN32 AND MONGOC_ENABLE_CRYPTO_CNG)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0601)
list(APPEND CMAKE_REQUIRED_LIBRARIES Bcrypt.lib)
check_symbol_exists (BCryptDeriveKeyPBKDF2 "windows.h;bcrypt.h" HAVE_BCRYPT_PBKDF2)
cmake_pop_check_state()
endif ()

if (HAVE_BCRYPT_PBKDF2)
set (MONGOC_HAVE_BCRYPT_PBKDF2 1)
else ()
set (MONGOC_HAVE_BCRYPT_PBKDF2 0)
endif ()


set (SOURCES ${SOURCES}
${PROJECT_SOURCE_DIR}/src/mongoc/mcd-azure.c
Expand Down
1 change: 1 addition & 0 deletions src/libmongoc/examples/parse_handshake_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"MONGOC_MD_FLAG_ENABLE_CLIENT_SIDE_ENCRYPTION": 32,
"MONGOC_MD_FLAG_ENABLE_MONGODB_AWS_AUTH": 33,
"MONGOC_MD_FLAG_ENABLE_SRV": 34,
"MONGOC_MD_FLAG_HAVE_BCRYPT_PBKDF2": 35,
}

def main():
Expand Down
9 changes: 9 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@
# undef MONGOC_ENABLE_CRYPTO_CNG
#endif

/*
* MONGOC_HAVE_BCRYPT_PBKDF2 is set from configure to determine if
* our Bcrypt Windows library supports PBKDF2
*/
#define MONGOC_HAVE_BCRYPT_PBKDF2 @MONGOC_HAVE_BCRYPT_PBKDF2@

#if MONGOC_HAVE_BCRYPT_PBKDF2 != 1
# undef MONGOC_HAVE_BCRYPT_PBKDF2
#endif

/*
* MONGOC_ENABLE_SSL_SECURE_TRANSPORT is set from configure to determine if we are
Expand Down
21 changes: 21 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-crypto-cng-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ mongoc_crypto_cng_init (void);
void
mongoc_crypto_cng_cleanup (void);

bool
mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);


void
mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto,
const void *key,
Expand All @@ -47,6 +58,16 @@ mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto,
const size_t input_len,
unsigned char *hash_out);

bool
mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);

void
mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto,
const void *key,
Expand Down
131 changes: 129 additions & 2 deletions src/libmongoc/src/mongoc/mongoc-crypto-cng.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "mongoc-config.h"

#ifdef MONGOC_ENABLE_CRYPTO_CNG
#include "mongoc-scram-private.h"
#include "mongoc-crypto-private.h"
#include "mongoc-crypto-cng-private.h"
#include "mongoc-log.h"
Expand All @@ -24,6 +25,7 @@
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#include <string.h>

#define NT_SUCCESS(Status) (((NTSTATUS) (Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
Expand Down Expand Up @@ -75,8 +77,8 @@ mongoc_crypto_cng_cleanup (void)
if (_sha256_hash_algo) {
BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0);
}
if (_sha256_hash_algo) {
BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0);
if (_sha256_hmac_algo) {
BCryptCloseAlgorithmProvider (&_sha256_hmac_algo, 0);
}
}

Expand Down Expand Up @@ -141,6 +143,112 @@ _mongoc_crypto_cng_hmac_or_hash (
return retval;
}

static int
_crypto_hash_size (mongoc_crypto_t *crypto)
{
if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) {
return MONGOC_SCRAM_SHA_1_HASH_SIZE;
} else if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) {
return MONGOC_SCRAM_SHA_256_HASH_SIZE;
} else {
BSON_UNREACHABLE ("Unexpected crypto algorithm");
}
}

#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
/* Wrapper for BCryptDeriveKeyPBKDF2 */
static bool
_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE prf,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output)
{
// Make non-const versions of password and salt.
char *password_copy = bson_strndup (password, password_len);
char *salt_copy = bson_strndup (salt, salt_len);

NTSTATUS status = BCryptDeriveKeyPBKDF2 (prf,
(unsigned char *) password_copy,
password_len,
(unsigned char *) salt_copy,
salt_len,
iterations,
output,
output_len,
0);
bson_free (password_copy);
bson_free (salt_copy);

if (!NT_SUCCESS (status)) {
MONGOC_ERROR ("_bcrypt_derive_key_pbkdf2(): %ld", status);
return false;
}
return true;
}

#else
/* Manually salts password if BCryptDeriveKeyPBKDF2 is unavailable */
static bool
_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE algorithm,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t hash_size,
unsigned char *output)
{
uint8_t intermediate_digest[MONGOC_SCRAM_HASH_MAX_SIZE];
uint8_t start_key[MONGOC_SCRAM_HASH_MAX_SIZE];

memcpy (start_key, salt, salt_len);
start_key[salt_len] = 0;
start_key[salt_len + 1] = 0;
start_key[salt_len + 2] = 0;
start_key[salt_len + 3] = 1;

if (!_mongoc_crypto_cng_hmac_or_hash (algorithm, password, password_len, start_key, hash_size, output)) {
return false;
}
memcpy (intermediate_digest, output, hash_size);

for (uint32_t i = 2u; i <= iterations; i++) {
if (!_mongoc_crypto_cng_hmac_or_hash (
algorithm, password, password_len, intermediate_digest, hash_size, output)) {
return false;
}

for (int k = 0; k < hash_size; k++) {
output[k] ^= intermediate_digest[k];
}
}
return true;
}
#endif

bool
mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output)
{
#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
return _bcrypt_derive_key_pbkdf2 (
_sha1_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output);
#else
return _bcrypt_derive_key_pbkdf2 (
_sha1_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output);
#endif
}

void
mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto,
const void *key,
Expand Down Expand Up @@ -172,6 +280,25 @@ mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto,
return res;
}

bool
mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output)
{
#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
return _bcrypt_derive_key_pbkdf2 (
_sha256_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output);
#else
return _bcrypt_derive_key_pbkdf2 (
_sha256_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output);
#endif
}

void
mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto,
const void *key,
Expand Down
20 changes: 20 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-crypto-common-crypto-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@

BSON_BEGIN_DECLS

bool
mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);

void
mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto,
const void *key,
Expand All @@ -41,6 +51,16 @@ mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto,
const size_t input_len,
unsigned char *hash_out);

bool
mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);

void
mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto,
const void *key,
Expand Down
32 changes: 31 additions & 1 deletion src/libmongoc/src/mongoc/mongoc-crypto-common-crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,23 @@
#include "mongoc-crypto-common-crypto-private.h"
#include <CommonCrypto/CommonHMAC.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonKeyDerivation.h>
#include <CommonCrypto/CommonCryptoError.h>

bool
mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output)
{
return kCCSuccess ==
CCKeyDerivationPBKDF (
kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA1, iterations, output, output_len);
}

void
mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto,
Expand All @@ -46,6 +62,21 @@ mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto,
return false;
}

bool
mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output)
{
return kCCSuccess ==
CCKeyDerivationPBKDF (
kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA256, iterations, output, output_len);
}

void
mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto,
const void *key,
Expand All @@ -68,5 +99,4 @@ mongoc_crypto_common_crypto_sha256 (mongoc_crypto_t *crypto,
}
return false;
}

#endif
20 changes: 20 additions & 0 deletions src/libmongoc/src/mongoc/mongoc-crypto-openssl-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@

BSON_BEGIN_DECLS

bool
mongoc_crypto_openssl_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);

void
mongoc_crypto_openssl_hmac_sha1 (mongoc_crypto_t *crypto,
const void *key,
Expand All @@ -42,6 +52,16 @@ mongoc_crypto_openssl_sha1 (mongoc_crypto_t *crypto,
const size_t input_len,
unsigned char *hash_out);

bool
mongoc_crypto_openssl_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
const char *password,
size_t password_len,
const uint8_t *salt,
size_t salt_len,
uint32_t iterations,
size_t output_len,
unsigned char *output);

void
mongoc_crypto_openssl_hmac_sha256 (mongoc_crypto_t *crypto,
const void *key,
Expand Down
Loading