Skip to content

Commit 7b2ed29

Browse files
CDRIVER-5634: SCRAM-SHA-256 FIPS compliance (#1684)
1 parent 8e48bd1 commit 7b2ed29

16 files changed

+337
-42
lines changed

Diff for: src/libbson/src/bson/bson-compat.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636

3737

3838
#ifdef BSON_OS_WIN32
39-
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
39+
#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0601)
4040
#undef _WIN32_WINNT
4141
#endif
4242
#ifndef _WIN32_WINNT
43-
#define _WIN32_WINNT 0x0600
43+
#define _WIN32_WINNT 0x0601
4444
#endif
4545
#ifndef NOMINMAX
4646
#define NOMINMAX

Diff for: src/libmongoc/CMakeLists.txt

+15
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,21 @@ else ()
532532
set (MONGOC_HAVE_SS_FAMILY 1)
533533
endif ()
534534

535+
# Check if BCryptDeriveKeyPBKDF2 is defined in bcrypt.h
536+
if (WIN32 AND MONGOC_ENABLE_CRYPTO_CNG)
537+
cmake_push_check_state()
538+
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0601)
539+
list(APPEND CMAKE_REQUIRED_LIBRARIES Bcrypt.lib)
540+
check_symbol_exists (BCryptDeriveKeyPBKDF2 "windows.h;bcrypt.h" HAVE_BCRYPT_PBKDF2)
541+
cmake_pop_check_state()
542+
endif ()
543+
544+
if (HAVE_BCRYPT_PBKDF2)
545+
set (MONGOC_HAVE_BCRYPT_PBKDF2 1)
546+
else ()
547+
set (MONGOC_HAVE_BCRYPT_PBKDF2 0)
548+
endif ()
549+
535550

536551
set (SOURCES ${SOURCES}
537552
${PROJECT_SOURCE_DIR}/src/mongoc/mcd-azure.c

Diff for: src/libmongoc/examples/parse_handshake_cfg.py

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"MONGOC_MD_FLAG_ENABLE_CLIENT_SIDE_ENCRYPTION": 32,
4141
"MONGOC_MD_FLAG_ENABLE_MONGODB_AWS_AUTH": 33,
4242
"MONGOC_MD_FLAG_ENABLE_SRV": 34,
43+
"MONGOC_MD_FLAG_HAVE_BCRYPT_PBKDF2": 35,
4344
}
4445

4546
def main():

Diff for: src/libmongoc/src/mongoc/mongoc-config.h.in

+9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@
6464
# undef MONGOC_ENABLE_CRYPTO_CNG
6565
#endif
6666

67+
/*
68+
* MONGOC_HAVE_BCRYPT_PBKDF2 is set from configure to determine if
69+
* our Bcrypt Windows library supports PBKDF2
70+
*/
71+
#define MONGOC_HAVE_BCRYPT_PBKDF2 @MONGOC_HAVE_BCRYPT_PBKDF2@
72+
73+
#if MONGOC_HAVE_BCRYPT_PBKDF2 != 1
74+
# undef MONGOC_HAVE_BCRYPT_PBKDF2
75+
#endif
6776

