Module: wine Branch: master Commit: c7b46e8e3c1f91ba4e49ba7ae011006775d8b080 URL: https://source.winehq.org/git/wine.git/?a=commit;h=c7b46e8e3c1f91ba4e49ba7ae...
Author: Michael Müller michael@fds-team.de Date: Tue Mar 20 20:27:09 2018 +0000
bcrypt: Add support for computing/comparing cipher tag.
Signed-off-by: Alistair Leslie-Hughes leslie_alistair@hotmail.com Signed-off-by: Hans Leidekker hans@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
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 573cd37..a08eb00 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 e3cbc87..1176796 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);