Skip to content

Commit 92b5144

Browse files
authored
MONGOCRYPT-909 reject large KMIP response length (#1187)
1 parent 48ef436 commit 92b5144

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

kms-message/src/kms_kmip_response_parser.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ kms_kmip_response_parser_feed (kms_kmip_response_parser_t *parser,
111111
uint32_t temp;
112112
memcpy (&temp, parser->buf->str + FIRST_LENGTH_OFFSET, sizeof (uint32_t));
113113
parser->first_len = KMS_UINT32_FROM_BE (temp);
114+
if (parser->first_len > KMS_PARSER_MAX_RESPONSE_LEN) {
115+
KMS_ERROR (parser, "KMS KMIP response too large");
116+
return false;
117+
}
114118
}
115119
return true;
116120
}

test/test-mongocrypt-kms-ctx.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "mongocrypt-key-private.h"
2121
#include "mongocrypt-kms-ctx-private.h"
2222
#include "mongocrypt-private.h"
23+
#include "test-mongocrypt-assert.h"
2324
#include "test-mongocrypt-util.h"
2425
#include "test-mongocrypt.h"
2526

@@ -885,6 +886,100 @@ static void _test_mongocrypt_kms_ctx_feed_empty_bytes(_mongocrypt_tester_t *test
885886
mongocrypt_status_destroy(status);
886887
}
887888

889+
// _test_mongocrypt_kms_ctx_kmip_response_bad_length tests KMIP responses that report bad lengths.
890+
static void _test_mongocrypt_kms_ctx_kmip_response_bad_length(_mongocrypt_tester_t *tester) {
891+
mongocrypt_t *crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
892+
bool ok;
893+
uint8_t secretdata[KMS_KMIP_REQUEST_SECRETDATA_LENGTH] = {0};
894+
mongocrypt_status_t *status = mongocrypt_status_new();
895+
_mongocrypt_endpoint_t *endpoint = _mongocrypt_endpoint_new("example.com", -1, NULL /* opts */, status);
896+
ASSERT_OK_STATUS(endpoint != NULL, status);
897+
898+
// Regression test for MONGOCRYPT-909: test UINT32_MAX
899+
{
900+
mongocrypt_kms_ctx_t kms_ctx = {0};
901+
static const char *kmip_header = "\x42\x00\x7b\x01" // Tag=ResponseMessage, Type=Structure
902+
"\xff\xff\xff\xff"; // Length = UINT32_MAX
903+
904+
ok = _mongocrypt_kms_ctx_init_kmip_register(&kms_ctx,
905+
endpoint,
906+
secretdata,
907+
KMS_KMIP_REQUEST_SECRETDATA_LENGTH,
908+
"kmip",
909+
&crypt->log);
910+
ASSERT_OK_STATUS(ok, kms_ctx.status);
911+
912+
// Parser requests 8 bytes for initial header:
913+
ASSERT_CMPINT(mongocrypt_kms_ctx_bytes_needed(&kms_ctx), ==, 8u);
914+
915+
mongocrypt_binary_t *bytes = mongocrypt_binary_new_from_data((uint8_t *)kmip_header, 8u);
916+
917+
// Expect error (not abort):
918+
ASSERT_FAILS(mongocrypt_kms_ctx_feed(&kms_ctx, bytes), &kms_ctx, "KMS KMIP response too large");
919+
920+
mongocrypt_binary_destroy(bytes);
921+
_mongocrypt_kms_ctx_cleanup(&kms_ctx);
922+
}
923+
924+
// Length reported is less than data fed.
925+
{
926+
mongocrypt_kms_ctx_t kms_ctx = {0};
927+
static const char *kmip_header = "\x42\x00\x7b\x01" // Tag=ResponseMessage, Type=Structure
928+
"\x00\x00\x00\x01"; // Length = 1
929+
ASSERT_OK_STATUS(endpoint != NULL, status);
930+
931+
ok = _mongocrypt_kms_ctx_init_kmip_register(&kms_ctx,
932+
endpoint,
933+
secretdata,
934+
KMS_KMIP_REQUEST_SECRETDATA_LENGTH,
935+
"kmip",
936+
&crypt->log);
937+
ASSERT_OK_STATUS(ok, kms_ctx.status);
938+
939+
// Parser requests 8 bytes for initial header:
940+
ASSERT_CMPINT(mongocrypt_kms_ctx_bytes_needed(&kms_ctx), ==, 8u);
941+
942+
mongocrypt_binary_t *bytes = mongocrypt_binary_new_from_data((uint8_t *)kmip_header, 8u);
943+
ASSERT_OK(mongocrypt_kms_ctx_feed(&kms_ctx, bytes), &kms_ctx);
944+
945+
ASSERT_CMPINT(mongocrypt_kms_ctx_bytes_needed(&kms_ctx), ==, 1u);
946+
// Attempting to feed more data errors.
947+
ASSERT_FAILS(mongocrypt_kms_ctx_feed(&kms_ctx, bytes), &kms_ctx, "KMS response fed too much data");
948+
949+
mongocrypt_binary_destroy(bytes);
950+
_mongocrypt_kms_ctx_cleanup(&kms_ctx);
951+
}
952+
953+
// Length reported is zero.
954+
{
955+
mongocrypt_kms_ctx_t kms_ctx = {0};
956+
static const char *kmip_header = "\x42\x00\x7b\x01" // Tag=ResponseMessage, Type=Structure
957+
"\x00\x00\x00\x00"; // Length = 0
958+
ASSERT_OK_STATUS(endpoint != NULL, status);
959+
960+
ok = _mongocrypt_kms_ctx_init_kmip_register(&kms_ctx,
961+
endpoint,
962+
secretdata,
963+
KMS_KMIP_REQUEST_SECRETDATA_LENGTH,
964+
"kmip",
965+
&crypt->log);
966+
ASSERT_OK_STATUS(ok, kms_ctx.status);
967+
968+
// Parser requests 8 bytes for initial header:
969+
ASSERT_CMPINT(mongocrypt_kms_ctx_bytes_needed(&kms_ctx), ==, 8u);
970+
971+
mongocrypt_binary_t *bytes = mongocrypt_binary_new_from_data((uint8_t *)kmip_header, 8u);
972+
ASSERT_FAILS(mongocrypt_kms_ctx_feed(&kms_ctx, bytes), &kms_ctx, "Error getting UniqueIdentifer");
973+
974+
mongocrypt_binary_destroy(bytes);
975+
_mongocrypt_kms_ctx_cleanup(&kms_ctx);
976+
}
977+
978+
_mongocrypt_endpoint_destroy(endpoint);
979+
mongocrypt_status_destroy(status);
980+
mongocrypt_destroy(crypt);
981+
}
982+
888983
void _mongocrypt_tester_install_kms_ctx(_mongocrypt_tester_t *tester) {
889984
INSTALL_TEST(_test_mongocrypt_kms_ctx_kmip_register);
890985
INSTALL_TEST(_test_mongocrypt_kms_ctx_kmip_activate);
@@ -895,4 +990,5 @@ void _mongocrypt_tester_install_kms_ctx(_mongocrypt_tester_t *tester) {
895990
INSTALL_TEST(_test_mongocrypt_kms_ctx_get_kms_provider);
896991
INSTALL_TEST(_test_mongocrypt_kms_ctx_default_port);
897992
INSTALL_TEST(_test_mongocrypt_kms_ctx_feed_empty_bytes);
993+
INSTALL_TEST(_test_mongocrypt_kms_ctx_kmip_response_bad_length);
898994
}

0 commit comments

Comments
 (0)