6877
/*
6978
* MONGOC_ENABLE_SSL_SECURE_TRANSPORT is set from configure to determine if we are

Diff for: src/libmongoc/src/mongoc/mongoc-crypto-cng-private.h

+21
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ mongoc_crypto_cng_init (void);
3333
void
3434
mongoc_crypto_cng_cleanup (void);
3535

36+
bool
37+
mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
38+
const char *password,
39+
size_t password_len,
40+
const uint8_t *salt,
41+
size_t salt_len,
42+
uint32_t iterations,
43+
size_t output_len,
44+
unsigned char *output);
45+
46+
3647
void
3748
mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto,
3849
const void *key,
@@ -47,6 +58,16 @@ mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto,
4758
const size_t input_len,
4859
unsigned char *hash_out);
4960

61+
bool
62+
mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
63+
const char *password,
64+
size_t password_len,
65+
const uint8_t *salt,
66+
size_t salt_len,
67+
uint32_t iterations,
68+
size_t output_len,
69+
unsigned char *output);
70+
5071
void
5172
mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto,
5273
const void *key,

Diff for: src/libmongoc/src/mongoc/mongoc-crypto-cng.c

+129-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "mongoc-config.h"
1717

1818
#ifdef MONGOC_ENABLE_CRYPTO_CNG
19+
#include "mongoc-scram-private.h"
1920
#include "mongoc-crypto-private.h"
2021
#include "mongoc-crypto-cng-private.h"
2122
#include "mongoc-log.h"
@@ -24,6 +25,7 @@
2425
#include <windows.h>
2526
#include <stdio.h>
2627
#include <bcrypt.h>
28+
#include <string.h>
2729

2830
#define NT_SUCCESS(Status) (((NTSTATUS) (Status)) >= 0)
2931
#define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
@@ -75,8 +77,8 @@ mongoc_crypto_cng_cleanup (void)
7577
if (_sha256_hash_algo) {
7678
BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0);
7779
}
78-
if (_sha256_hash_algo) {
79-
BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0);
80+
if (_sha256_hmac_algo) {
81+
BCryptCloseAlgorithmProvider (&_sha256_hmac_algo, 0);
8082
}
8183
}
8284

@@ -141,6 +143,112 @@ _mongoc_crypto_cng_hmac_or_hash (
141143
return retval;
142144
}
143145

146+
static int
147+
_crypto_hash_size (mongoc_crypto_t *crypto)
148+
{
149+
if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) {
150+
return MONGOC_SCRAM_SHA_1_HASH_SIZE;
151+
} else if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) {
152+
return MONGOC_SCRAM_SHA_256_HASH_SIZE;
153+
} else {
154+
BSON_UNREACHABLE ("Unexpected crypto algorithm");
155+
}
156+
}
157+
158+
#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
159+
/* Wrapper for BCryptDeriveKeyPBKDF2 */
160+
static bool
161+
_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE prf,
162+
const char *password,
163+
size_t password_len,
164+
const uint8_t *salt,
165+
size_t salt_len,
166+
uint32_t iterations,
167+
size_t output_len,
168+
unsigned char *output)
169+
{
170+
// Make non-const versions of password and salt.
171+
char *password_copy = bson_strndup (password, password_len);
172+
char *salt_copy = bson_strndup (salt, salt_len);
173+
174+
NTSTATUS status = BCryptDeriveKeyPBKDF2 (prf,
175+
(unsigned char *) password_copy,
176+
password_len,
177+
(unsigned char *) salt_copy,
178+
salt_len,
179+
iterations,
180+
output,
181+
output_len,
182+
0);
183+
bson_free (password_copy);
184+
bson_free (salt_copy);
185+
186+
if (!NT_SUCCESS (status)) {
187+
MONGOC_ERROR ("_bcrypt_derive_key_pbkdf2(): %ld", status);
188+
return false;
189+
}
190+
return true;
191+
}
192+
193+
#else
194+
/* Manually salts password if BCryptDeriveKeyPBKDF2 is unavailable */
195+
static bool
196+
_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE algorithm,
197+
const char *password,
198+
size_t password_len,
199+
const uint8_t *salt,
200+
size_t salt_len,
201+
uint32_t iterations,
202+
size_t hash_size,
203+
unsigned char *output)
204+
{
205+
uint8_t intermediate_digest[MONGOC_SCRAM_HASH_MAX_SIZE];
206+
uint8_t start_key[MONGOC_SCRAM_HASH_MAX_SIZE];
207+
208+
memcpy (start_key, salt, salt_len);
209+
start_key[salt_len] = 0;
210+
start_key[salt_len + 1] = 0;
211+
start_key[salt_len + 2] = 0;
212+
start_key[salt_len + 3] = 1;
213+
214+
if (!_mongoc_crypto_cng_hmac_or_hash (algorithm, password, password_len, start_key, hash_size, output)) {
215+
return false;
216+
}
217+
memcpy (intermediate_digest, output, hash_size);
218+
219+
for (uint32_t i = 2u; i <= iterations; i++) {
220+
if (!_mongoc_crypto_cng_hmac_or_hash (
221+
algorithm, password, password_len, intermediate_digest, hash_size, output)) {
222+
return false;
223+
}
224+
225+
for (int k = 0; k < hash_size; k++) {
226+
output[k] ^= intermediate_digest[k];
227+
}
228+
}
229+
return true;
230+
}
231+
#endif
232+
233+
bool
234+
mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
235+
const char *password,
236+
size_t password_len,
237+
const uint8_t *salt,
238+
size_t salt_len,
239+
uint32_t iterations,
240+
size_t output_len,
241+
unsigned char *output)
242+
{
243+
#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
244+
return _bcrypt_derive_key_pbkdf2 (
245+
_sha1_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output);
246+
#else
247+
return _bcrypt_derive_key_pbkdf2 (
248+
_sha1_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output);
249+
#endif
250+
}
251+
144252
void
145253
mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto,
146254
const void *key,
@@ -172,6 +280,25 @@ mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto,
172280
return res;
173281
}
174282

