From c7b46e8e3c1f91ba4e49ba7ae011006775d8b080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Tue, 20 Mar 2018 20:27:09 +0000 Subject: [PATCH] bcrypt: Add support for computing/comparing cipher tag. Signed-off-by: Alistair Leslie-Hughes Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/bcrypt/bcrypt_main.c | 47 +++++++++++++++++++++++++++++++++++++- dlls/bcrypt/tests/bcrypt.c | 10 ++++---- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 573cd374a48..a08eb00269e 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -50,6 +50,9 @@ static HINSTANCE instance; #if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONCRYPTOR_H) WINE_DECLARE_DEBUG_CHANNEL(winediag); +/* Not present in gnutls version < 3.0 */ +static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t handle, void * tag, size_t tag_size); + static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); @@ -69,6 +72,11 @@ MAKE_FUNCPTR(gnutls_perror); #define GNUTLS_CIPHER_AES_256_GCM 94 #endif +static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void * tag, size_t tag_size) +{ + return GNUTLS_E_UNKNOWN_CIPHER_TYPE; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -102,6 +110,12 @@ static BOOL gnutls_initialize(void) LOAD_FUNCPTR(gnutls_perror) #undef LOAD_FUNCPTR + if (!(pgnutls_cipher_tag = wine_dlsym( libgnutls_handle, "gnutls_cipher_tag", NULL, 0 ))) + { + WARN("gnutls_cipher_tag not found\n"); + pgnutls_cipher_tag = compat_gnutls_cipher_tag; + } + if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS) { pgnutls_perror( ret ); @@ -1018,6 +1032,19 @@ static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_le return STATUS_SUCCESS; } +static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len ) +{ + int ret; + + if ((ret = pgnutls_cipher_tag( key->handle, tag, len ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} + static NTSTATUS key_destroy( struct key *key ) { if (key->handle) pgnutls_cipher_deinit( key->handle ); @@ -1123,6 +1150,12 @@ static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_le return STATUS_SUCCESS; } +static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len ) +{ + FIXME( "not implemented on Mac\n" ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS key_destroy( struct key *key ) { if (key->ref_encrypt) CCCryptorRelease( key->ref_encrypt ); @@ -1158,6 +1191,12 @@ static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_le return STATUS_NOT_IMPLEMENTED; } +static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len ) +{ + ERR( "support for keys not available at build time\n" ); + return STATUS_NOT_IMPLEMENTED; +} + static NTSTATUS key_destroy( struct key *key ) { ERR( "support for keys not available at build time\n" ); @@ -1311,7 +1350,7 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp if ((status = key_encrypt( key, input, input_len, output, output_len ))) return status; - return STATUS_SUCCESS; + return key_get_tag( key, auth_info->pbTag, auth_info->cbTag ); } if ((status = key_set_params( key, iv, iv_len ))) return status; @@ -1370,6 +1409,7 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp if (key->mode == MODE_ID_GCM) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; + UCHAR tag[16]; if (!auth_info) return STATUS_INVALID_PARAMETER; if (!auth_info->pbNonce) return STATUS_INVALID_PARAMETER; @@ -1387,6 +1427,11 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp if ((status = key_decrypt( key, input, input_len, output, output_len ))) return status; + if ((status = key_get_tag( key, tag, sizeof(tag) ))) + return status; + if (memcmp( tag, auth_info->pbTag, auth_info->cbTag )) + return STATUS_AUTH_TAG_MISMATCH; + return STATUS_SUCCESS; } diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index e3cbc87db42..1176796dbc0 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -754,11 +754,11 @@ static void test_BCryptEncrypt(void) ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ok(size == 32, "got %u\n", size); ok(!memcmp(ciphertext, expected4, sizeof(expected4)), "wrong data\n"); - todo_wine ok(!memcmp(tag, expected_tag, sizeof(expected_tag)), "wrong tag\n"); + ok(!memcmp(tag, expected_tag, sizeof(expected_tag)), "wrong tag\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected4[i], "%u: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) - todo_wine ok(tag[i] == expected_tag[i], "%u: %02x != %02x\n", i, tag[i], expected_tag[i]); + ok(tag[i] == expected_tag[i], "%u: %02x != %02x\n", i, tag[i], expected_tag[i]); /* input size is not multiple of block size */ size = 0; @@ -769,11 +769,11 @@ static void test_BCryptEncrypt(void) ok(ret == STATUS_SUCCESS, "got %08x\n", ret); ok(size == 24, "got %u\n", size); ok(!memcmp(ciphertext, expected4, 24), "wrong data\n"); - todo_wine ok(!memcmp(tag, expected_tag2, sizeof(expected_tag2)), "wrong tag\n"); + ok(!memcmp(tag, expected_tag2, sizeof(expected_tag2)), "wrong tag\n"); for (i = 0; i < 24; i++) ok(ciphertext[i] == expected4[i], "%u: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) - todo_wine ok(tag[i] == expected_tag2[i], "%u: %02x != %02x\n", i, tag[i], expected_tag2[i]); + ok(tag[i] == expected_tag2[i], "%u: %02x != %02x\n", i, tag[i], expected_tag2[i]); /* test with padding */ memcpy(ivbuf, iv, sizeof(iv)); @@ -977,7 +977,7 @@ static void test_BCryptDecrypt(void) memcpy(ivbuf, iv, sizeof(iv)); auth_info.pbTag = iv; /* wrong tag */ ret = pBCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 32, &size, 0); - todo_wine ok(ret == STATUS_AUTH_TAG_MISMATCH, "got %08x\n", ret); + ok(ret == STATUS_AUTH_TAG_MISMATCH, "got %08x\n", ret); ok(size == 32, "got %u\n", size); ret = pBCryptDestroyKey(key);