283+
bool
284+
mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
285+
const char *password,
286+
size_t password_len,
287+
const uint8_t *salt,
288+
size_t salt_len,
289+
uint32_t iterations,
290+
size_t output_len,
291+
unsigned char *output)
292+
{
293+
#if defined(MONGOC_HAVE_BCRYPT_PBKDF2)
294+
return _bcrypt_derive_key_pbkdf2 (
295+
_sha256_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output);
296+
#else
297+
return _bcrypt_derive_key_pbkdf2 (
298+
_sha256_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output);
299+
#endif
300+
}
301+
175302
void
176303
mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto,
177304
const void *key,

Diff for: src/libmongoc/src/mongoc/mongoc-crypto-common-crypto-private.h

+20
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727

2828
BSON_BEGIN_DECLS
2929

30+
bool
31+
mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
32+
const char *password,
33+
size_t password_len,
34+
const uint8_t *salt,
35+
size_t salt_len,
36+
uint32_t iterations,
37+
size_t output_len,
38+
unsigned char *output);
39+
3040
void
3141
mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto,
3242
const void *key,
@@ -41,6 +51,16 @@ mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto,
4151
const size_t input_len,
4252
unsigned char *hash_out);
4353

54+
bool
55+
mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
56+
const char *password,
57+
size_t password_len,
58+
const uint8_t *salt,
59+
size_t salt_len,
60+
uint32_t iterations,
61+
size_t output_len,
62+
unsigned char *output);
63+
4464
void
4565
mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto,
4666
const void *key,

Diff for: src/libmongoc/src/mongoc/mongoc-crypto-common-crypto.c

+31-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,23 @@
2020
#include "mongoc-crypto-common-crypto-private.h"
2121
#include <CommonCrypto/CommonHMAC.h>
2222
#include <CommonCrypto/CommonDigest.h>
23+
#include <CommonCrypto/CommonKeyDerivation.h>
24+
#include <CommonCrypto/CommonCryptoError.h>
2325

26+
bool
27+
mongoc_crypto_common_crypto_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
28+
const char *password,
29+
size_t password_len,
30+
const uint8_t *salt,
31+
size_t salt_len,
32+
uint32_t iterations,
33+
size_t output_len,
34+
unsigned char *output)
35+
{
36+
return kCCSuccess ==
37+
CCKeyDerivationPBKDF (
38+
kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA1, iterations, output, output_len);
39+
}
2440

2541
void
2642
mongoc_crypto_common_crypto_hmac_sha1 (mongoc_crypto_t *crypto,
@@ -46,6 +62,21 @@ mongoc_crypto_common_crypto_sha1 (mongoc_crypto_t *crypto,
4662
return false;
4763
}
4864

65+
bool
66+
mongoc_crypto_common_crypto_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
67+
const char *password,
68+
size_t password_len,
69+
const uint8_t *salt,
70+
size_t salt_len,
71+
uint32_t iterations,
72+
size_t output_len,
73+
unsigned char *output)
74+
{
75+
return kCCSuccess ==
76+
CCKeyDerivationPBKDF (
77+
kCCPBKDF2, password, password_len, salt, salt_len, kCCPRFHmacAlgSHA256, iterations, output, output_len);
78+
}
79+
4980
void
5081
mongoc_crypto_common_crypto_hmac_sha256 (mongoc_crypto_t *crypto,
5182
const void *key,
@@ -68,5 +99,4 @@ mongoc_crypto_common_crypto_sha256 (mongoc_crypto_t *crypto,
6899
}
69100
return false;
70101
}
71-
72102
#endif

Diff for: src/libmongoc/src/mongoc/mongoc-crypto-openssl-private.h

+20
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@
2828

2929
BSON_BEGIN_DECLS
3030

31+
bool
32+
mongoc_crypto_openssl_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto,
33+
const char *password,
34+
size_t password_len,
35+
const uint8_t *salt,
36+
size_t salt_len,
37+
uint32_t iterations,
38+
size_t output_len,
39+
unsigned char *output);
40+
3141
void
3242
mongoc_crypto_openssl_hmac_sha1 (mongoc_crypto_t *crypto,
3343
const void *key,
@@ -42,6 +52,16 @@ mongoc_crypto_openssl_sha1 (mongoc_crypto_t *crypto,
4252
const size_t input_len,
4353
unsigned char *hash_out);
4454

55+
bool
56+
mongoc_crypto_openssl_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto,
57+
const char *password,
58+
size_t password_len,
59+
const uint8_t *salt,
60+
size_t salt_len,
61+
uint32_t iterations,
62+
size_t output_len,
63+
unsigned char *output);
64+
4565
void
4666
mongoc_crypto_openssl_hmac_sha256 (mongoc_crypto_t *crypto,
4767
const void *key,

0 commit comments

Comments
 (0)