mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
Added patch to implement support for validating ECDSA certificate chains.
This commit is contained in:
parent
76cd811f73
commit
edf6f27f25
@ -0,0 +1,683 @@
|
||||
From f0a766813a241fad6771c83634855fc97a14ff2e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 18:31:55 +0200
|
||||
Subject: bcrypt: Preparation for asymmetric keys.
|
||||
|
||||
---
|
||||
dlls/bcrypt/bcrypt_main.c | 312 ++++++++++++++++++++++++++++++----------------
|
||||
1 file changed, 204 insertions(+), 108 deletions(-)
|
||||
|
||||
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
|
||||
index a7e5bff2b8c..4e1992292cd 100644
|
||||
--- a/dlls/bcrypt/bcrypt_main.c
|
||||
+++ b/dlls/bcrypt/bcrypt_main.c
|
||||
@@ -199,14 +199,15 @@ static const struct {
|
||||
ULONG hash_length;
|
||||
ULONG block_bits;
|
||||
const WCHAR *alg_name;
|
||||
+ BOOL symmetric;
|
||||
} alg_props[] = {
|
||||
- /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM },
|
||||
- /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM },
|
||||
- /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM },
|
||||
- /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM },
|
||||
- /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM },
|
||||
- /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM },
|
||||
- /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM }
|
||||
+ /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM, TRUE },
|
||||
+ /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE },
|
||||
};
|
||||
|
||||
struct algorithm
|
||||
@@ -815,10 +816,8 @@ NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG se
|
||||
}
|
||||
|
||||
#if defined(HAVE_GNUTLS_CIPHER_INIT) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
|
||||
-struct key
|
||||
+struct key_symmetric
|
||||
{
|
||||
- struct object hdr;
|
||||
- enum alg_id alg_id;
|
||||
enum mode_id mode;
|
||||
ULONG block_size;
|
||||
gnutls_cipher_hd_t handle;
|
||||
@@ -826,6 +825,16 @@ struct key
|
||||
ULONG secret_len;
|
||||
};
|
||||
|
||||
+struct key
|
||||
+{
|
||||
+ struct object hdr;
|
||||
+ enum alg_id alg_id;
|
||||
+ union
|
||||
+ {
|
||||
+ struct key_symmetric s;
|
||||
+ } u;
|
||||
+};
|
||||
+
|
||||
static ULONG get_block_size( struct algorithm *alg )
|
||||
{
|
||||
ULONG ret = 0, size = sizeof(ret);
|
||||
@@ -833,7 +842,7 @@ static ULONG get_block_size( struct algorithm *alg )
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
|
||||
+static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, const UCHAR *secret, ULONG secret_len )
|
||||
{
|
||||
UCHAR *buffer;
|
||||
|
||||
@@ -849,34 +858,64 @@ static NTSTATUS key_init( struct key *key, struct algorithm *alg, const UCHAR *s
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
- if (!(key->block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
|
||||
+ if (!(key->u.s.block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
|
||||
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, secret_len ))) return STATUS_NO_MEMORY;
|
||||
memcpy( buffer, secret, secret_len );
|
||||
|
||||
- key->alg_id = alg->id;
|
||||
- key->mode = alg->mode;
|
||||
- key->handle = 0; /* initialized on first use */
|
||||
- key->secret = buffer;
|
||||
- key->secret_len = secret_len;
|
||||
+ key->alg_id = alg->id;
|
||||
+ key->u.s.mode = alg->mode;
|
||||
+ key->u.s.handle = 0; /* initialized on first use */
|
||||
+ key->u.s.secret = buffer;
|
||||
+ key->u.s.secret_len = secret_len;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+static inline BOOL key_is_symmetric( struct key *key )
|
||||
+{
|
||||
+ return alg_props[key->alg_id].symmetric;
|
||||
+}
|
||||
+
|
||||
+static inline BOOL key_is_asymmetric( struct key *key )
|
||||
+{
|
||||
+ return !alg_props[key->alg_id].symmetric;
|
||||
+}
|
||||
+
|
||||
static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
|
||||
{
|
||||
UCHAR *buffer;
|
||||
|
||||
- if (!(buffer = HeapAlloc( GetProcessHeap(), 0, key_orig->secret_len ))) return STATUS_NO_MEMORY;
|
||||
- memcpy( buffer, key_orig->secret, key_orig->secret_len );
|
||||
-
|
||||
key_copy->hdr = key_orig->hdr;
|
||||
key_copy->alg_id = key_orig->alg_id;
|
||||
- key_copy->mode = key_orig->mode;
|
||||
- key_copy->block_size = key_orig->block_size;
|
||||
- key_copy->handle = NULL;
|
||||
- key_copy->secret = buffer;
|
||||
- key_copy->secret_len = key_orig->secret_len;
|
||||
|
||||
+ if (key_is_symmetric(key_orig))
|
||||
+ {
|
||||
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, key_orig->u.s.secret_len ))) return STATUS_NO_MEMORY;
|
||||
+ memcpy( buffer, key_orig->u.s.secret, key_orig->u.s.secret_len );
|
||||
+
|
||||
+ key_copy->u.s.mode = key_orig->u.s.mode;
|
||||
+ key_copy->u.s.block_size = key_orig->u.s.block_size;
|
||||
+ key_copy->u.s.handle = NULL;
|
||||
+ key_copy->u.s.secret = buffer;
|
||||
+ key_copy->u.s.secret_len = key_orig->u.s.secret_len;
|
||||
+
|
||||
+ return STATUS_SUCCESS;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_symmetric_get_mode( struct key *key, enum mode_id *mode )
|
||||
+{
|
||||
+ *mode = key->u.s.mode;
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_symmetric_get_blocksize( struct key *key, ULONG *size )
|
||||
+{
|
||||
+ *size = key->u.s.block_size;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -884,19 +923,22 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val
|
||||
{
|
||||
if (!strcmpW( prop, BCRYPT_CHAINING_MODE ))
|
||||
{
|
||||
+ if (!key_is_symmetric(key))
|
||||
+ return STATUS_NOT_SUPPORTED;
|
||||
+
|
||||
if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_ECB, size ))
|
||||
{
|
||||
- key->mode = MODE_ID_ECB;
|
||||
+ key->u.s.mode = MODE_ID_ECB;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_CBC, size ))
|
||||
{
|
||||
- key->mode = MODE_ID_CBC;
|
||||
+ key->u.s.mode = MODE_ID_CBC;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else if (!strncmpW( (WCHAR *)value, BCRYPT_CHAIN_MODE_GCM, size ))
|
||||
{
|
||||
- key->mode = MODE_ID_GCM;
|
||||
+ key->u.s.mode = MODE_ID_GCM;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
@@ -916,22 +958,22 @@ static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
|
||||
{
|
||||
case ALG_ID_AES:
|
||||
WARN( "handle block size\n" );
|
||||
- switch (key->mode)
|
||||
+ switch (key->u.s.mode)
|
||||
{
|
||||
case MODE_ID_GCM:
|
||||
- if (key->secret_len == 16) return GNUTLS_CIPHER_AES_128_GCM;
|
||||
- if (key->secret_len == 32) return GNUTLS_CIPHER_AES_256_GCM;
|
||||
+ if (key->u.s.secret_len == 16) return GNUTLS_CIPHER_AES_128_GCM;
|
||||
+ if (key->u.s.secret_len == 32) return GNUTLS_CIPHER_AES_256_GCM;
|
||||
break;
|
||||
case MODE_ID_ECB: /* can be emulated with CBC + empty IV */
|
||||
case MODE_ID_CBC:
|
||||
- if (key->secret_len == 16) return GNUTLS_CIPHER_AES_128_CBC;
|
||||
- if (key->secret_len == 24) return GNUTLS_CIPHER_AES_192_CBC;
|
||||
- if (key->secret_len == 32) return GNUTLS_CIPHER_AES_256_CBC;
|
||||
+ if (key->u.s.secret_len == 16) return GNUTLS_CIPHER_AES_128_CBC;
|
||||
+ if (key->u.s.secret_len == 24) return GNUTLS_CIPHER_AES_192_CBC;
|
||||
+ if (key->u.s.secret_len == 32) return GNUTLS_CIPHER_AES_256_CBC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
- FIXME( "aes mode %u with key length %u not supported\n", key->mode, key->secret_len );
|
||||
+ FIXME( "aes mode %u with key length %u not supported\n", key->u.s.mode, key->u.s.secret_len );
|
||||
return GNUTLS_CIPHER_UNKNOWN;
|
||||
default:
|
||||
FIXME( "algorithm %u not supported\n", key->alg_id );
|
||||
@@ -939,17 +981,17 @@ static gnutls_cipher_algorithm_t get_gnutls_cipher( const struct key *key )
|
||||
}
|
||||
}
|
||||
|
||||
-static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
+static NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
{
|
||||
static const UCHAR zero_iv[16];
|
||||
gnutls_cipher_algorithm_t cipher;
|
||||
gnutls_datum_t secret, vector;
|
||||
int ret;
|
||||
|
||||
- if (key->handle)
|
||||
+ if (key->u.s.handle)
|
||||
{
|
||||
- pgnutls_cipher_deinit( key->handle );
|
||||
- key->handle = NULL;
|
||||
+ pgnutls_cipher_deinit( key->u.s.handle );
|
||||
+ key->u.s.handle = NULL;
|
||||
}
|
||||
|
||||
if ((cipher = get_gnutls_cipher( key )) == GNUTLS_CIPHER_UNKNOWN)
|
||||
@@ -961,12 +1003,12 @@ static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
iv_len = sizeof(zero_iv);
|
||||
}
|
||||
|
||||
- secret.data = key->secret;
|
||||
- secret.size = key->secret_len;
|
||||
+ secret.data = key->u.s.secret;
|
||||
+ secret.size = key->u.s.secret_len;
|
||||
vector.data = iv;
|
||||
vector.size = iv_len;
|
||||
|
||||
- if ((ret = pgnutls_cipher_init( &key->handle, cipher, &secret, &vector )))
|
||||
+ if ((ret = pgnutls_cipher_init( &key->u.s.handle, cipher, &secret, &vector )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
@@ -975,11 +1017,11 @@ static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
|
||||
+static NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if ((ret = pgnutls_cipher_add_auth( key->handle, auth_data, len )))
|
||||
+ if ((ret = pgnutls_cipher_add_auth( key->u.s.handle, auth_data, len )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
@@ -988,12 +1030,12 @@ static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
+static NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
ULONG output_len )
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if ((ret = pgnutls_cipher_encrypt2( key->handle, input, input_len, output, output_len )))
|
||||
+ if ((ret = pgnutls_cipher_encrypt2( key->u.s.handle, input, input_len, output, output_len )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
@@ -1002,12 +1044,12 @@ static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_le
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
+static NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
ULONG output_len )
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if ((ret = pgnutls_cipher_decrypt2( key->handle, input, input_len, output, output_len )))
|
||||
+ if ((ret = pgnutls_cipher_decrypt2( key->u.s.handle, input, input_len, output, output_len )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
@@ -1016,11 +1058,11 @@ 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 )
|
||||
+static NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if ((ret = pgnutls_cipher_tag( key->handle, tag, len )))
|
||||
+ if ((ret = pgnutls_cipher_tag( key->u.s.handle, tag, len )))
|
||||
{
|
||||
pgnutls_perror( ret );
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
@@ -1029,17 +1071,20 @@ static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_get_secret( struct key *key, UCHAR **secret, ULONG *len )
|
||||
+static NTSTATUS key_symmetric_get_secret( struct key *key, UCHAR **secret, ULONG *len )
|
||||
{
|
||||
- *secret = key->secret;
|
||||
- *len = key->secret_len;
|
||||
+ *secret = key->u.s.secret;
|
||||
+ *len = key->u.s.secret_len;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS key_destroy( struct key *key )
|
||||
{
|
||||
- if (key->handle) pgnutls_cipher_deinit( key->handle );
|
||||
- HeapFree( GetProcessHeap(), 0, key->secret );
|
||||
+ if (key_is_symmetric(key))
|
||||
+ {
|
||||
+ if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
|
||||
+ HeapFree( GetProcessHeap(), 0, key->u.s.secret );
|
||||
+ }
|
||||
HeapFree( GetProcessHeap(), 0, key );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1047,21 +1092,41 @@ static NTSTATUS key_destroy( struct key *key )
|
||||
struct key
|
||||
{
|
||||
struct object hdr;
|
||||
- enum mode_id mode;
|
||||
- ULONG block_size;
|
||||
};
|
||||
|
||||
-static NTSTATUS key_init( struct key *key, struct algorithm *alg, UCHAR *secret, ULONG secret_len )
|
||||
+static inline BOOL key_is_symmetric( struct key *key )
|
||||
+{
|
||||
+ ERR( "support for keys not available at build time\n" );
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static inline BOOL key_is_asymmetric( struct key *key )
|
||||
+{
|
||||
+ ERR( "support for keys not available at build time\n" );
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, UCHAR *secret, ULONG secret_len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
- key->mode = MODE_ID_CBC;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
- key_copy->mode = MODE_ID_CBC;
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_symmetric_get_mode( struct key *key, enum mode_id *mode )
|
||||
+{
|
||||
+ ERR( "support for keys not available at build time\n" );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_symmetric_get_blocksize( struct key *key, ULONG *size )
|
||||
+{
|
||||
+ ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -1071,39 +1136,39 @@ static NTSTATUS set_key_property( struct key *key, const WCHAR *prop, UCHAR *val
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
+static NTSTATUS key_symmetric_set_params( struct key *key, UCHAR *iv, ULONG iv_len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
|
||||
+static NTSTATUS key_symmetric_set_auth_data( struct key *key, UCHAR *auth_data, ULONG len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
+static NTSTATUS key_symmetric_encrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
ULONG output_len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
+static NTSTATUS key_symmetric_decrypt( struct key *key, const UCHAR *input, ULONG input_len, UCHAR *output,
|
||||
ULONG output_len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
-static NTSTATUS key_get_tag( struct key *key, UCHAR *tag, ULONG len )
|
||||
+static NTSTATUS key_symmetric_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_get_secret( struct key *key, UCHAR **secret, ULONG *len )
|
||||
+static NTSTATUS key_symmetric_get_secret( struct key *key, UCHAR **secret, ULONG *len )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
@@ -1136,7 +1201,7 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_
|
||||
}
|
||||
key->hdr.magic = MAGIC_KEY;
|
||||
|
||||
- if ((status = key_init( key, alg, secret, secret_len )))
|
||||
+ if ((status = key_symmetric_init( key, alg, secret, secret_len )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, key );
|
||||
*handle = NULL;
|
||||
@@ -1233,13 +1298,19 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE
|
||||
if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
|
||||
if (!output || !output_len || !size) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
+ if (!key_is_symmetric(key))
|
||||
+ {
|
||||
+ FIXME( "export of asymmetric keys not yet supported\n");
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
if (encrypt_key)
|
||||
{
|
||||
FIXME( "encryption of key not yet supported\n" );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
- if ((status = key_get_secret( key, &secret, &secret_len )))
|
||||
+ if ((status = key_symmetric_get_secret( key, &secret, &secret_len )))
|
||||
return status;
|
||||
|
||||
if (!strcmpW( type, BCRYPT_KEY_DATA_BLOB ))
|
||||
@@ -1280,19 +1351,30 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
struct key *key = handle;
|
||||
ULONG bytes_left = input_len;
|
||||
UCHAR *buf, *src, *dst;
|
||||
+ enum mode_id mode;
|
||||
+ ULONG block_size;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
|
||||
padding, iv, iv_len, output, output_len, ret_len, flags );
|
||||
|
||||
if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
|
||||
+
|
||||
+ if (!key_is_symmetric(key))
|
||||
+ {
|
||||
+ FIXME( "encryption with asymmetric keys not yet supported\n");
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
if (flags & ~BCRYPT_BLOCK_PADDING)
|
||||
{
|
||||
FIXME( "flags %08x not implemented\n", flags );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
- if (key->mode == MODE_ID_GCM)
|
||||
+ if ((status = key_symmetric_get_mode( key, &mode ))) return status;
|
||||
+
|
||||
+ if (mode == MODE_ID_GCM)
|
||||
{
|
||||
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
|
||||
|
||||
@@ -1303,7 +1385,7 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
if (auth_info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG)
|
||||
FIXME( "call chaining not implemented\n" );
|
||||
|
||||
- if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
|
||||
+ if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
|
||||
return status;
|
||||
|
||||
*ret_len = input_len;
|
||||
@@ -1311,46 +1393,48 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
if (input && !output) return STATUS_SUCCESS;
|
||||
if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
- if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
|
||||
+ if (auth_info->pbAuthData && (status = key_symmetric_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
|
||||
return status;
|
||||
- if ((status = key_encrypt( key, input, input_len, output, output_len )))
|
||||
+ if ((status = key_symmetric_encrypt( key, input, input_len, output, output_len )))
|
||||
return status;
|
||||
|
||||
- return key_get_tag( key, auth_info->pbTag, auth_info->cbTag );
|
||||
+ return key_symmetric_get_tag( key, auth_info->pbTag, auth_info->cbTag );
|
||||
}
|
||||
|
||||
- if ((status = key_set_params( key, iv, iv_len ))) return status;
|
||||
+ if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
|
||||
+ if ((status = key_symmetric_get_blocksize( key, &block_size ))) return status;
|
||||
+
|
||||
|
||||
*ret_len = input_len;
|
||||
|
||||
if (flags & BCRYPT_BLOCK_PADDING)
|
||||
- *ret_len = (input_len + key->block_size) & ~(key->block_size - 1);
|
||||
- else if (input_len & (key->block_size - 1))
|
||||
+ *ret_len = (input_len + block_size) & ~(block_size - 1);
|
||||
+ else if (input_len & (block_size - 1))
|
||||
return STATUS_INVALID_BUFFER_SIZE;
|
||||
|
||||
if (!output) return STATUS_SUCCESS;
|
||||
if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
- if (key->mode == MODE_ID_ECB && iv)
|
||||
+ if (mode == MODE_ID_ECB && iv)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
src = input;
|
||||
dst = output;
|
||||
- while (bytes_left >= key->block_size)
|
||||
+ while (bytes_left >= block_size)
|
||||
{
|
||||
- if ((status = key_encrypt( key, src, key->block_size, dst, key->block_size ))) return status;
|
||||
- if (key->mode == MODE_ID_ECB && (status = key_set_params( key, iv, iv_len ))) return status;
|
||||
- bytes_left -= key->block_size;
|
||||
- src += key->block_size;
|
||||
- dst += key->block_size;
|
||||
+ if ((status = key_symmetric_encrypt( key, src, block_size, dst, block_size ))) return status;
|
||||
+ if (mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, iv, iv_len ))) return status;
|
||||
+ bytes_left -= block_size;
|
||||
+ src += block_size;
|
||||
+ dst += block_size;
|
||||
}
|
||||
|
||||
if (flags & BCRYPT_BLOCK_PADDING)
|
||||
{
|
||||
- if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
|
||||
+ if (!(buf = HeapAlloc( GetProcessHeap(), 0, block_size ))) return STATUS_NO_MEMORY;
|
||||
memcpy( buf, src, bytes_left );
|
||||
- memset( buf + bytes_left, key->block_size - bytes_left, key->block_size - bytes_left );
|
||||
- status = key_encrypt( key, buf, key->block_size, dst, key->block_size );
|
||||
+ memset( buf + bytes_left, block_size - bytes_left, block_size - bytes_left );
|
||||
+ status = key_symmetric_encrypt( key, buf, block_size, dst, block_size );
|
||||
HeapFree( GetProcessHeap(), 0, buf );
|
||||
}
|
||||
|
||||
@@ -1364,19 +1448,30 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
struct key *key = handle;
|
||||
ULONG bytes_left = input_len;
|
||||
UCHAR *buf, *src, *dst;
|
||||
+ enum mode_id mode;
|
||||
+ ULONG block_size;
|
||||
NTSTATUS status;
|
||||
|
||||
TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len,
|
||||
padding, iv, iv_len, output, output_len, ret_len, flags );
|
||||
|
||||
if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
|
||||
+
|
||||
+ if (!key_is_symmetric(key))
|
||||
+ {
|
||||
+ FIXME( "decryption with asymmetric keys not yet supported\n");
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
if (flags & ~BCRYPT_BLOCK_PADDING)
|
||||
{
|
||||
FIXME( "flags %08x not supported\n", flags );
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
- if (key->mode == MODE_ID_GCM)
|
||||
+ if ((status = key_symmetric_get_mode( key, &mode ))) return status;
|
||||
+
|
||||
+ if (mode == MODE_ID_GCM)
|
||||
{
|
||||
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding;
|
||||
UCHAR tag[16];
|
||||
@@ -1386,7 +1481,7 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
if (!auth_info->pbTag) return STATUS_INVALID_PARAMETER;
|
||||
if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
- if ((status = key_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
|
||||
+ if ((status = key_symmetric_set_params( key, auth_info->pbNonce, auth_info->cbNonce )))
|
||||
return status;
|
||||
|
||||
*ret_len = input_len;
|
||||
@@ -1394,12 +1489,12 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
if (!output) return STATUS_SUCCESS;
|
||||
if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
- if (auth_info->pbAuthData && (status = key_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
|
||||
+ if (auth_info->pbAuthData && (status = key_symmetric_set_auth_data( key, auth_info->pbAuthData, auth_info->cbAuthData )))
|
||||
return status;
|
||||
- if ((status = key_decrypt( key, input, input_len, output, output_len )))
|
||||
+ if ((status = key_symmetric_decrypt( key, input, input_len, output, output_len )))
|
||||
return status;
|
||||
|
||||
- if ((status = key_get_tag( key, tag, sizeof(tag) )))
|
||||
+ if ((status = key_symmetric_get_tag( key, tag, sizeof(tag) )))
|
||||
return status;
|
||||
if (memcmp( tag, auth_info->pbTag, auth_info->cbTag ))
|
||||
return STATUS_AUTH_TAG_MISMATCH;
|
||||
@@ -1407,44 +1502,45 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
- if ((status = key_set_params( key, iv, iv_len ))) return status;
|
||||
+ if ((status = key_symmetric_set_params( key, iv, iv_len ))) return status;
|
||||
+ if ((status = key_symmetric_get_blocksize( key, &block_size ))) return status;
|
||||
|
||||
*ret_len = input_len;
|
||||
|
||||
- if (input_len & (key->block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
|
||||
+ if (input_len & (block_size - 1)) return STATUS_INVALID_BUFFER_SIZE;
|
||||
if (!output) return STATUS_SUCCESS;
|
||||
if (flags & BCRYPT_BLOCK_PADDING)
|
||||
{
|
||||
- if (output_len + key->block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
|
||||
- if (input_len < key->block_size) return STATUS_BUFFER_TOO_SMALL;
|
||||
- bytes_left -= key->block_size;
|
||||
+ if (output_len + block_size < *ret_len) return STATUS_BUFFER_TOO_SMALL;
|
||||
+ if (input_len < block_size) return STATUS_BUFFER_TOO_SMALL;
|
||||
+ bytes_left -= block_size;
|
||||
}
|
||||
else if (output_len < *ret_len)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
- if (key->mode == MODE_ID_ECB && iv)
|
||||
+ if (mode == MODE_ID_ECB && iv)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
src = input;
|
||||
dst = output;
|
||||
- while (bytes_left >= key->block_size)
|
||||
+ while (bytes_left >= block_size)
|
||||
{
|
||||
- if ((status = key_decrypt( key, src, key->block_size, dst, key->block_size ))) return status;
|
||||
- if (key->mode == MODE_ID_ECB && (status = key_set_params( key, iv, iv_len ))) return status;
|
||||
- bytes_left -= key->block_size;
|
||||
- src += key->block_size;
|
||||
- dst += key->block_size;
|
||||
+ if ((status = key_symmetric_decrypt( key, src, block_size, dst, block_size ))) return status;
|
||||
+ if (mode == MODE_ID_ECB && (status = key_symmetric_set_params( key, iv, iv_len ))) return status;
|
||||
+ bytes_left -= block_size;
|
||||
+ src += block_size;
|
||||
+ dst += block_size;
|
||||
}
|
||||
|
||||
if (flags & BCRYPT_BLOCK_PADDING)
|
||||
{
|
||||
- if (!(buf = HeapAlloc( GetProcessHeap(), 0, key->block_size ))) return STATUS_NO_MEMORY;
|
||||
- status = key_decrypt( key, src, key->block_size, buf, key->block_size );
|
||||
- if (!status && buf[ key->block_size - 1 ] <= key->block_size)
|
||||
+ if (!(buf = HeapAlloc( GetProcessHeap(), 0, block_size ))) return STATUS_NO_MEMORY;
|
||||
+ status = key_symmetric_decrypt( key, src, block_size, buf, block_size );
|
||||
+ if (!status && buf[ block_size - 1 ] <= block_size)
|
||||
{
|
||||
- *ret_len -= buf[ key->block_size - 1 ];
|
||||
+ *ret_len -= buf[ block_size - 1 ];
|
||||
if (output_len < *ret_len) status = STATUS_BUFFER_TOO_SMALL;
|
||||
- else memcpy( dst, buf, key->block_size - buf[ key->block_size - 1 ] );
|
||||
+ else memcpy( dst, buf, block_size - buf[ block_size - 1 ] );
|
||||
}
|
||||
else
|
||||
status = STATUS_UNSUCCESSFUL; /* FIXME: invalid padding */
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,86 @@
|
||||
From 4deacb4fe26419c2c3e7e9e7b194736e2f0b6063 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 18:49:09 +0200
|
||||
Subject: include: Add ecdsa and asymmetric key related bcrypt definitions.
|
||||
|
||||
---
|
||||
include/bcrypt.h | 28 ++++++++++++++++++++++++++++
|
||||
include/ntstatus.h | 2 ++
|
||||
2 files changed, 30 insertions(+)
|
||||
|
||||
diff --git a/include/bcrypt.h b/include/bcrypt.h
|
||||
index de812ffe333..f524cb9afdc 100644
|
||||
--- a/include/bcrypt.h
|
||||
+++ b/include/bcrypt.h
|
||||
@@ -61,6 +61,8 @@ typedef LONG NTSTATUS;
|
||||
#define BCRYPT_OPAQUE_KEY_BLOB (const WCHAR []){'O','p','a','q','u','e','K','e','y','B','l','o','b',0}
|
||||
#define BCRYPT_KEY_DATA_BLOB (const WCHAR []){'K','e','y','D','a','t','a','B','l','o','b',0}
|
||||
#define BCRYPT_AES_WRAP_KEY_BLOB (const WCHAR []){'R','f','c','3','5','6','5','K','e','y','W','r','a','p','B','l','o','b',0}
|
||||
+#define BCRYPT_ECCPUBLIC_BLOB (const WCHAR []){'E','C','C','P','U','B','L','I','C','B','L','O','B',0}
|
||||
+#define BCRYPT_ECCPRIVATE_BLOB (const WCHAR []){'E','C','C','P','R','I','V','A','T','E','B','L','O','B',0}
|
||||
|
||||
#define MS_PRIMITIVE_PROVIDER (const WCHAR [])\
|
||||
{'M','i','c','r','o','s','o','f','t',' ','P','r','i','m','i','t','i','v','e',' ','P','r','o','v','i','d','e','r',0}
|
||||
@@ -74,6 +76,9 @@ typedef LONG NTSTATUS;
|
||||
#define BCRYPT_SHA256_ALGORITHM (const WCHAR []){'S','H','A','2','5','6',0}
|
||||
#define BCRYPT_SHA384_ALGORITHM (const WCHAR []){'S','H','A','3','8','4',0}
|
||||
#define BCRYPT_SHA512_ALGORITHM (const WCHAR []){'S','H','A','5','1','2',0}
|
||||
+#define BCRYPT_ECDSA_P256_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','2','5','6',0}
|
||||
+#define BCRYPT_ECDSA_P384_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','3','8','4',0}
|
||||
+#define BCRYPT_ECDSA_P521_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','5','2','1',0}
|
||||
|
||||
#define BCRYPT_CHAIN_MODE_NA (const WCHAR []){'C','h','a','i','n','i','n','g','M','o','d','e','N','/','A',0}
|
||||
#define BCRYPT_CHAIN_MODE_CBC (const WCHAR []){'C','h','a','i','n','i','n','g','M','o','d','e','C','B','C',0}
|
||||
@@ -82,6 +87,13 @@ typedef LONG NTSTATUS;
|
||||
#define BCRYPT_CHAIN_MODE_CCM (const WCHAR []){'C','h','a','i','n','i','n','g','M','o','d','e','C','C','M',0}
|
||||
#define BCRYPT_CHAIN_MODE_GCM (const WCHAR []){'C','h','a','i','n','i','n','g','M','o','d','e','G','C','M',0}
|
||||
|
||||
+#define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345
|
||||
+#define BCRYPT_ECDSA_PRIVATE_P256_MAGIC 0x32534345
|
||||
+#define BCRYPT_ECDSA_PUBLIC_P384_MAGIC 0x33534345
|
||||
+#define BCRYPT_ECDSA_PRIVATE_P384_MAGIC 0x34534345
|
||||
+#define BCRYPT_ECDSA_PUBLIC_P521_MAGIC 0x35534345
|
||||
+#define BCRYPT_ECDSA_PRIVATE_P521_MAGIC 0x36534345
|
||||
+
|
||||
typedef struct _BCRYPT_ALGORITHM_IDENTIFIER
|
||||
{
|
||||
LPWSTR pszName;
|
||||
@@ -120,6 +132,22 @@ typedef struct _BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
|
||||
ULONG dwFlags;
|
||||
} BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO, *PBCRYPT_AUTHENTICATED_CIPHER_MODE_INFO;
|
||||
|
||||
+typedef struct _BCRYPT_ECCKEY_BLOB
|
||||
+{
|
||||
+ ULONG dwMagic;
|
||||
+ ULONG cbKey;
|
||||
+} BCRYPT_ECCKEY_BLOB, *PBCRYPT_ECCKEY_BLOB;
|
||||
+
|
||||
+typedef struct _BCRYPT_PKCS1_PADDING_INFO
|
||||
+{
|
||||
+ LPCWSTR pszAlgId;
|
||||
+} BCRYPT_PKCS1_PADDING_INFO;
|
||||
+
|
||||
+#define BCRYPT_PAD_NONE 0x00000001
|
||||
+#define BCRYPT_PAD_PKCS1 0x00000002
|
||||
+#define BCRYPT_PAD_OAEP 0x00000004
|
||||
+#define BCRYPT_PAD_PSS 0x00000008
|
||||
+
|
||||
#define BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION 1
|
||||
|
||||
#define BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG 0x00000001
|
||||
diff --git a/include/ntstatus.h b/include/ntstatus.h
|
||||
index 7026de7f85f..735b6c2c41c 100644
|
||||
--- a/include/ntstatus.h
|
||||
+++ b/include/ntstatus.h
|
||||
@@ -990,6 +990,8 @@
|
||||
|
||||
#define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898)
|
||||
|
||||
+#define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000)
|
||||
+#define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001)
|
||||
#define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002)
|
||||
|
||||
#define RPC_NT_INVALID_STRING_BINDING ((NTSTATUS) 0xC0020001)
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,109 @@
|
||||
From bbc4343e5ce6b5a5404dbd9d61ce7f49f042da52 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 18:50:04 +0200
|
||||
Subject: bcrypt/tests: Add basic test for ecdsa.
|
||||
|
||||
---
|
||||
dlls/bcrypt/tests/bcrypt.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 65 insertions(+)
|
||||
|
||||
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
|
||||
index ae48914b5de..be901202970 100644
|
||||
--- a/dlls/bcrypt/tests/bcrypt.c
|
||||
+++ b/dlls/bcrypt/tests/bcrypt.c
|
||||
@@ -50,6 +50,8 @@ static NTSTATUS (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE);
|
||||
static NTSTATUS (WINAPI *pBCryptImportKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *,
|
||||
PUCHAR, ULONG, PUCHAR, ULONG, ULONG);
|
||||
static NTSTATUS (WINAPI *pBCryptExportKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
|
||||
+static NTSTATUS (WINAPI *pBCryptImportKeyPair)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
|
||||
+static NTSTATUS (WINAPI *pBCryptVerifySignature)(BCRYPT_KEY_HANDLE, VOID *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
|
||||
|
||||
static void test_BCryptGenRandom(void)
|
||||
{
|
||||
@@ -1635,6 +1637,66 @@ static void test_key_import_export(void)
|
||||
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
|
||||
}
|
||||
|
||||
+static BYTE eccPubkey[] =
|
||||
+{
|
||||
+ /* X */
|
||||
+ 0x3b, 0x3c, 0x34, 0xc8, 0x3f, 0x15, 0xea, 0x02, 0x68, 0x46, 0x69, 0xdf, 0x0c, 0xa6, 0xee, 0x7a,
|
||||
+ 0xd9, 0x82, 0x08, 0x9b, 0x37, 0x53, 0x42, 0xf3, 0x13, 0x63, 0xda, 0x65, 0x79, 0xe8, 0x04, 0x9e,
|
||||
+ /* Y */
|
||||
+ 0x8c, 0x77, 0xc4, 0x33, 0x77, 0xd9, 0x5a, 0x7f, 0x60, 0x7b, 0x98, 0xce, 0xf3, 0x96, 0x56, 0xd6,
|
||||
+ 0xb5, 0x8d, 0x87, 0x7a, 0x00, 0x2b, 0xf3, 0x70, 0xb3, 0x90, 0x73, 0xa0, 0x56, 0x06, 0x3b, 0x22,
|
||||
+};
|
||||
+static BYTE certHash[] =
|
||||
+{
|
||||
+ 0x28, 0x19, 0x0f, 0x15, 0x6d, 0x75, 0xcc, 0xcf, 0x62, 0xf1, 0x5e, 0xe6, 0x8a, 0xc3, 0xf0, 0x5d,
|
||||
+ 0x89, 0x28, 0x2d, 0x48, 0xd8, 0x73, 0x7c, 0x05, 0x05, 0x8e, 0xbc, 0xce, 0x28, 0xb7, 0xba, 0xc9,
|
||||
+};
|
||||
+static BYTE certSignature[] =
|
||||
+{
|
||||
+ /* r */
|
||||
+ 0xd7, 0x29, 0xce, 0x5a, 0xef, 0x74, 0x85, 0xd1, 0x18, 0x5f, 0x6e, 0xf1, 0xba, 0x53, 0xd4, 0xcd,
|
||||
+ 0xdd, 0xe0, 0x5d, 0xf1, 0x5e, 0x48, 0x51, 0xea, 0x63, 0xc0, 0xe8, 0xe2, 0xf6, 0xfa, 0x4c, 0xaf,
|
||||
+ /* s */
|
||||
+ 0xe3, 0x94, 0x15, 0x3b, 0x6c, 0x71, 0x6e, 0x44, 0x22, 0xcb, 0xa0, 0x88, 0xcd, 0x0a, 0x5a, 0x50,
|
||||
+ 0x29, 0x7c, 0x5c, 0xd6, 0x6c, 0xd2, 0xe0, 0x7f, 0xcd, 0x02, 0x92, 0x21, 0x4c, 0x2c, 0x92, 0xee,
|
||||
+};
|
||||
+
|
||||
+static void test_ECDSA(void)
|
||||
+{
|
||||
+ BYTE buffer[sizeof(BCRYPT_ECCKEY_BLOB) + sizeof(eccPubkey)];
|
||||
+ BCRYPT_ECCKEY_BLOB *ecckey = (void *)buffer;
|
||||
+ BCRYPT_ALG_HANDLE alg = NULL;
|
||||
+ BCRYPT_KEY_HANDLE key = NULL;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ status = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P256_ALGORITHM, NULL, 0);
|
||||
+ if (status)
|
||||
+ {
|
||||
+ todo_wine win_skip("Failed to open ECDSA provider: %08x, skipping test\n", status);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ecckey->dwMagic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
|
||||
+ memcpy(ecckey + 1, eccPubkey, sizeof(eccPubkey));
|
||||
+
|
||||
+ ecckey->cbKey = 2;
|
||||
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &key, buffer, sizeof(buffer), 0);
|
||||
+ ok(status == STATUS_INVALID_PARAMETER, "Expected STATUS_INVALID_PARAMETER, got %08x\n", status);
|
||||
+
|
||||
+ ecckey->cbKey = sizeof(eccPubkey) / 2;
|
||||
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &key, buffer, sizeof(buffer), 0);
|
||||
+ ok(!status, "BCryptImportKeyPair failed: %08x\n", status);
|
||||
+
|
||||
+ status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash) - 1, certSignature, sizeof(certSignature), 0);
|
||||
+ ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
|
||||
+
|
||||
+ status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash), certSignature, sizeof(certSignature), 0);
|
||||
+ ok(!status, "BCryptVerifySignature failed: %08x\n", status);
|
||||
+
|
||||
+ pBCryptDestroyKey(key);
|
||||
+ pBCryptCloseAlgorithmProvider(alg, 0);
|
||||
+}
|
||||
+
|
||||
START_TEST(bcrypt)
|
||||
{
|
||||
HMODULE module;
|
||||
@@ -1665,6 +1727,8 @@ START_TEST(bcrypt)
|
||||
pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey");
|
||||
pBCryptImportKey = (void *)GetProcAddress(module, "BCryptImportKey");
|
||||
pBCryptExportKey = (void *)GetProcAddress(module, "BCryptExportKey");
|
||||
+ pBCryptImportKeyPair = (void *)GetProcAddress(module, "BCryptImportKeyPair");
|
||||
+ pBCryptVerifySignature = (void *)GetProcAddress(module, "BCryptVerifySignature");
|
||||
|
||||
test_BCryptGenRandom();
|
||||
test_BCryptGetFipsAlgorithmMode();
|
||||
@@ -1679,6 +1743,7 @@ START_TEST(bcrypt)
|
||||
test_BCryptEncrypt();
|
||||
test_BCryptDecrypt();
|
||||
test_key_import_export();
|
||||
+ test_ECDSA();
|
||||
|
||||
if (pBCryptHash) /* >= Win 10 */
|
||||
test_BcryptHash();
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,308 @@
|
||||
From 745f8d61f2335efb96078f937ca113f144892cc3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 19:18:58 +0200
|
||||
Subject: bcrypt: Implement importing of ecdsa keys.
|
||||
|
||||
---
|
||||
dlls/bcrypt/bcrypt.spec | 4 +-
|
||||
dlls/bcrypt/bcrypt_main.c | 156 ++++++++++++++++++++++++++++++++++++++++++---
|
||||
dlls/bcrypt/tests/bcrypt.c | 6 +-
|
||||
include/bcrypt.h | 2 +
|
||||
4 files changed, 154 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec
|
||||
index f8a8c45a1d5..5d21b4646cc 100644
|
||||
--- a/dlls/bcrypt/bcrypt.spec
|
||||
+++ b/dlls/bcrypt/bcrypt.spec
|
||||
@@ -32,7 +32,7 @@
|
||||
@ stdcall BCryptHash(ptr ptr long ptr long ptr long)
|
||||
@ stdcall BCryptHashData(ptr ptr long long)
|
||||
@ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long)
|
||||
-@ stub BCryptImportKeyPair
|
||||
+@ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long)
|
||||
@ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long)
|
||||
@ stub BCryptQueryContextConfiguration
|
||||
@ stub BCryptQueryContextFunctionConfiguration
|
||||
@@ -50,7 +50,7 @@
|
||||
@ stub BCryptSignHash
|
||||
@ stub BCryptUnregisterConfigChangeNotify
|
||||
@ stub BCryptUnregisterProvider
|
||||
-@ stub BCryptVerifySignature
|
||||
+@ stdcall BCryptVerifySignature(ptr ptr ptr long ptr long long)
|
||||
@ stub GetAsymmetricEncryptionInterface
|
||||
@ stub GetCipherInterface
|
||||
@ stub GetHashInterface
|
||||
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
|
||||
index 4e1992292cd..f822a7aadf3 100644
|
||||
--- a/dlls/bcrypt/bcrypt_main.c
|
||||
+++ b/dlls/bcrypt/bcrypt_main.c
|
||||
@@ -181,7 +181,9 @@ enum alg_id
|
||||
ALG_ID_SHA1,
|
||||
ALG_ID_SHA256,
|
||||
ALG_ID_SHA384,
|
||||
- ALG_ID_SHA512
|
||||
+ ALG_ID_SHA512,
|
||||
+ ALG_ID_ECDSA_P256,
|
||||
+ ALG_ID_ECDSA_P384,
|
||||
};
|
||||
|
||||
enum mode_id
|
||||
@@ -201,13 +203,15 @@ static const struct {
|
||||
const WCHAR *alg_name;
|
||||
BOOL symmetric;
|
||||
} alg_props[] = {
|
||||
- /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM, TRUE },
|
||||
- /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM, FALSE },
|
||||
- /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM, FALSE },
|
||||
- /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM, FALSE },
|
||||
- /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM, FALSE },
|
||||
- /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
|
||||
- /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_AES */ { 654, 0, 0, BCRYPT_AES_ALGORITHM, TRUE },
|
||||
+ /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA1 */ { 278, 20, 512, BCRYPT_SHA1_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_ECDSA_P256 */ { 0, 0, 0, BCRYPT_ECDSA_P256_ALGORITHM, FALSE },
|
||||
+ /* ALG_ID_ECDSA_P384 */ { 0, 0, 0, BCRYPT_ECDSA_P384_ALGORITHM, FALSE },
|
||||
};
|
||||
|
||||
struct algorithm
|
||||
@@ -284,6 +288,8 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR
|
||||
else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
|
||||
else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
|
||||
else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
|
||||
+ else if (!strcmpW( id, BCRYPT_ECDSA_P256_ALGORITHM )) alg_id = ALG_ID_ECDSA_P256;
|
||||
+ else if (!strcmpW( id, BCRYPT_ECDSA_P384_ALGORITHM )) alg_id = ALG_ID_ECDSA_P384;
|
||||
else
|
||||
{
|
||||
FIXME( "algorithm %s not supported\n", debugstr_w(id) );
|
||||
@@ -825,6 +831,12 @@ struct key_symmetric
|
||||
ULONG secret_len;
|
||||
};
|
||||
|
||||
+struct key_asymmetric
|
||||
+{
|
||||
+ UCHAR *pubkey;
|
||||
+ ULONG pubkey_len;
|
||||
+};
|
||||
+
|
||||
struct key
|
||||
{
|
||||
struct object hdr;
|
||||
@@ -832,6 +844,7 @@ struct key
|
||||
union
|
||||
{
|
||||
struct key_symmetric s;
|
||||
+ struct key_asymmetric a;
|
||||
} u;
|
||||
};
|
||||
|
||||
@@ -871,6 +884,33 @@ static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, cons
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
|
||||
+{
|
||||
+ UCHAR *buffer;
|
||||
+
|
||||
+ if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
|
||||
+
|
||||
+ switch (alg->id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256:
|
||||
+ case ALG_ID_ECDSA_P384:
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ FIXME( "algorithm %u not supported\n", alg->id );
|
||||
+ return STATUS_NOT_SUPPORTED;
|
||||
+ }
|
||||
+
|
||||
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, pubkey_len ))) return STATUS_NO_MEMORY;
|
||||
+ memcpy( buffer, pubkey, pubkey_len );
|
||||
+
|
||||
+ key->alg_id = alg->id;
|
||||
+ key->u.a.pubkey = buffer;
|
||||
+ key->u.a.pubkey_len = pubkey_len;
|
||||
+
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
static inline BOOL key_is_symmetric( struct key *key )
|
||||
{
|
||||
return alg_props[key->alg_id].symmetric;
|
||||
@@ -903,7 +943,13 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
|
||||
}
|
||||
else
|
||||
{
|
||||
- return STATUS_NOT_IMPLEMENTED;
|
||||
+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, key_orig->u.a.pubkey_len ))) return STATUS_NO_MEMORY;
|
||||
+ memcpy( buffer, key_orig->u.a.pubkey, key_orig->u.a.pubkey_len );
|
||||
+
|
||||
+ key_copy->u.a.pubkey = buffer;
|
||||
+ key_copy->u.a.pubkey_len = key_orig->u.a.pubkey_len;
|
||||
+
|
||||
+ return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,6 +1131,10 @@ static NTSTATUS key_destroy( struct key *key )
|
||||
if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
|
||||
HeapFree( GetProcessHeap(), 0, key->u.s.secret );
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ HeapFree( GetProcessHeap(), 0, key->u.a.pubkey );
|
||||
+ }
|
||||
HeapFree( GetProcessHeap(), 0, key );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1112,6 +1162,12 @@ static NTSTATUS key_symmetric_init( struct key *key, struct algorithm *alg, UCHA
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
+static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
|
||||
+{
|
||||
+ ERR( "support for keys not available at build time\n" );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+}
|
||||
+
|
||||
static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
|
||||
{
|
||||
ERR( "support for keys not available at build time\n" );
|
||||
@@ -1334,6 +1390,88 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
+NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type,
|
||||
+ BCRYPT_KEY_HANDLE *ret_key, UCHAR *input, ULONG input_len, ULONG flags )
|
||||
+{
|
||||
+ struct algorithm *alg = algorithm;
|
||||
+ NTSTATUS status;
|
||||
+ struct key *key;
|
||||
+
|
||||
+ TRACE( "%p, %p, %s, %p, %p, %u, %u\n", algorithm, decrypt_key, debugstr_w(type), ret_key, input, input_len, flags );
|
||||
+
|
||||
+ if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
|
||||
+ if (!ret_key || !type || !input) return STATUS_INVALID_PARAMETER;
|
||||
+
|
||||
+ *ret_key = NULL;
|
||||
+
|
||||
+ if (decrypt_key)
|
||||
+ {
|
||||
+ FIXME( "decrypting of key not yet supported\n" );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
+ if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
|
||||
+ {
|
||||
+ BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input;
|
||||
+ DWORD key_size, magic;
|
||||
+
|
||||
+ if (input_len < sizeof(*ecc_blob))
|
||||
+ return STATUS_INVALID_PARAMETER;
|
||||
+
|
||||
+ switch (alg->id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256:
|
||||
+ key_size = 32;
|
||||
+ magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
|
||||
+ break;
|
||||
+ case ALG_ID_ECDSA_P384:
|
||||
+ key_size = 48;
|
||||
+ magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ FIXME("Algorithm %d does not yet support importing blob of type: %s\n", alg->id, debugstr_w(type));
|
||||
+ return STATUS_NOT_SUPPORTED;
|
||||
+ }
|
||||
+
|
||||
+ if (ecc_blob->dwMagic != magic)
|
||||
+ return STATUS_NOT_SUPPORTED;
|
||||
+
|
||||
+ if (ecc_blob->cbKey != key_size)
|
||||
+ return STATUS_INVALID_PARAMETER;
|
||||
+
|
||||
+ if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) )))
|
||||
+ return STATUS_NO_MEMORY;
|
||||
+
|
||||
+ key->hdr.magic = MAGIC_KEY;
|
||||
+ if ((status = key_asymmetric_init( key, alg, (BYTE *)(ecc_blob + 1), ecc_blob->cbKey * 2 )))
|
||||
+ {
|
||||
+ HeapFree( GetProcessHeap(), 0, key );
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ *ret_key = key;
|
||||
+ return STATUS_SUCCESS;
|
||||
+ }
|
||||
+
|
||||
+ FIXME( "unsupported key type %s\n", debugstr_w(type) );
|
||||
+ return STATUS_NOT_SUPPORTED;
|
||||
+}
|
||||
+
|
||||
+NTSTATUS WINAPI BCryptVerifySignature( BCRYPT_KEY_HANDLE handle, void *padding, UCHAR *hash, ULONG hash_len,
|
||||
+ UCHAR *signature, ULONG signature_len, ULONG flags )
|
||||
+{
|
||||
+ struct key *key = handle;
|
||||
+
|
||||
+ FIXME( "%p, %p, %p, %u, %p, %u, %08x: stub!\n", handle, padding, hash,
|
||||
+ hash_len, signature, signature_len, flags );
|
||||
+
|
||||
+ if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
|
||||
+ if (!key_is_asymmetric(key)) return STATUS_NOT_SUPPORTED;
|
||||
+
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+}
|
||||
+
|
||||
NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
|
||||
{
|
||||
struct key *key = handle;
|
||||
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
|
||||
index be901202970..20f70706430 100644
|
||||
--- a/dlls/bcrypt/tests/bcrypt.c
|
||||
+++ b/dlls/bcrypt/tests/bcrypt.c
|
||||
@@ -1672,7 +1672,7 @@ static void test_ECDSA(void)
|
||||
status = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDSA_P256_ALGORITHM, NULL, 0);
|
||||
if (status)
|
||||
{
|
||||
- todo_wine win_skip("Failed to open ECDSA provider: %08x, skipping test\n", status);
|
||||
+ win_skip("Failed to open ECDSA provider: %08x, skipping test\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1688,10 +1688,10 @@ static void test_ECDSA(void)
|
||||
ok(!status, "BCryptImportKeyPair failed: %08x\n", status);
|
||||
|
||||
status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash) - 1, certSignature, sizeof(certSignature), 0);
|
||||
- ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
|
||||
+ todo_wine ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
|
||||
|
||||
status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash), certSignature, sizeof(certSignature), 0);
|
||||
- ok(!status, "BCryptVerifySignature failed: %08x\n", status);
|
||||
+ todo_wine ok(!status, "BCryptVerifySignature failed: %08x\n", status);
|
||||
|
||||
pBCryptDestroyKey(key);
|
||||
pBCryptCloseAlgorithmProvider(alg, 0);
|
||||
diff --git a/include/bcrypt.h b/include/bcrypt.h
|
||||
index f524cb9afdc..3dcc953e9ed 100644
|
||||
--- a/include/bcrypt.h
|
||||
+++ b/include/bcrypt.h
|
||||
@@ -185,8 +185,10 @@ NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *);
|
||||
NTSTATUS WINAPI BCryptGetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
|
||||
NTSTATUS WINAPI BCryptHash(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, PUCHAR, ULONG);
|
||||
NTSTATUS WINAPI BCryptHashData(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
|
||||
+NTSTATUS WINAPI BCryptImportKeyPair(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
|
||||
NTSTATUS WINAPI BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *, LPCWSTR, LPCWSTR, ULONG);
|
||||
NTSTATUS WINAPI BCryptSetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
|
||||
NTSTATUS WINAPI BCryptDuplicateHash(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
|
||||
+NTSTATUS WINAPI BCryptVerifySignature(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
|
||||
|
||||
#endif /* __WINE_BCRYPT_H */
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,362 @@
|
||||
From 13ffc8c6432546a32aa4c2af5cd4c3fa1337947e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 20:31:00 +0200
|
||||
Subject: bcrypt: Implement BCryptVerifySignature for ecdsa signatures.
|
||||
|
||||
---
|
||||
dlls/bcrypt/bcrypt_main.c | 281 ++++++++++++++++++++++++++++++++++++++++++++-
|
||||
dlls/bcrypt/tests/bcrypt.c | 4 +-
|
||||
2 files changed, 281 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
|
||||
index f822a7aadf3..866364f237e 100644
|
||||
--- a/dlls/bcrypt/bcrypt_main.c
|
||||
+++ b/dlls/bcrypt/bcrypt_main.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#elif defined(SONAME_LIBGNUTLS)
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/crypto.h>
|
||||
+#include <gnutls/abstract.h>
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
@@ -64,6 +65,11 @@ MAKE_FUNCPTR(gnutls_global_init);
|
||||
MAKE_FUNCPTR(gnutls_global_set_log_function);
|
||||
MAKE_FUNCPTR(gnutls_global_set_log_level);
|
||||
MAKE_FUNCPTR(gnutls_perror);
|
||||
+MAKE_FUNCPTR(gnutls_pubkey_init);
|
||||
+MAKE_FUNCPTR(gnutls_pubkey_deinit);
|
||||
+MAKE_FUNCPTR(gnutls_pubkey_import_ecc_raw);
|
||||
+MAKE_FUNCPTR(gnutls_pk_to_sign);
|
||||
+MAKE_FUNCPTR(gnutls_pubkey_verify_hash2);
|
||||
#undef MAKE_FUNCPTR
|
||||
|
||||
#if GNUTLS_VERSION_MAJOR < 3
|
||||
@@ -113,6 +119,11 @@ static BOOL gnutls_initialize(void)
|
||||
LOAD_FUNCPTR(gnutls_global_set_log_function)
|
||||
LOAD_FUNCPTR(gnutls_global_set_log_level)
|
||||
LOAD_FUNCPTR(gnutls_perror)
|
||||
+ LOAD_FUNCPTR(gnutls_pubkey_init);
|
||||
+ LOAD_FUNCPTR(gnutls_pubkey_deinit);
|
||||
+ LOAD_FUNCPTR(gnutls_pubkey_import_ecc_raw);
|
||||
+ LOAD_FUNCPTR(gnutls_pk_to_sign);
|
||||
+ LOAD_FUNCPTR(gnutls_pubkey_verify_hash2);
|
||||
#undef LOAD_FUNCPTR
|
||||
|
||||
if (!(pgnutls_cipher_tag = wine_dlsym( libgnutls_handle, "gnutls_cipher_tag", NULL, 0 )))
|
||||
@@ -1124,6 +1135,264 @@ static NTSTATUS key_symmetric_get_secret( struct key *key, UCHAR **secret, ULONG
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
+struct buffer
|
||||
+{
|
||||
+ BYTE *buffer;
|
||||
+ DWORD length;
|
||||
+ DWORD pos;
|
||||
+ BOOL error;
|
||||
+};
|
||||
+
|
||||
+static void buffer_init( struct buffer *buffer )
|
||||
+{
|
||||
+ buffer->buffer = NULL;
|
||||
+ buffer->length = 0;
|
||||
+ buffer->pos = 0;
|
||||
+ buffer->error = FALSE;
|
||||
+}
|
||||
+
|
||||
+static void buffer_free( struct buffer *buffer )
|
||||
+{
|
||||
+ HeapFree( GetProcessHeap(), 0, buffer->buffer );
|
||||
+}
|
||||
+
|
||||
+static void buffer_append( struct buffer *buffer, BYTE *data, DWORD len )
|
||||
+{
|
||||
+ if (!len) return;
|
||||
+
|
||||
+ if (buffer->pos + len > buffer->length)
|
||||
+ {
|
||||
+ DWORD new_length = max( max( buffer->pos + len, buffer->length * 2 ), 64 );
|
||||
+ BYTE *new_buffer;
|
||||
+
|
||||
+ if (buffer->buffer)
|
||||
+ new_buffer = HeapReAlloc( GetProcessHeap(), 0, buffer->buffer, new_length );
|
||||
+ else
|
||||
+ new_buffer = HeapAlloc( GetProcessHeap(), 0, new_length );
|
||||
+
|
||||
+ if (!new_buffer)
|
||||
+ {
|
||||
+ ERR( "out of memory\n" );
|
||||
+ buffer->error = TRUE;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ buffer->buffer = new_buffer;
|
||||
+ buffer->length = new_length;
|
||||
+ }
|
||||
+
|
||||
+ memcpy( &buffer->buffer[buffer->pos], data, len );
|
||||
+ buffer->pos += len;
|
||||
+}
|
||||
+
|
||||
+static void buffer_append_byte( struct buffer *buffer, BYTE value )
|
||||
+{
|
||||
+ buffer_append( buffer, &value, sizeof(value) );
|
||||
+}
|
||||
+
|
||||
+static void buffer_append_asn1_length( struct buffer *buffer, DWORD length )
|
||||
+{
|
||||
+ DWORD num_bytes;
|
||||
+
|
||||
+ if (length < 128)
|
||||
+ {
|
||||
+ buffer_append_byte( buffer, length );
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (length <= 0xff) num_bytes = 1;
|
||||
+ else if (length <= 0xffff) num_bytes = 2;
|
||||
+ else if (length <= 0xffffff) num_bytes = 3;
|
||||
+ else num_bytes = 4;
|
||||
+
|
||||
+ buffer_append_byte( buffer, 0x80 | num_bytes );
|
||||
+ while (num_bytes--)
|
||||
+ buffer_append_byte( buffer, length >> (num_bytes * 8) );
|
||||
+}
|
||||
+
|
||||
+static void buffer_append_asn1_integer( struct buffer *buffer, BYTE *data, DWORD len )
|
||||
+{
|
||||
+ DWORD leading_zero = (*data & 0x80) != 0;
|
||||
+
|
||||
+ buffer_append_byte( buffer, 0x02 ); /* tag */
|
||||
+ buffer_append_asn1_length( buffer, len + leading_zero );
|
||||
+ if (leading_zero) buffer_append_byte( buffer, 0 );
|
||||
+ buffer_append( buffer, data, len );
|
||||
+}
|
||||
+
|
||||
+static void buffer_append_asn1_sequence( struct buffer *buffer, struct buffer *content )
|
||||
+{
|
||||
+ if (content->error)
|
||||
+ {
|
||||
+ buffer->error = TRUE;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ buffer_append_byte( buffer, 0x30 ); /* tag */
|
||||
+ buffer_append_asn1_length( buffer, content->pos );
|
||||
+ buffer_append( buffer, content->buffer, content->pos );
|
||||
+}
|
||||
+
|
||||
+static void buffer_append_asn1_r_s( struct buffer *buffer, BYTE *r, DWORD r_len, BYTE *s, DWORD s_len )
|
||||
+{
|
||||
+ struct buffer value;
|
||||
+
|
||||
+ buffer_init( &value );
|
||||
+ buffer_append_asn1_integer( &value, r, r_len );
|
||||
+ buffer_append_asn1_integer( &value, s, s_len );
|
||||
+ buffer_append_asn1_sequence( buffer, &value );
|
||||
+ buffer_free( &value );
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS import_gnutls_pubkey_ecc( struct key *key, gnutls_pubkey_t *gnutls_key )
|
||||
+{
|
||||
+ gnutls_ecc_curve_t curve;
|
||||
+ gnutls_datum_t x, y;
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (key->alg_id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256: curve = GNUTLS_ECC_CURVE_SECP256R1; break;
|
||||
+ case ALG_ID_ECDSA_P384: curve = GNUTLS_ECC_CURVE_SECP384R1; break;
|
||||
+
|
||||
+ default:
|
||||
+ FIXME( "Algorithm %d not yet supported\n", key->alg_id );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
+ if ((ret = pgnutls_pubkey_init( gnutls_key )))
|
||||
+ {
|
||||
+ pgnutls_perror( ret );
|
||||
+ return STATUS_INTERNAL_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ x.data = key->u.a.pubkey;
|
||||
+ x.size = key->u.a.pubkey_len / 2;
|
||||
+ y.data = key->u.a.pubkey + x.size;
|
||||
+ y.size = x.size;
|
||||
+
|
||||
+ if ((ret = pgnutls_pubkey_import_ecc_raw( *gnutls_key, curve, &x, &y )))
|
||||
+ {
|
||||
+ pgnutls_perror( ret );
|
||||
+ pgnutls_pubkey_deinit( *gnutls_key );
|
||||
+ return STATUS_INTERNAL_ERROR;
|
||||
+ }
|
||||
+
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS import_gnutls_pubkey( struct key *key, gnutls_pubkey_t *gnutls_key)
|
||||
+{
|
||||
+ switch (key->alg_id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256:
|
||||
+ case ALG_ID_ECDSA_P384:
|
||||
+ return import_gnutls_pubkey_ecc( key, gnutls_key );
|
||||
+
|
||||
+ default:
|
||||
+ FIXME("Algorithm %d not yet supported\n", key->alg_id);
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS prepare_gnutls_signature_ecc( struct key *key, UCHAR *signature, ULONG signature_len,
|
||||
+ gnutls_datum_t *gnutls_signature )
|
||||
+{
|
||||
+ struct buffer buffer;
|
||||
+ DWORD r_len = signature_len / 2;
|
||||
+ DWORD s_len = r_len;
|
||||
+ BYTE *r = signature;
|
||||
+ BYTE *s = signature + r_len;
|
||||
+
|
||||
+ buffer_init( &buffer );
|
||||
+ buffer_append_asn1_r_s( &buffer, r, r_len, s, s_len );
|
||||
+ if (buffer.error)
|
||||
+ {
|
||||
+ buffer_free( &buffer );
|
||||
+ return STATUS_NO_MEMORY;
|
||||
+ }
|
||||
+
|
||||
+ gnutls_signature->data = buffer.buffer;
|
||||
+ gnutls_signature->size = buffer.pos;
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS prepare_gnutls_signature( struct key *key, UCHAR *signature, ULONG signature_len,
|
||||
+ gnutls_datum_t *gnutls_signature )
|
||||
+{
|
||||
+ switch (key->alg_id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256:
|
||||
+ case ALG_ID_ECDSA_P384:
|
||||
+ return prepare_gnutls_signature_ecc( key, signature, signature_len, gnutls_signature );
|
||||
+
|
||||
+ default:
|
||||
+ FIXME( "Algorithm %d not yet supported\n", key->alg_id );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULONG hash_len,
|
||||
+ UCHAR *signature, ULONG signature_len, DWORD flags )
|
||||
+{
|
||||
+ gnutls_digest_algorithm_t hash_algo;
|
||||
+ gnutls_sign_algorithm_t sign_algo;
|
||||
+ gnutls_datum_t gnutls_hash, gnutls_signature;
|
||||
+ gnutls_pk_algorithm_t pk_algo;
|
||||
+ gnutls_pubkey_t gnutls_key;
|
||||
+ NTSTATUS status;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (flags)
|
||||
+ FIXME( "Flags %08x not supported\n", flags );
|
||||
+
|
||||
+ /* only the hash size must match, not the actual hash function */
|
||||
+ switch (hash_len)
|
||||
+ {
|
||||
+ case 32: hash_algo = GNUTLS_DIG_SHA256; break;
|
||||
+ case 48: hash_algo = GNUTLS_DIG_SHA384; break;
|
||||
+
|
||||
+ default:
|
||||
+ FIXME( "Hash size %u not yet supported\n", hash_len );
|
||||
+ return STATUS_INVALID_SIGNATURE;
|
||||
+ }
|
||||
+
|
||||
+ switch (key->alg_id)
|
||||
+ {
|
||||
+ case ALG_ID_ECDSA_P256:
|
||||
+ case ALG_ID_ECDSA_P384:
|
||||
+ pk_algo = GNUTLS_PK_ECDSA;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ FIXME( "Algorithm %d not yet supported\n", key->alg_id );
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
+ if ((sign_algo = pgnutls_pk_to_sign( pk_algo, hash_algo )) == GNUTLS_SIGN_UNKNOWN)
|
||||
+ {
|
||||
+ FIXME("Gnutls does not support algorithm %d with hash len %u\n", key->alg_id, hash_len);
|
||||
+ return STATUS_NOT_IMPLEMENTED;
|
||||
+ }
|
||||
+
|
||||
+ if ((status = import_gnutls_pubkey( key, &gnutls_key )))
|
||||
+ return status;
|
||||
+
|
||||
+ if ((status = prepare_gnutls_signature( key, signature, signature_len, &gnutls_signature )))
|
||||
+ {
|
||||
+ pgnutls_pubkey_deinit( gnutls_key );
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ gnutls_hash.data = hash;
|
||||
+ gnutls_hash.size = hash_len;
|
||||
+ ret = pgnutls_pubkey_verify_hash2( gnutls_key, sign_algo, 0, &gnutls_hash, &gnutls_signature );
|
||||
+
|
||||
+ HeapFree( GetProcessHeap(), 0, gnutls_signature.data );
|
||||
+ pgnutls_pubkey_deinit( gnutls_key );
|
||||
+ return (ret < 0) ? STATUS_INVALID_SIGNATURE : STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
static NTSTATUS key_destroy( struct key *key )
|
||||
{
|
||||
if (key_is_symmetric(key))
|
||||
@@ -1230,6 +1499,13 @@ static NTSTATUS key_symmetric_get_secret( struct key *key, UCHAR **secret, ULONG
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
+static NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULONG hash_len,
|
||||
+ UCHAR *signature, ULONG signature_len, DWORD flags )
|
||||
+{
|
||||
+ 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" );
|
||||
@@ -1463,13 +1739,14 @@ NTSTATUS WINAPI BCryptVerifySignature( BCRYPT_KEY_HANDLE handle, void *padding,
|
||||
{
|
||||
struct key *key = handle;
|
||||
|
||||
- FIXME( "%p, %p, %p, %u, %p, %u, %08x: stub!\n", handle, padding, hash,
|
||||
+ TRACE( "%p, %p, %p, %u, %p, %u, %08x\n", handle, padding, hash,
|
||||
hash_len, signature, signature_len, flags );
|
||||
|
||||
if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
|
||||
+ if (!hash || !hash_len || !signature || !signature_len) return STATUS_INVALID_PARAMETER;
|
||||
if (!key_is_asymmetric(key)) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
- return STATUS_NOT_IMPLEMENTED;
|
||||
+ return key_asymmetric_verify( key, padding, hash, hash_len, signature, signature_len, flags );
|
||||
}
|
||||
|
||||
NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle )
|
||||
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
|
||||
index 20f70706430..73bd4d69a5b 100644
|
||||
--- a/dlls/bcrypt/tests/bcrypt.c
|
||||
+++ b/dlls/bcrypt/tests/bcrypt.c
|
||||
@@ -1688,10 +1688,10 @@ static void test_ECDSA(void)
|
||||
ok(!status, "BCryptImportKeyPair failed: %08x\n", status);
|
||||
|
||||
status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash) - 1, certSignature, sizeof(certSignature), 0);
|
||||
- todo_wine ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
|
||||
+ ok(status == STATUS_INVALID_SIGNATURE, "Expected STATUS_INVALID_SIGNATURE, got %08x\n", status);
|
||||
|
||||
status = pBCryptVerifySignature(key, NULL, certHash, sizeof(certHash), certSignature, sizeof(certSignature), 0);
|
||||
- todo_wine ok(!status, "BCryptVerifySignature failed: %08x\n", status);
|
||||
+ ok(!status, "BCryptVerifySignature failed: %08x\n", status);
|
||||
|
||||
pBCryptDestroyKey(key);
|
||||
pBCryptCloseAlgorithmProvider(alg, 0);
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,251 @@
|
||||
From 929e67829c47d2fcb99f0aac8ac983f0c3a56836 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Wed, 27 Sep 2017 18:31:07 +0200
|
||||
Subject: crypt32/tests: Basic tests for decoding ECDSA signed certificate.
|
||||
|
||||
---
|
||||
dlls/crypt32/tests/encode.c | 168 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/wincrypt.h | 15 ++++
|
||||
2 files changed, 183 insertions(+)
|
||||
|
||||
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
|
||||
index 8cb384c3395..fa389c41ff1 100644
|
||||
--- a/dlls/crypt32/tests/encode.c
|
||||
+++ b/dlls/crypt32/tests/encode.c
|
||||
@@ -8352,6 +8352,173 @@ static void testPortPublicKeyInfo(void)
|
||||
ok(ret,"CryptAcquireContextA failed\n");
|
||||
}
|
||||
|
||||
+static const BYTE eccCert[] = {
|
||||
+0x30,0x82,0x01,0x46,0x30,0x81,0xec,0x02,0x09,0x00,0xe7,0x6b,
|
||||
+0x26,0x86,0x0a,0x82,0xff,0xe9,0x30,0x0a,0x06,0x08,0x2a,0x86,
|
||||
+0x48,0xce,0x3d,0x04,0x03,0x02,0x30,0x2b,0x31,0x0b,0x30,0x09,
|
||||
+0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x0d,0x30,
|
||||
+0x0b,0x06,0x03,0x55,0x04,0x0a,0x0c,0x04,0x57,0x69,0x6e,0x65,
|
||||
+0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x03,0x0c,0x04,0x57,
|
||||
+0x69,0x6e,0x65,0x30,0x1e,0x17,0x0d,0x31,0x37,0x30,0x39,0x32,
|
||||
+0x37,0x31,0x33,0x34,0x31,0x30,0x34,0x5a,0x17,0x0d,0x32,0x37,
|
||||
+0x30,0x39,0x32,0x35,0x31,0x33,0x34,0x31,0x30,0x34,0x5a,0x30,
|
||||
+0x2b,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
|
||||
+0x44,0x45,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x0a,0x0c,
|
||||
+0x04,0x54,0x65,0x73,0x74,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,
|
||||
+0x04,0x03,0x0c,0x04,0x54,0x65,0x73,0x74,0x30,0x59,0x30,0x13,
|
||||
+0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,
|
||||
+0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xed,
|
||||
+0xfc,0x77,0xd8,0xb9,0xe7,0xf3,0xf8,0xce,0x13,0xb8,0x7f,0x0f,
|
||||
+0x78,0xea,0x73,0x87,0x29,0x10,0xe1,0x6d,0x10,0xce,0x57,0x60,
|
||||
+0x3b,0x3e,0xb4,0x5f,0x0d,0x20,0xc1,0xeb,0x6d,0x74,0xe9,0x7b,
|
||||
+0x11,0x51,0x9a,0x00,0xe8,0xe9,0x12,0x84,0xb9,0x07,0x7e,0x7b,
|
||||
+0x62,0x67,0x12,0x67,0x08,0xe5,0x2e,0x27,0xce,0xa2,0x57,0x15,
|
||||
+0xad,0xc5,0x1f,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,
|
||||
+0x04,0x03,0x02,0x03,0x49,0x00,0x30,0x46,0x02,0x21,0x00,0xd7,
|
||||
+0x29,0xce,0x5a,0xef,0x74,0x85,0xd1,0x18,0x5f,0x6e,0xf1,0xba,
|
||||
+0x53,0xd4,0xcd,0xdd,0xe0,0x5d,0xf1,0x5e,0x48,0x51,0xea,0x63,
|
||||
+0xc0,0xe8,0xe2,0xf6,0xfa,0x4c,0xaf,0x02,0x21,0x00,0xe3,0x94,
|
||||
+0x15,0x3b,0x6c,0x71,0x6e,0x44,0x22,0xcb,0xa0,0x88,0xcd,0x0a,
|
||||
+0x5a,0x50,0x29,0x7c,0x5c,0xd6,0x6c,0xd2,0xe0,0x7f,0xcd,0x02,
|
||||
+0x92,0x21,0x4c,0x2c,0x92,0xee };
|
||||
+static const BYTE ecdsaSig[] = {
|
||||
+0x30,0x46,0x02,0x21,0x00,0xd7,0x29,0xce,0x5a,0xef,0x74,0x85,
|
||||
+0xd1,0x18,0x5f,0x6e,0xf1,0xba,0x53,0xd4,0xcd,0xdd,0xe0,0x5d,
|
||||
+0xf1,0x5e,0x48,0x51,0xea,0x63,0xc0,0xe8,0xe2,0xf6,0xfa,0x4c,
|
||||
+0xaf,0x02,0x21,0x00,0xe3,0x94,0x15,0x3b,0x6c,0x71,0x6e,0x44,
|
||||
+0x22,0xcb,0xa0,0x88,0xcd,0x0a,0x5a,0x50,0x29,0x7c,0x5c,0xd6,
|
||||
+0x6c,0xd2,0xe0,0x7f,0xcd,0x02,0x92,0x21,0x4c,0x2c,0x92,0xee };
|
||||
+static const BYTE eccPubKey[] = {
|
||||
+0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,
|
||||
+0x01,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,
|
||||
+0x42,0x00,0x04,0xed,0xfc,0x77,0xd8,0xb9,0xe7,0xf3,0xf8,0xce,
|
||||
+0x13,0xb8,0x7f,0x0f,0x78,0xea,0x73,0x87,0x29,0x10,0xe1,0x6d,
|
||||
+0x10,0xce,0x57,0x60,0x3b,0x3e,0xb4,0x5f,0x0d,0x20,0xc1,0xeb,
|
||||
+0x6d,0x74,0xe9,0x7b,0x11,0x51,0x9a,0x00,0xe8,0xe9,0x12,0x84,
|
||||
+0xb9,0x07,0x7e,0x7b,0x62,0x67,0x12,0x67,0x08,0xe5,0x2e,0x27,
|
||||
+0xce,0xa2,0x57,0x15,0xad,0xc5,0x1f };
|
||||
+
|
||||
+static void testECDSACert(void)
|
||||
+{
|
||||
+ DWORD decode_flags = CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG;
|
||||
+ CERT_SIGNED_CONTENT_INFO *info;
|
||||
+ CERT_PUBLIC_KEY_INFO *pubkey;
|
||||
+ CERT_ECC_SIGNATURE *ecc_sig;
|
||||
+ LPSTR *ecc_curve;
|
||||
+ DWORD size;
|
||||
+ BOOL ret;
|
||||
+ int i;
|
||||
+
|
||||
+ info = NULL;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, eccCert, sizeof(eccCert), decode_flags,
|
||||
+ NULL, &info, &size);
|
||||
+ ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+
|
||||
+ ok(!strcmp(info->SignatureAlgorithm.pszObjId, szOID_ECDSA_SHA256),
|
||||
+ "Expected 1.2.840.10045.4.3.2, got %s\n", info->SignatureAlgorithm.pszObjId);
|
||||
+ ok(!info->SignatureAlgorithm.Parameters.cbData,
|
||||
+ "Expected no parameter data, got %d bytes\n", info->SignatureAlgorithm.Parameters.cbData);
|
||||
+ ok(!info->SignatureAlgorithm.Parameters.pbData,
|
||||
+ "Expected no parameter data, got %p pointer\n", info->SignatureAlgorithm.Parameters.pbData);
|
||||
+
|
||||
+ ok(info->Signature.cbData == sizeof(ecdsaSig),
|
||||
+ "Expected %d bytes, got %d\n", (int)sizeof(ecdsaSig), info->Signature.cbData);
|
||||
+ ok(info->Signature.pbData != NULL, "Got NULL pointer\n");
|
||||
+ ok(!info->Signature.cUnusedBits, "Expected no unused bytes, got %d\n", info->Signature.cUnusedBits);
|
||||
+ for (i = 0; i < info->Signature.cbData; i++)
|
||||
+ {
|
||||
+ ok(ecdsaSig[i] == info->Signature.pbData[i], "Expected %02x, got %02x at offset %d\n",
|
||||
+ ecdsaSig[i], info->Signature.pbData[i], i);
|
||||
+ }
|
||||
+
|
||||
+ ecc_sig = NULL;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, info->Signature.pbData,
|
||||
+ info->Signature.cbData, decode_flags, NULL, &ecc_sig, &size);
|
||||
+ todo_wine ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ ok(ecc_sig->r.cbData == 32, "Expected 32 bytes, got %d\n", ecc_sig->r.cbData);
|
||||
+ ok(ecc_sig->r.pbData != NULL, "Got NULL pointer\n");
|
||||
+ ok(ecc_sig->s.cbData == 32, "Expected 32 bytes, got %d\n", ecc_sig->s.cbData);
|
||||
+ ok(ecc_sig->s.pbData != NULL, "Got NULL pointer\n");
|
||||
+ for (i = 0; i < ecc_sig->r.cbData; i++)
|
||||
+ {
|
||||
+ ok(ecdsaSig[4+32-i] == ecc_sig->r.pbData[i], "Expected %02x, got %02x at offset %d\n",
|
||||
+ ecdsaSig[4+32-i], ecc_sig->r.pbData[i], i);
|
||||
+ }
|
||||
+ for (i = 0; i < ecc_sig->s.cbData; i++)
|
||||
+ {
|
||||
+ ok(ecdsaSig[4+35+32-i] == ecc_sig->s.pbData[i], "Expected %02x, got %02x at offset %d\n",
|
||||
+ ecdsaSig[4+35+32-i], ecc_sig->s.pbData[i], i);
|
||||
+ }
|
||||
+ LocalFree(ecc_sig);
|
||||
+ }
|
||||
+
|
||||
+ LocalFree(info);
|
||||
+
|
||||
+ info = NULL;
|
||||
+ decode_flags &= ~CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_CERT, eccCert, sizeof(eccCert), decode_flags,
|
||||
+ NULL, &info, &size);
|
||||
+ ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+
|
||||
+ ok(info->Signature.cbData == sizeof(ecdsaSig),
|
||||
+ "Expected %d bytes, got %d\n", (int)sizeof(ecdsaSig), info->Signature.cbData);
|
||||
+ ok(info->Signature.pbData != NULL, "Got NULL pointer\n");
|
||||
+ ok(!info->Signature.cUnusedBits, "Expected no unused bytes, got %d\n", info->Signature.cUnusedBits);
|
||||
+ for (i = 0; i < info->Signature.cbData; i++)
|
||||
+ {
|
||||
+ ok(ecdsaSig[sizeof(ecdsaSig)-i-1] == info->Signature.pbData[i], "Expected %02x, got %02x at offset %d\n",
|
||||
+ ecdsaSig[sizeof(ecdsaSig)-i-1], info->Signature.pbData[i], i);
|
||||
+ }
|
||||
+
|
||||
+ LocalFree(info);
|
||||
+
|
||||
+ pubkey = NULL;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, eccPubKey, sizeof(eccPubKey),
|
||||
+ decode_flags, NULL, &pubkey, &size);
|
||||
+ ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+
|
||||
+ ok(!strcmp(pubkey->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY),
|
||||
+ "Expected 1.2.840.10045.2.1, got %s\n", pubkey->Algorithm.pszObjId);
|
||||
+ ok(pubkey->Algorithm.Parameters.cbData == 10,
|
||||
+ "Expected 10 bytes parameters, got %d bytes\n", pubkey->Algorithm.Parameters.cbData);
|
||||
+ ok(pubkey->Algorithm.Parameters.pbData != NULL,
|
||||
+ "Expected pointer to parameters, got NULL\n");
|
||||
+
|
||||
+ ecc_curve = NULL;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubkey->Algorithm.Parameters.pbData,
|
||||
+ pubkey->Algorithm.Parameters.cbData, decode_flags, NULL, &ecc_curve, &size);
|
||||
+ todo_wine ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
+ "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ ok(!strcmp(*ecc_curve, szOID_ECC_CURVE_P256), "Expected 1.2.840.10045.3.1.7, got %s\n", *ecc_curve);
|
||||
+ LocalFree(ecc_curve);
|
||||
+ }
|
||||
+
|
||||
+ ecc_curve = NULL;
|
||||
+ ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, szOID_ECC_PUBLIC_KEY, pubkey->Algorithm.Parameters.pbData,
|
||||
+ pubkey->Algorithm.Parameters.cbData, decode_flags, NULL, &ecc_curve, &size);
|
||||
+ todo_wine ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
+ "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ ok(!strcmp(*ecc_curve, szOID_ECC_CURVE_P256), "Expected 1.2.840.10045.3.1.7, got %s\n", *ecc_curve);
|
||||
+ LocalFree(ecc_curve);
|
||||
+ }
|
||||
+
|
||||
+ ok(pubkey->PublicKey.cbData == 65, "Expected 32 bytes parameters, got %d bytes\n", pubkey->PublicKey.cbData);
|
||||
+ ok(pubkey->PublicKey.pbData != NULL, "Expected pointer to parameters, got NULL\n");
|
||||
+ for (i = 0; i < pubkey->PublicKey.cbData; i++)
|
||||
+ {
|
||||
+ ok(eccPubKey[26+i] == pubkey->PublicKey.pbData[i], "Expected %02x, got %02x at offset %d\n",
|
||||
+ eccPubKey[26+i], pubkey->PublicKey.pbData[i], i);
|
||||
+ }
|
||||
+
|
||||
+ LocalFree(pubkey);
|
||||
+}
|
||||
+
|
||||
START_TEST(encode)
|
||||
{
|
||||
static const DWORD encodings[] = { X509_ASN_ENCODING, PKCS_7_ASN_ENCODING,
|
||||
@@ -8445,4 +8612,5 @@ START_TEST(encode)
|
||||
test_decodeRsaPrivateKey(encodings[i]);
|
||||
}
|
||||
testPortPublicKeyInfo();
|
||||
+ testECDSACert();
|
||||
}
|
||||
diff --git a/include/wincrypt.h b/include/wincrypt.h
|
||||
index 8b120206cd8..22ff350923a 100644
|
||||
--- a/include/wincrypt.h
|
||||
+++ b/include/wincrypt.h
|
||||
@@ -288,6 +288,11 @@ typedef struct _CERT_KEY_ATTRIBUTES_INFO {
|
||||
PCERT_PRIVATE_KEY_VALIDITY pPrivateKeyUsagePeriod;
|
||||
} CERT_KEY_ATTRIBUTES_INFO, *PCERT_KEY_ATTRIBUTES_INFO;
|
||||
|
||||
+typedef struct _CERT_ECC_SIGNATURE {
|
||||
+ CRYPT_UINT_BLOB r;
|
||||
+ CRYPT_UINT_BLOB s;
|
||||
+} CERT_ECC_SIGNATURE, *PCERT_ECC_SIGNATURE;
|
||||
+
|
||||
/* byte 0 */
|
||||
#define CERT_DIGITAL_SIGNATURE_KEY_USAGE 0x80
|
||||
#define CERT_NON_REPUDIATION_KEY_USAGE 0x40
|
||||
@@ -2878,6 +2883,12 @@ typedef struct _CTL_FIND_SUBJECT_PARA
|
||||
#define szOID_X957 "1.2.840.10040"
|
||||
#define szOID_X957_DSA "1.2.840.10040.4.1"
|
||||
#define szOID_X957_SHA1DSA "1.2.840.10040.4.3"
|
||||
+#define szOID_ECC_PUBLIC_KEY "1.2.840.10045.2.1"
|
||||
+#define szOID_ECC_CURVE_P256 "1.2.840.10045.3.1.7"
|
||||
+#define szOID_ECDSA_SPECIFIED "1.2.840.10045.4.3"
|
||||
+#define szOID_ECDSA_SHA256 "1.2.840.10045.4.3.2"
|
||||
+#define szOID_ECDSA_SHA384 "1.2.840.10045.4.3.3"
|
||||
+#define szOID_ECDSA_SHA512 "1.2.840.10045.4.3.4"
|
||||
#define szOID_DS "2.5"
|
||||
#define szOID_DSALG "2.5.8"
|
||||
#define szOID_DSALG_CRPT "2.5.8.1"
|
||||
@@ -2919,6 +2930,8 @@ typedef struct _CTL_FIND_SUBJECT_PARA
|
||||
#define szOID_OIWDIR_SIGN "1.3.14.7.2.3"
|
||||
#define szOID_OIWDIR_md2 "1.3.14.7.2.2.1"
|
||||
#define szOID_OIWDIR_md2RSA "1.3.14.7.2.3.1"
|
||||
+#define szOID_ECC_CURVE_P384 "1.3.132.0.34"
|
||||
+#define szOID_ECC_CURVE_P521 "1.3.132.0.35"
|
||||
#define szOID_INFOSEC "2.16.840.1.101.2.1"
|
||||
#define szOID_INFOSEC_sdnsSignature "2.16.840.1.101.2.1.1.1"
|
||||
#define szOID_INFOSEC_mosaicSignature "2.16.840.1.101.2.1.1.2"
|
||||
@@ -3224,6 +3237,7 @@ typedef struct _CTL_FIND_SUBJECT_PARA
|
||||
#define X509_PKIX_POLICY_QUALIFIER_USERNOTICE ((LPCSTR)46)
|
||||
#define X509_DH_PUBLICKEY X509_MULTI_BYTE_UINT
|
||||
#define X509_DH_PARAMETERS ((LPCSTR)47)
|
||||
+#define X509_ECC_SIGNATURE ((LPCSTR)47)
|
||||
#define PKCS_ATTRIBUTES ((LPCSTR)48)
|
||||
#define PKCS_SORTED_CTL ((LPCSTR)49)
|
||||
#define X942_DH_PARAMETERS ((LPCSTR)50)
|
||||
@@ -3241,6 +3255,7 @@ typedef struct _CTL_FIND_SUBJECT_PARA
|
||||
#define CMC_ADD_EXTENSIONS ((LPCSTR)62)
|
||||
#define CMC_ADD_ATTRIBUTES ((LPCSTR)63)
|
||||
#define X509_CERTIFICATE_TEMPLATE ((LPCSTR)64)
|
||||
+#define X509_OBJECT_IDENTIFIER ((LPCSTR)73)
|
||||
#define PKCS7_SIGNER_INFO ((LPCSTR)500)
|
||||
#define CMS_SIGNER_INFO ((LPCSTR)501)
|
||||
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,109 @@
|
||||
From e271981b27492ce0612b5c2b7b0c18fd747ce2a7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Wed, 27 Sep 2017 19:08:43 +0200
|
||||
Subject: crypt32: Implement decoding of X509_OBJECT_IDENTIFIER.
|
||||
|
||||
---
|
||||
dlls/crypt32/decode.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/crypt32/tests/encode.c | 8 ++++----
|
||||
2 files changed, 49 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
|
||||
index ddeb0552906..6b124f9db7d 100644
|
||||
--- a/dlls/crypt32/decode.c
|
||||
+++ b/dlls/crypt32/decode.c
|
||||
@@ -5890,6 +5890,46 @@ BOOL CRYPT_AsnDecodePKCSEnvelopedData(const BYTE *pbEncoded, DWORD cbEncoded,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static BOOL WINAPI CRYPT_AsnDecodeObjectIdentifier(DWORD dwCertEncodingType,
|
||||
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
+{
|
||||
+ DWORD bytesNeeded = 0;
|
||||
+ BOOL ret;
|
||||
+
|
||||
+ __TRY
|
||||
+ {
|
||||
+ ret = CRYPT_AsnDecodeOidInternal(pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
|
||||
+ NULL, &bytesNeeded, NULL);
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ if (!pvStructInfo)
|
||||
+ *pcbStructInfo = bytesNeeded;
|
||||
+ else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
|
||||
+ {
|
||||
+ LPSTR *info;
|
||||
+
|
||||
+ if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
|
||||
+ pvStructInfo = *(BYTE **)pvStructInfo;
|
||||
+
|
||||
+ info = pvStructInfo;
|
||||
+ *info = (void *)((BYTE *)info + sizeof(*info));
|
||||
+ ret = CRYPT_AsnDecodeOidInternal(pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
|
||||
+ pvStructInfo, &bytesNeeded, NULL);
|
||||
+ if (!ret && (dwFlags & CRYPT_DECODE_ALLOC_FLAG))
|
||||
+ CRYPT_FreeSpace(pDecodePara, info);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ __EXCEPT_PAGE_FAULT
|
||||
+ {
|
||||
+ SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
+ ret = FALSE;
|
||||
+ }
|
||||
+ __ENDTRY
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType)
|
||||
{
|
||||
@@ -6029,6 +6069,9 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
|
||||
case LOWORD(CMS_SIGNER_INFO):
|
||||
decodeFunc = CRYPT_AsnDecodeCMSSignerInfo;
|
||||
break;
|
||||
+ case LOWORD(X509_OBJECT_IDENTIFIER):
|
||||
+ decodeFunc = CRYPT_AsnDecodeObjectIdentifier;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
|
||||
@@ -6083,6 +6126,8 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
|
||||
decodeFunc = CRYPT_AsnDecodePolicyQualifierUserNotice;
|
||||
else if (!strcmp(lpszStructType, szOID_CTL))
|
||||
decodeFunc = CRYPT_AsnDecodeCTL;
|
||||
+ else if (!strcmp(lpszStructType, szOID_ECC_PUBLIC_KEY))
|
||||
+ decodeFunc = CRYPT_AsnDecodeObjectIdentifier;
|
||||
return decodeFunc;
|
||||
}
|
||||
|
||||
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
|
||||
index fa389c41ff1..574b1e95351 100644
|
||||
--- a/dlls/crypt32/tests/encode.c
|
||||
+++ b/dlls/crypt32/tests/encode.c
|
||||
@@ -8489,8 +8489,8 @@ static void testECDSACert(void)
|
||||
ecc_curve = NULL;
|
||||
ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubkey->Algorithm.Parameters.pbData,
|
||||
pubkey->Algorithm.Parameters.cbData, decode_flags, NULL, &ecc_curve, &size);
|
||||
- todo_wine ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
- "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
+ "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
ok(!strcmp(*ecc_curve, szOID_ECC_CURVE_P256), "Expected 1.2.840.10045.3.1.7, got %s\n", *ecc_curve);
|
||||
@@ -8500,8 +8500,8 @@ static void testECDSACert(void)
|
||||
ecc_curve = NULL;
|
||||
ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, szOID_ECC_PUBLIC_KEY, pubkey->Algorithm.Parameters.pbData,
|
||||
pubkey->Algorithm.Parameters.cbData, decode_flags, NULL, &ecc_curve, &size);
|
||||
- todo_wine ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
- "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ ok(ret || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* < Vista */),
|
||||
+ "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
ok(!strcmp(*ecc_curve, szOID_ECC_CURVE_P256), "Expected 1.2.840.10045.3.1.7, got %s\n", *ecc_curve);
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,76 @@
|
||||
From 4f3a56480857ec2b17c6bb6dd53f40420aebdc3b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Thu, 28 Sep 2017 05:35:49 +0200
|
||||
Subject: crypt32: Implement decoding of X509_ECC_SIGNATURE.
|
||||
|
||||
---
|
||||
dlls/crypt32/decode.c | 32 ++++++++++++++++++++++++++++++++
|
||||
dlls/crypt32/tests/encode.c | 2 +-
|
||||
2 files changed, 33 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c
|
||||
index 6b124f9db7d..02392ec6bf0 100644
|
||||
--- a/dlls/crypt32/decode.c
|
||||
+++ b/dlls/crypt32/decode.c
|
||||
@@ -5930,6 +5930,35 @@ static BOOL WINAPI CRYPT_AsnDecodeObjectIdentifier(DWORD dwCertEncodingType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static BOOL WINAPI CRYPT_AsnDecodeEccSignature(DWORD dwCertEncodingType,
|
||||
+ LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
|
||||
+ PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
|
||||
+{
|
||||
+ BOOL ret;
|
||||
+ struct AsnDecodeSequenceItem items[] = {
|
||||
+ { ASN_INTEGER, offsetof(CERT_ECC_SIGNATURE, r),
|
||||
+ CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_UINT_BLOB), FALSE,
|
||||
+ TRUE, offsetof(CERT_ECC_SIGNATURE, r.pbData), 0 },
|
||||
+ { ASN_INTEGER, offsetof(CERT_ECC_SIGNATURE, s),
|
||||
+ CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_UINT_BLOB), FALSE,
|
||||
+ TRUE, offsetof(CERT_ECC_SIGNATURE, s.pbData), 0 },
|
||||
+ };
|
||||
+
|
||||
+ __TRY
|
||||
+ {
|
||||
+ ret = CRYPT_AsnDecodeSequence(items, sizeof(items) / sizeof(items[0]),
|
||||
+ pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
|
||||
+ pcbStructInfo, NULL, NULL);
|
||||
+ }
|
||||
+ __EXCEPT_PAGE_FAULT
|
||||
+ {
|
||||
+ SetLastError(STATUS_ACCESS_VIOLATION);
|
||||
+ ret = FALSE;
|
||||
+ }
|
||||
+ __ENDTRY
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
|
||||
LPCSTR lpszStructType)
|
||||
{
|
||||
@@ -6072,6 +6101,9 @@ static CryptDecodeObjectExFunc CRYPT_GetBuiltinDecoder(DWORD dwCertEncodingType,
|
||||
case LOWORD(X509_OBJECT_IDENTIFIER):
|
||||
decodeFunc = CRYPT_AsnDecodeObjectIdentifier;
|
||||
break;
|
||||
+ case LOWORD(X509_ECC_SIGNATURE):
|
||||
+ decodeFunc = CRYPT_AsnDecodeEccSignature;
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
|
||||
diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c
|
||||
index 574b1e95351..5ab828151fa 100644
|
||||
--- a/dlls/crypt32/tests/encode.c
|
||||
+++ b/dlls/crypt32/tests/encode.c
|
||||
@@ -8434,7 +8434,7 @@ static void testECDSACert(void)
|
||||
ecc_sig = NULL;
|
||||
ret = pCryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, info->Signature.pbData,
|
||||
info->Signature.cbData, decode_flags, NULL, &ecc_sig, &size);
|
||||
- todo_wine ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
+ ok(ret, "CryptDecodeObjectEx failed with %d\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
ok(ecc_sig->r.cbData == 32, "Expected 32 bytes, got %d\n", ecc_sig->r.cbData);
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,108 @@
|
||||
From 8ad9cbe32ec79dfff404aee19772d684f524e287 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 22:17:15 +0200
|
||||
Subject: crypt32/tests: Add basic test for ecdsa oid.
|
||||
|
||||
---
|
||||
dlls/crypt32/tests/oid.c | 35 +++++++++++++++++++++++++++++++++++
|
||||
include/wincrypt.h | 15 +++++++++++++++
|
||||
2 files changed, 50 insertions(+)
|
||||
|
||||
diff --git a/dlls/crypt32/tests/oid.c b/dlls/crypt32/tests/oid.c
|
||||
index b6614071aba..567658d515d 100644
|
||||
--- a/dlls/crypt32/tests/oid.c
|
||||
+++ b/dlls/crypt32/tests/oid.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winerror.h>
|
||||
+#define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
|
||||
#include <wincrypt.h>
|
||||
#include <winreg.h>
|
||||
|
||||
@@ -541,8 +542,10 @@ static void test_enumOIDInfo(void)
|
||||
|
||||
static void test_findOIDInfo(void)
|
||||
{
|
||||
+ static WCHAR sha256ECDSA[] = { 's','h','a','2','5','6','E','C','D','S','A',0 };
|
||||
static WCHAR sha1[] = { 's','h','a','1',0 };
|
||||
static CHAR oid_rsa_md5[] = szOID_RSA_MD5;
|
||||
+ static CHAR oid_ecda_sha25[] = szOID_ECDSA_SHA256;
|
||||
ALG_ID alg = CALG_SHA1;
|
||||
ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN };
|
||||
PCCRYPT_OID_INFO info;
|
||||
@@ -585,6 +588,38 @@ static void test_findOIDInfo(void)
|
||||
ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n",
|
||||
U(*info).Algid);
|
||||
}
|
||||
+
|
||||
+ info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_ecda_sha25, 0);
|
||||
+ if (info)
|
||||
+ {
|
||||
+ DWORD *data;
|
||||
+
|
||||
+ ok(info->cbSize == sizeof(*info),
|
||||
+ "Expected %d, got %d\n", (int)sizeof(*info), info->cbSize);
|
||||
+ ok(!strcmp(info->pszOID, oid_ecda_sha25),
|
||||
+ "Expected %s, got %s\n", oid_ecda_sha25, info->pszOID);
|
||||
+ ok(!lstrcmpW(info->pwszName, sha256ECDSA),
|
||||
+ "Expected %s, got %s\n", wine_dbgstr_w(sha256ECDSA), wine_dbgstr_w(info->pwszName));
|
||||
+ ok(info->dwGroupId == CRYPT_SIGN_ALG_OID_GROUP_ID,
|
||||
+ "Expected CRYPT_SIGN_ALG_OID_GROUP_ID, got %u\n", info->dwGroupId);
|
||||
+ ok(U(*info).Algid == CALG_OID_INFO_CNG_ONLY,
|
||||
+ "Expected CALG_OID_INFO_CNG_ONLY, got %d\n", U(*info).Algid);
|
||||
+
|
||||
+ data = (DWORD *)info->ExtraInfo.pbData;
|
||||
+ ok(info->ExtraInfo.cbData == 8,
|
||||
+ "Expected 8, got %d\n", info->ExtraInfo.cbData);
|
||||
+ ok(data[0] == CALG_OID_INFO_PARAMETERS,
|
||||
+ "Expected CALG_OID_INFO_PARAMETERS, got %x\n", data[0]);
|
||||
+ ok(data[1] == CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG,
|
||||
+ "Expected CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG, got %x\n", data[1]);
|
||||
+
|
||||
+ ok(!lstrcmpW(info->pwszCNGAlgid, BCRYPT_SHA256_ALGORITHM), "Expected %s, got %s\n",
|
||||
+ wine_dbgstr_w(BCRYPT_SHA256_ALGORITHM), wine_dbgstr_w(info->pwszCNGAlgid));
|
||||
+ ok(!lstrcmpW(info->pwszCNGExtraAlgid, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), "Expected %s, got %s\n",
|
||||
+ wine_dbgstr_w(CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), wine_dbgstr_w(info->pwszCNGExtraAlgid));
|
||||
+ }
|
||||
+ else
|
||||
+ todo_wine win_skip("Host does not support ECDSA_SHA256, skipping test\n");
|
||||
}
|
||||
|
||||
START_TEST(oid)
|
||||
diff --git a/include/wincrypt.h b/include/wincrypt.h
|
||||
index 22ff350923a..d3c3bf07056 100644
|
||||
--- a/include/wincrypt.h
|
||||
+++ b/include/wincrypt.h
|
||||
@@ -1244,6 +1244,17 @@ typedef BOOL (WINAPI *PFN_CRYPT_ENUM_OID_FUNC)(DWORD dwEncodingType,
|
||||
|
||||
#define CRYPT_MATCH_ANY_ENCODING_TYPE 0xffffffff
|
||||
|
||||
+#define CALG_OID_INFO_CNG_ONLY 0xffffffff
|
||||
+#define CALG_OID_INFO_PARAMETERS 0xfffffffe
|
||||
+
|
||||
+#define CRYPT_OID_INFO_HASH_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','H','a','s','h','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+#define CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','E','C','C','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+#define CRYPT_OID_INFO_MGF1_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','M','g','f','1','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+#define CRYPT_OID_INFO_NO_SIGN_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','N','o','S','i','g','n',0}
|
||||
+#define CRYPT_OID_INFO_OAEP_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','O','A','E','P','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+#define CRYPT_OID_INFO_ECC_WRAP_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','E','C','C','W','r','a','p','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+#define CRYPT_OID_INFO_NO_PARAMETERS_ALGORITHM (const WCHAR []){'C','r','y','p','t','O','I','D','I','n','f','o','N','o','P','a','r','a','m','e','t','e','r','s',0}
|
||||
+
|
||||
typedef struct _CRYPT_OID_INFO {
|
||||
DWORD cbSize;
|
||||
LPCSTR pszOID;
|
||||
@@ -1255,6 +1266,10 @@ typedef struct _CRYPT_OID_INFO {
|
||||
DWORD dwLength;
|
||||
} DUMMYUNIONNAME;
|
||||
CRYPT_DATA_BLOB ExtraInfo;
|
||||
+#ifdef CRYPT_OID_INFO_HAS_EXTRA_FIELDS
|
||||
+ LPCWSTR pwszCNGAlgid;
|
||||
+ LPCWSTR pwszCNGExtraAlgid;
|
||||
+#endif
|
||||
} CRYPT_OID_INFO, *PCRYPT_OID_INFO;
|
||||
typedef const CRYPT_OID_INFO CCRYPT_OID_INFO, *PCCRYPT_OID_INFO;
|
||||
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,102 @@
|
||||
From 46195d1c3633ba489f99a896012283b467df7fc2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Fri, 29 Sep 2017 22:42:56 +0200
|
||||
Subject: crypt32: Add oids for sha256ECDSA and sha384ECDSA.
|
||||
|
||||
---
|
||||
dlls/crypt32/oid.c | 17 +++++++++++++++++
|
||||
dlls/crypt32/tests/oid.c | 2 +-
|
||||
2 files changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/crypt32/oid.c b/dlls/crypt32/oid.c
|
||||
index 7c07b9fcd99..b34c5980d65 100644
|
||||
--- a/dlls/crypt32/oid.c
|
||||
+++ b/dlls/crypt32/oid.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#define NONAMELESSUNION
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
+#define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
|
||||
#include "wincrypt.h"
|
||||
#include "winreg.h"
|
||||
#include "winuser.h"
|
||||
@@ -1080,6 +1081,8 @@ static const WCHAR sha384RSA[] = { 's','h','a','3','8','4','R','S','A',0 };
|
||||
static const WCHAR sha512RSA[] = { 's','h','a','5','1','2','R','S','A',0 };
|
||||
static const WCHAR mosaicUpdatedSig[] =
|
||||
{ 'm','o','s','a','i','c','U','p','d','a','t','e','d','S','i','g',0 };
|
||||
+static const WCHAR sha256ECDSA[] = { 's','h','a','2','5','6','E','C','D','S','A',0 };
|
||||
+static const WCHAR sha384ECDSA[] = { 's','h','a','3','8','4','E','C','D','S','A',0 };
|
||||
static const WCHAR CN[] = { 'C','N',0 };
|
||||
static const WCHAR L[] = { 'L',0 };
|
||||
static const WCHAR O[] = { 'O',0 };
|
||||
@@ -1126,12 +1129,16 @@ static const DWORD dssSign[2] = { CALG_DSS_SIGN,
|
||||
static const DWORD mosaicSign[2] = { CALG_DSS_SIGN,
|
||||
CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG |
|
||||
CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG };
|
||||
+static const DWORD ecdsaSign[2] = { CALG_OID_INFO_PARAMETERS,
|
||||
+ CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG };
|
||||
static const CRYPT_DATA_BLOB rsaSignBlob = { sizeof(rsaSign),
|
||||
(LPBYTE)&rsaSign };
|
||||
static const CRYPT_DATA_BLOB dssSignBlob = { sizeof(dssSign),
|
||||
(LPBYTE)dssSign };
|
||||
static const CRYPT_DATA_BLOB mosaicSignBlob = { sizeof(mosaicSign),
|
||||
(LPBYTE)mosaicSign };
|
||||
+static const CRYPT_DATA_BLOB ecdsaSignBlob = { sizeof(ecdsaSign),
|
||||
+ (LPBYTE)ecdsaSign };
|
||||
|
||||
static const DWORD ia5String[] = { CERT_RDN_IA5_STRING, 0 };
|
||||
static const DWORD numericString[] = { CERT_RDN_NUMERIC_STRING, 0 };
|
||||
@@ -1153,6 +1160,8 @@ static const struct OIDInfoConstructor {
|
||||
UINT Algid;
|
||||
LPCWSTR pwszName;
|
||||
const CRYPT_DATA_BLOB *blob;
|
||||
+ LPCWSTR pwszCNGAlgid;
|
||||
+ LPCWSTR pwszCNGExtraAlgid;
|
||||
} oidInfoConstructors[] = {
|
||||
{ 1, szOID_OIWSEC_sha1, CALG_SHA1, sha1, NULL },
|
||||
{ 1, szOID_OIWSEC_sha1, CALG_SHA1, sha, NULL },
|
||||
@@ -1207,6 +1216,10 @@ static const struct OIDInfoConstructor {
|
||||
{ 4, szOID_OIWSEC_dsaSHA1, CALG_SHA1, dsaSHA1, &dssSignBlob },
|
||||
{ 4, szOID_INFOSEC_mosaicUpdatedSig, CALG_SHA1, mosaicUpdatedSig,
|
||||
&mosaicSignBlob },
|
||||
+ { 4, szOID_ECDSA_SHA256, CALG_OID_INFO_CNG_ONLY, sha256ECDSA, &ecdsaSignBlob,
|
||||
+ BCRYPT_SHA256_ALGORITHM, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM },
|
||||
+ { 4, szOID_ECDSA_SHA384, CALG_OID_INFO_CNG_ONLY, sha384ECDSA, &ecdsaSignBlob,
|
||||
+ BCRYPT_SHA384_ALGORITHM, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM },
|
||||
|
||||
{ 5, szOID_COMMON_NAME, 0, CN, NULL },
|
||||
{ 5, szOID_LOCALITY_NAME, 0, L, NULL },
|
||||
@@ -1422,6 +1435,8 @@ static void init_oid_info(void)
|
||||
info->info.ExtraInfo.pbData =
|
||||
oidInfoConstructors[i].blob->pbData;
|
||||
}
|
||||
+ info->info.pwszCNGAlgid = oidInfoConstructors[i].pwszCNGAlgid;
|
||||
+ info->info.pwszCNGExtraAlgid = oidInfoConstructors[i].pwszCNGExtraAlgid;
|
||||
list_add_tail(&oidInfo, &info->entry);
|
||||
}
|
||||
}
|
||||
@@ -1454,6 +1469,8 @@ static void init_oid_info(void)
|
||||
info->info.ExtraInfo.pbData =
|
||||
oidInfoConstructors[i].blob->pbData;
|
||||
}
|
||||
+ info->info.pwszCNGAlgid = oidInfoConstructors[i].pwszCNGAlgid;
|
||||
+ info->info.pwszCNGExtraAlgid = oidInfoConstructors[i].pwszCNGExtraAlgid;
|
||||
list_add_tail(&oidInfo, &info->entry);
|
||||
}
|
||||
}
|
||||
diff --git a/dlls/crypt32/tests/oid.c b/dlls/crypt32/tests/oid.c
|
||||
index 567658d515d..fa885efb742 100644
|
||||
--- a/dlls/crypt32/tests/oid.c
|
||||
+++ b/dlls/crypt32/tests/oid.c
|
||||
@@ -619,7 +619,7 @@ static void test_findOIDInfo(void)
|
||||
wine_dbgstr_w(CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), wine_dbgstr_w(info->pwszCNGExtraAlgid));
|
||||
}
|
||||
else
|
||||
- todo_wine win_skip("Host does not support ECDSA_SHA256, skipping test\n");
|
||||
+ win_skip("Host does not support ECDSA_SHA256, skipping test\n");
|
||||
}
|
||||
|
||||
START_TEST(oid)
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,146 @@
|
||||
From ad4623778a56ea3278bb9c81a951af14575b9ac0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 30 Sep 2017 03:02:15 +0200
|
||||
Subject: crypt32: Correctly return how the issuer of a self signed certificate
|
||||
was checked.
|
||||
|
||||
---
|
||||
dlls/crypt32/cert.c | 2 +-
|
||||
dlls/crypt32/chain.c | 20 ++++++++++++++------
|
||||
dlls/crypt32/crypt32_private.h | 2 +-
|
||||
3 files changed, 16 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
|
||||
index a4b43ff1555..0cfa46788f3 100644
|
||||
--- a/dlls/crypt32/cert.c
|
||||
+++ b/dlls/crypt32/cert.c
|
||||
@@ -1884,7 +1884,7 @@ PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
|
||||
CertFreeCertificateContext(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
- if (CRYPT_IsCertificateSelfSigned(pSubjectContext))
|
||||
+ if (CRYPT_IsCertificateSelfSigned(pSubjectContext, NULL))
|
||||
{
|
||||
CertFreeCertificateContext(ret);
|
||||
ret = NULL;
|
||||
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
|
||||
index 80b6513ab1e..89a8ddb95f4 100644
|
||||
--- a/dlls/crypt32/chain.c
|
||||
+++ b/dlls/crypt32/chain.c
|
||||
@@ -265,7 +265,7 @@ typedef struct _CertificateChain
|
||||
LONG ref;
|
||||
} CertificateChain;
|
||||
|
||||
-BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
+BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert, DWORD *type)
|
||||
{
|
||||
PCERT_EXTENSION ext;
|
||||
DWORD size;
|
||||
@@ -300,6 +300,7 @@ BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
&directoryName->u.DirectoryName, &cert->pCertInfo->Issuer)
|
||||
&& CertCompareIntegerBlob(&info->AuthorityCertSerialNumber,
|
||||
&cert->pCertInfo->SerialNumber);
|
||||
+ if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -321,6 +322,7 @@ BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
|
||||
ret = !memcmp(buf, info->KeyId.pbData, size);
|
||||
CryptMemFree(buf);
|
||||
+ if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
@@ -348,6 +350,7 @@ BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
&info->CertIssuer, &cert->pCertInfo->Issuer) &&
|
||||
CertCompareIntegerBlob(&info->CertSerialNumber,
|
||||
&cert->pCertInfo->SerialNumber);
|
||||
+ if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
||||
}
|
||||
else if (info->KeyId.cbData)
|
||||
{
|
||||
@@ -363,6 +366,7 @@ BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
|
||||
ret = !memcmp(buf, info->KeyId.pbData, size);
|
||||
CryptMemFree(buf);
|
||||
+ if (type) *type = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
|
||||
}
|
||||
else
|
||||
ret = FALSE;
|
||||
@@ -376,8 +380,11 @@ BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert)
|
||||
}
|
||||
}
|
||||
else
|
||||
+ {
|
||||
ret = CertCompareCertificateName(cert->dwCertEncodingType,
|
||||
&cert->pCertInfo->Subject, &cert->pCertInfo->Issuer);
|
||||
+ if (type) *type = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
||||
+ }
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1320,7 +1327,7 @@ static void CRYPT_CheckChainNameConstraints(PCERT_SIMPLE_CHAIN chain)
|
||||
* constraints checked unless they're the end cert.
|
||||
*/
|
||||
if (j == 0 || !CRYPT_IsCertificateSelfSigned(
|
||||
- chain->rgpElement[j]->pCertContext))
|
||||
+ chain->rgpElement[j]->pCertContext, NULL))
|
||||
{
|
||||
CRYPT_CheckNameConstraints(nameConstraints,
|
||||
chain->rgpElement[j]->pCertContext->pCertInfo,
|
||||
@@ -1893,6 +1900,7 @@ static void CRYPT_CheckSimpleChain(CertificateChainEngine *engine,
|
||||
int i;
|
||||
BOOL pathLengthConstraintViolated = FALSE;
|
||||
CERT_BASIC_CONSTRAINTS2_INFO constraints = { FALSE, FALSE, 0 };
|
||||
+ DWORD type;
|
||||
|
||||
TRACE_(chain)("checking chain with %d elements for time %s\n",
|
||||
chain->cElement, filetime_to_str(time));
|
||||
@@ -1904,7 +1912,7 @@ static void CRYPT_CheckSimpleChain(CertificateChainEngine *engine,
|
||||
dump_element(chain->rgpElement[i]->pCertContext);
|
||||
if (i == chain->cElement - 1)
|
||||
isRoot = CRYPT_IsCertificateSelfSigned(
|
||||
- chain->rgpElement[i]->pCertContext);
|
||||
+ chain->rgpElement[i]->pCertContext, NULL);
|
||||
else
|
||||
isRoot = FALSE;
|
||||
if (!CRYPT_IsCertVersionValid(chain->rgpElement[i]->pCertContext))
|
||||
@@ -1980,10 +1988,10 @@ static void CRYPT_CheckSimpleChain(CertificateChainEngine *engine,
|
||||
}
|
||||
CRYPT_CheckChainNameConstraints(chain);
|
||||
CRYPT_CheckChainPolicies(chain);
|
||||
- if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext))
|
||||
+ if (CRYPT_IsCertificateSelfSigned(rootElement->pCertContext, &type))
|
||||
{
|
||||
rootElement->TrustStatus.dwInfoStatus |=
|
||||
- CERT_TRUST_IS_SELF_SIGNED | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
|
||||
+ CERT_TRUST_IS_SELF_SIGNED | type;
|
||||
CRYPT_CheckRootCert(engine->hRoot, rootElement);
|
||||
}
|
||||
CRYPT_CombineTrustStatus(&chain->TrustStatus, &rootElement->TrustStatus);
|
||||
@@ -2195,7 +2203,7 @@ static BOOL CRYPT_BuildSimpleChain(const CertificateChainEngine *engine,
|
||||
PCCERT_CONTEXT cert = chain->rgpElement[chain->cElement - 1]->pCertContext;
|
||||
|
||||
while (ret && !CRYPT_IsSimpleChainCyclic(chain) &&
|
||||
- !CRYPT_IsCertificateSelfSigned(cert))
|
||||
+ !CRYPT_IsCertificateSelfSigned(cert, NULL))
|
||||
{
|
||||
PCCERT_CONTEXT issuer = CRYPT_GetIssuer(engine, world, cert, NULL, flags,
|
||||
&chain->rgpElement[chain->cElement - 1]->TrustStatus.dwInfoStatus);
|
||||
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
|
||||
index 8b1b003a120..5c08369f007 100644
|
||||
--- a/dlls/crypt32/crypt32_private.h
|
||||
+++ b/dlls/crypt32/crypt32_private.h
|
||||
@@ -341,7 +341,7 @@ void CRYPT_ImportSystemRootCertsToReg(void) DECLSPEC_HIDDEN;
|
||||
BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *contextInterface,
|
||||
HCERTSTORE memStore) DECLSPEC_HIDDEN;
|
||||
|
||||
-BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert) DECLSPEC_HIDDEN;
|
||||
+BOOL CRYPT_IsCertificateSelfSigned(PCCERT_CONTEXT cert, DWORD *type) DECLSPEC_HIDDEN;
|
||||
|
||||
/* Allocates and initializes a certificate chain engine, but without creating
|
||||
* the root store. Instead, it uses root, and assumes the caller has done any
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,128 @@
|
||||
From a1989f6e804cd11efe4da438939b481ef430cd4c Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 30 Sep 2017 03:08:58 +0200
|
||||
Subject: crypt32/tets: Add test for verifying an ecdsa chain.
|
||||
|
||||
---
|
||||
dlls/crypt32/tests/chain.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 84 insertions(+)
|
||||
|
||||
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
|
||||
index 0839fc73976..1279735e496 100644
|
||||
--- a/dlls/crypt32/tests/chain.c
|
||||
+++ b/dlls/crypt32/tests/chain.c
|
||||
@@ -2889,6 +2889,59 @@ static const BYTE chain31_1[] = {
|
||||
0x43,0x08,0xe5,0x78,0x2b,0x95,0xf3,0x75,0xb6,0x88,0xf0,0x6b,0x5c,0x5b,0x50,
|
||||
0x04,0x91,0x3b,0x89,0x5a,0x60,0x1f,0xfc,0x36,0x53,0x32,0x36,0x0a,0x4d,0x03,
|
||||
0x2c,0xd7 };
|
||||
+static const BYTE ecc_crt[] = {
|
||||
+0x30,0x82,0x01,0x46,0x30,0x81,0xec,0x02,0x09,0x00,0xe7,0x6b,0x26,0x86,0x0a,
|
||||
+0x82,0xff,0xe9,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,
|
||||
+0x30,0x2b,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,
|
||||
+0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x0a,0x0c,0x04,0x57,0x69,0x6e,0x65,
|
||||
+0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x03,0x0c,0x04,0x57,0x69,0x6e,0x65,
|
||||
+0x30,0x1e,0x17,0x0d,0x31,0x37,0x30,0x39,0x32,0x37,0x31,0x33,0x34,0x31,0x30,
|
||||
+0x34,0x5a,0x17,0x0d,0x32,0x37,0x30,0x39,0x32,0x35,0x31,0x33,0x34,0x31,0x30,
|
||||
+0x34,0x5a,0x30,0x2b,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
|
||||
+0x44,0x45,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x0a,0x0c,0x04,0x54,0x65,
|
||||
+0x73,0x74,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x03,0x0c,0x04,0x54,0x65,
|
||||
+0x73,0x74,0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,
|
||||
+0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xed,
|
||||
+0xfc,0x77,0xd8,0xb9,0xe7,0xf3,0xf8,0xce,0x13,0xb8,0x7f,0x0f,0x78,0xea,0x73,
|
||||
+0x87,0x29,0x10,0xe1,0x6d,0x10,0xce,0x57,0x60,0x3b,0x3e,0xb4,0x5f,0x0d,0x20,
|
||||
+0xc1,0xeb,0x6d,0x74,0xe9,0x7b,0x11,0x51,0x9a,0x00,0xe8,0xe9,0x12,0x84,0xb9,
|
||||
+0x07,0x7e,0x7b,0x62,0x67,0x12,0x67,0x08,0xe5,0x2e,0x27,0xce,0xa2,0x57,0x15,
|
||||
+0xad,0xc5,0x1f,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,
|
||||
+0x03,0x49,0x00,0x30,0x46,0x02,0x21,0x00,0xd7,0x29,0xce,0x5a,0xef,0x74,0x85,
|
||||
+0xd1,0x18,0x5f,0x6e,0xf1,0xba,0x53,0xd4,0xcd,0xdd,0xe0,0x5d,0xf1,0x5e,0x48,
|
||||
+0x51,0xea,0x63,0xc0,0xe8,0xe2,0xf6,0xfa,0x4c,0xaf,0x02,0x21,0x00,0xe3,0x94,
|
||||
+0x15,0x3b,0x6c,0x71,0x6e,0x44,0x22,0xcb,0xa0,0x88,0xcd,0x0a,0x5a,0x50,0x29,
|
||||
+0x7c,0x5c,0xd6,0x6c,0xd2,0xe0,0x7f,0xcd,0x02,0x92,0x21,0x4c,0x2c,0x92,0xee };
|
||||
+static const BYTE ecc_ca[] = {
|
||||
+0x30,0x82,0x01,0x9f,0x30,0x82,0x01,0x46,0xa0,0x03,0x02,0x01,0x02,0x02,0x09,
|
||||
+0x00,0xf1,0x54,0xae,0x21,0x2e,0x4d,0x31,0x9f,0x30,0x0a,0x06,0x08,0x2a,0x86,
|
||||
+0x48,0xce,0x3d,0x04,0x03,0x02,0x30,0x2b,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,
|
||||
+0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x0a,
|
||||
+0x0c,0x04,0x57,0x69,0x6e,0x65,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,0x04,0x03,
|
||||
+0x0c,0x04,0x57,0x69,0x6e,0x65,0x30,0x1e,0x17,0x0d,0x31,0x37,0x30,0x39,0x32,
|
||||
+0x37,0x31,0x33,0x33,0x39,0x31,0x35,0x5a,0x17,0x0d,0x32,0x37,0x30,0x39,0x32,
|
||||
+0x35,0x31,0x33,0x33,0x39,0x31,0x35,0x5a,0x30,0x2b,0x31,0x0b,0x30,0x09,0x06,
|
||||
+0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,
|
||||
+0x04,0x0a,0x0c,0x04,0x57,0x69,0x6e,0x65,0x31,0x0d,0x30,0x0b,0x06,0x03,0x55,
|
||||
+0x04,0x03,0x0c,0x04,0x57,0x69,0x6e,0x65,0x30,0x59,0x30,0x13,0x06,0x07,0x2a,
|
||||
+0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,
|
||||
+0x07,0x03,0x42,0x00,0x04,0x3b,0x3c,0x34,0xc8,0x3f,0x15,0xea,0x02,0x68,0x46,
|
||||
+0x69,0xdf,0x0c,0xa6,0xee,0x7a,0xd9,0x82,0x08,0x9b,0x37,0x53,0x42,0xf3,0x13,
|
||||
+0x63,0xda,0x65,0x79,0xe8,0x04,0x9e,0x8c,0x77,0xc4,0x33,0x77,0xd9,0x5a,0x7f,
|
||||
+0x60,0x7b,0x98,0xce,0xf3,0x96,0x56,0xd6,0xb5,0x8d,0x87,0x7a,0x00,0x2b,0xf3,
|
||||
+0x70,0xb3,0x90,0x73,0xa0,0x56,0x06,0x3b,0x22,0xa3,0x53,0x30,0x51,0x30,0x1d,
|
||||
+0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0x26,0xef,0x6f,0xe4,0xb5,0x24,
|
||||
+0x2f,0x68,0x49,0x84,0xd9,0x89,0xa6,0xab,0x0c,0xf8,0x6d,0xf5,0xe5,0x0c,0x30,
|
||||
+0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x26,0xef,0x6f,
|
||||
+0xe4,0xb5,0x24,0x2f,0x68,0x49,0x84,0xd9,0x89,0xa6,0xab,0x0c,0xf8,0x6d,0xf5,
|
||||
+0xe5,0x0c,0x30,0x0f,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,
|
||||
+0x03,0x01,0x01,0xff,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,
|
||||
+0x02,0x03,0x47,0x00,0x30,0x44,0x02,0x20,0x2b,0x6b,0x23,0x42,0x32,0xf2,0xcb,
|
||||
+0x71,0xd7,0x5c,0xfa,0x5e,0x6c,0x19,0x31,0xd6,0x74,0xf7,0xc0,0xf8,0xc6,0x39,
|
||||
+0x38,0xe9,0x79,0x4d,0x84,0x44,0x40,0x13,0x8e,0x43,0x02,0x20,0x34,0xc7,0x61,
|
||||
+0xbb,0x18,0x1c,0x85,0x34,0xe3,0x4c,0x30,0x28,0x42,0x0e,0x06,0x65,0x68,0x1d,
|
||||
+0x76,0x53,0x24,0xa0,0x27,0xa5,0x84,0x3b,0x2d,0xf3,0xec,0x27,0x60,0xb2 };
|
||||
+
|
||||
|
||||
typedef struct _CONST_DATA_BLOB
|
||||
{
|
||||
@@ -3086,6 +3139,8 @@ static SYSTEMTIME jun2013 = { 2013, 6, 5, 6, 0, 0, 0, 0 };
|
||||
static SYSTEMTIME oct2016 = { 2016, 10, 6, 1, 0, 0, 0, 0 };
|
||||
/* Wednesday, Nov 17, 2016 */
|
||||
static SYSTEMTIME nov2016 = { 2016, 11, 3, 17, 0, 0, 0, 0 };
|
||||
+/* Wednesday, Nov 17, 2017 */
|
||||
+static SYSTEMTIME nov2017 = { 2017, 11, 3, 17, 0, 0, 0, 0 };
|
||||
|
||||
typedef struct _ChainCheck
|
||||
{
|
||||
@@ -3873,6 +3928,25 @@ static ChainCheck chainCheckEmbeddedNullBroken = {
|
||||
CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS },
|
||||
1, simpleStatus27Broken },
|
||||
0 };
|
||||
+static CONST_DATA_BLOB chainECDSA[] = {
|
||||
+ { sizeof(ecc_ca), ecc_ca },
|
||||
+ { sizeof(ecc_crt), ecc_crt },
|
||||
+};
|
||||
+static const CERT_TRUST_STATUS elementStatusECDSA[] = {
|
||||
+ { CERT_TRUST_NO_ERROR, CERT_TRUST_HAS_NAME_MATCH_ISSUER },
|
||||
+ { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_KEY_MATCH_ISSUER | CERT_TRUST_IS_SELF_SIGNED },
|
||||
+};
|
||||
+static const SimpleChainStatusCheck simpleStatusECDSA[] = {
|
||||
+ { sizeof(elementStatusECDSA) / sizeof(elementStatusECDSA[0]), elementStatusECDSA },
|
||||
+};
|
||||
+static ChainCheck chainCheckECDSA = {
|
||||
+ { sizeof(chainECDSA) / sizeof(chainECDSA[0]), chainECDSA },
|
||||
+ {
|
||||
+ { CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER },
|
||||
+ { CERT_TRUST_IS_UNTRUSTED_ROOT, 0 },
|
||||
+ 1, simpleStatusECDSA
|
||||
+ }, TODO_ERROR
|
||||
+};
|
||||
|
||||
#define test_name_blob(a,b) _test_name_blob(__LINE__,a,b)
|
||||
static void _test_name_blob(unsigned line, CERT_NAME_BLOB *blob, const char *exdata)
|
||||
@@ -4148,6 +4222,16 @@ static void testGetCertChain(void)
|
||||
|
||||
pCertFreeCertificateChain(chain);
|
||||
|
||||
+ /* Test with ECDSA certificate */
|
||||
+ chain = getChain(NULL, &chainCheckECDSA.certs, 0, TRUE, &nov2017, FALSE, 0);
|
||||
+ if (chain)
|
||||
+ {
|
||||
+ todo_wine ok(chain->TrustStatus.dwErrorStatus == CERT_TRUST_IS_UNTRUSTED_ROOT,
|
||||
+ "unexpected chain error status %08x\n", chain->TrustStatus.dwErrorStatus);
|
||||
+ checkChainStatus(chain, &chainCheckECDSA.status, chainCheckECDSA.todo, "chainCheckECDSA", 0);
|
||||
+ pCertFreeCertificateChain(chain);
|
||||
+ }
|
||||
+
|
||||
/* Test HCCE_LOCAL_MACHINE */
|
||||
ret = CertGetCertificateChain(HCCE_LOCAL_MACHINE, cert, &fileTime, store, ¶, 0, NULL, &chain);
|
||||
ok(ret, "CertGetCertificateChain failed: %u\n", GetLastError());
|
||||
--
|
||||
2.14.1
|
||||
|
@ -0,0 +1,384 @@
|
||||
From 2da87110b4a7637cada56e5e188f2d6ccafc97e4 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
||||
Date: Sat, 30 Sep 2017 03:10:08 +0200
|
||||
Subject: crypt32: Implement verification of ECDSA signatures.
|
||||
|
||||
---
|
||||
dlls/crypt32/Makefile.in | 2 +-
|
||||
dlls/crypt32/cert.c | 292 ++++++++++++++++++++++++++++++++++++++++++---
|
||||
dlls/crypt32/tests/chain.c | 4 +-
|
||||
3 files changed, 280 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in
|
||||
index d3a409fcae6..09342221192 100644
|
||||
--- a/dlls/crypt32/Makefile.in
|
||||
+++ b/dlls/crypt32/Makefile.in
|
||||
@@ -1,7 +1,7 @@
|
||||
EXTRADEFS = -D_CRYPT32_
|
||||
MODULE = crypt32.dll
|
||||
IMPORTLIB = crypt32
|
||||
-IMPORTS = user32 advapi32
|
||||
+IMPORTS = user32 advapi32 bcrypt
|
||||
DELAYIMPORTS = cryptnet
|
||||
EXTRALIBS = $(SECURITY_LIBS)
|
||||
|
||||
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
|
||||
index 0cfa46788f3..d2aa182ff6e 100644
|
||||
--- a/dlls/crypt32/cert.c
|
||||
+++ b/dlls/crypt32/cert.c
|
||||
@@ -21,9 +21,14 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
+#include "ntstatus.h"
|
||||
+#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
+#include "winternl.h"
|
||||
+#define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
|
||||
#include "wincrypt.h"
|
||||
+#include "bcrypt.h"
|
||||
#include "winnls.h"
|
||||
#include "rpc.h"
|
||||
#include "wine/debug.h"
|
||||
@@ -2409,36 +2414,29 @@ BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
|
||||
CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
|
||||
}
|
||||
|
||||
-static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
|
||||
- DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
|
||||
- const CERT_SIGNED_CONTENT_INFO *signedCert)
|
||||
+static BOOL verify_signature_crypt(HCRYPTPROV_LEGACY hCryptProv,
|
||||
+ DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
|
||||
+ const CERT_SIGNED_CONTENT_INFO *signedCert, PCCRYPT_OID_INFO info)
|
||||
{
|
||||
- BOOL ret;
|
||||
- HCRYPTKEY key;
|
||||
- PCCRYPT_OID_INFO info;
|
||||
ALG_ID pubKeyID, hashID;
|
||||
+ HCRYPTHASH hash;
|
||||
+ HCRYPTKEY key;
|
||||
+ BOOL ret;
|
||||
|
||||
- info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
|
||||
- signedCert->SignatureAlgorithm.pszObjId, 0);
|
||||
- if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
|
||||
- {
|
||||
- SetLastError(NTE_BAD_ALGID);
|
||||
- return FALSE;
|
||||
- }
|
||||
hashID = info->u.Algid;
|
||||
if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
|
||||
pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
|
||||
else
|
||||
pubKeyID = hashID;
|
||||
+
|
||||
/* Load the default provider if necessary */
|
||||
if (!hCryptProv)
|
||||
hCryptProv = CRYPT_GetDefaultProvider();
|
||||
+
|
||||
ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
|
||||
pubKeyInfo, pubKeyID, 0, NULL, &key);
|
||||
if (ret)
|
||||
{
|
||||
- HCRYPTHASH hash;
|
||||
-
|
||||
ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
|
||||
if (ret)
|
||||
{
|
||||
@@ -2454,6 +2452,270 @@ static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptP
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static BOOL calculate_hash_bcrypt(const WCHAR *algorithm,
|
||||
+ const CERT_SIGNED_CONTENT_INFO *signedCert, BYTE **hash_value, DWORD *hash_len)
|
||||
+{
|
||||
+ BCRYPT_HASH_HANDLE hash = NULL;
|
||||
+ BCRYPT_ALG_HANDLE alg = NULL;
|
||||
+ NTSTATUS status;
|
||||
+ DWORD size;
|
||||
+ BOOL ret = FALSE;
|
||||
+
|
||||
+ if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
|
||||
+ goto done;
|
||||
+
|
||||
+ if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
|
||||
+ goto done;
|
||||
+
|
||||
+ if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
|
||||
+ goto done;
|
||||
+
|
||||
+ if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
|
||||
+ goto done;
|
||||
+
|
||||
+ if (!(*hash_value = CryptMemAlloc(*hash_len)))
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
|
||||
+ {
|
||||
+ CryptMemFree(*hash_value);
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ ret = TRUE;
|
||||
+
|
||||
+done:
|
||||
+ if (hash) BCryptDestroyHash(hash);
|
||||
+ if (alg) BCryptCloseAlgorithmProvider(alg, 0);
|
||||
+ if (status) SetLastError(RtlNtStatusToDosError(status));
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static BOOL import_bcrypt_pubkey_ecc(PCERT_PUBLIC_KEY_INFO pubKeyInfo, BCRYPT_KEY_HANDLE *key)
|
||||
+{
|
||||
+ DWORD blob_magic, ecckey_len, size;
|
||||
+ NTSTATUS status = STATUS_SUCCESS;
|
||||
+ BCRYPT_ECCKEY_BLOB *ecckey;
|
||||
+ const WCHAR *sign_algo;
|
||||
+ BCRYPT_ALG_HANDLE alg;
|
||||
+ LPSTR *ecc_curve;
|
||||
+
|
||||
+ if (!pubKeyInfo->PublicKey.cbData)
|
||||
+ {
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
|
||||
+ {
|
||||
+ FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER,
|
||||
+ pubKeyInfo->Algorithm.Parameters.pbData,
|
||||
+ pubKeyInfo->Algorithm.Parameters.cbData,
|
||||
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
|
||||
+ {
|
||||
+ sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
|
||||
+ blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
|
||||
+ }
|
||||
+ else if(!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
|
||||
+ {
|
||||
+ sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
|
||||
+ blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
|
||||
+ sign_algo = NULL;
|
||||
+ blob_magic = 0;
|
||||
+ }
|
||||
+ LocalFree(ecc_curve);
|
||||
+
|
||||
+ if (!sign_algo)
|
||||
+ {
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
|
||||
+ {
|
||||
+ SetLastError(RtlNtStatusToDosError(status));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
|
||||
+ if (!(ecckey = CryptMemAlloc(ecckey_len)))
|
||||
+ {
|
||||
+ BCryptCloseAlgorithmProvider(alg, 0);
|
||||
+ SetLastError(ERROR_OUTOFMEMORY);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ecckey->dwMagic = blob_magic;
|
||||
+ ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2;
|
||||
+ memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1);
|
||||
+
|
||||
+ status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
|
||||
+ BCryptCloseAlgorithmProvider(alg, 0);
|
||||
+ if (status)
|
||||
+ {
|
||||
+ SetLastError(RtlNtStatusToDosError(status));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BOOL import_bcrypt_pubkey(PCERT_PUBLIC_KEY_INFO pubKeyInfo, BCRYPT_KEY_HANDLE *key)
|
||||
+{
|
||||
+ if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
|
||||
+ return import_bcrypt_pubkey_ecc(pubKeyInfo, key);
|
||||
+
|
||||
+ FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static BOOL prepare_bcrypt_signature_ecc(BYTE *encoded_sig, DWORD encoded_size,
|
||||
+ BYTE **sig_value, DWORD *sig_len)
|
||||
+{
|
||||
+ CERT_ECC_SIGNATURE *ecc_sig;
|
||||
+ DWORD size;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE,
|
||||
+ encoded_sig, encoded_size,
|
||||
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
|
||||
+ {
|
||||
+ LocalFree(ecc_sig);
|
||||
+ SetLastError(ERROR_INVALID_DATA);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
|
||||
+ if (!(*sig_value = CryptMemAlloc(*sig_len)))
|
||||
+ {
|
||||
+ LocalFree(ecc_sig);
|
||||
+ SetLastError(ERROR_OUTOFMEMORY);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < ecc_sig->r.cbData; i++)
|
||||
+ (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1];
|
||||
+ for (i = 0; i < ecc_sig->s.cbData; i++)
|
||||
+ (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1];
|
||||
+
|
||||
+ LocalFree(ecc_sig);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BOOL prepare_bcrypt_signature(PCERT_PUBLIC_KEY_INFO pubKeyInfo,
|
||||
+ const CERT_SIGNED_CONTENT_INFO *signedCert, BYTE **sig_value, DWORD *sig_len)
|
||||
+{
|
||||
+ BYTE *encoded_sig;
|
||||
+ BOOL ret = FALSE;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!signedCert->Signature.cbData)
|
||||
+ {
|
||||
+ SetLastError(ERROR_INVALID_DATA);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
|
||||
+ {
|
||||
+ SetLastError(ERROR_OUTOFMEMORY);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < signedCert->Signature.cbData; i++)
|
||||
+ encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
|
||||
+
|
||||
+ if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
|
||||
+ ret = prepare_bcrypt_signature_ecc(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len);
|
||||
+ else
|
||||
+ {
|
||||
+ FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ }
|
||||
+
|
||||
+ CryptMemFree(encoded_sig);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static BOOL verify_signature_bcrypt(HCRYPTPROV_LEGACY hCryptProv,
|
||||
+ DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
|
||||
+ const CERT_SIGNED_CONTENT_INFO *signedCert, PCCRYPT_OID_INFO info)
|
||||
+{
|
||||
+ BCRYPT_KEY_HANDLE key = NULL;
|
||||
+ BYTE *hash_value, *sig_value;
|
||||
+ DWORD hash_len, sig_len;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ if (!calculate_hash_bcrypt(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (!import_bcrypt_pubkey(pubKeyInfo, &key))
|
||||
+ {
|
||||
+ CryptMemFree(hash_value);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (!prepare_bcrypt_signature(pubKeyInfo, signedCert, &sig_value, &sig_len))
|
||||
+ {
|
||||
+ CryptMemFree(hash_value);
|
||||
+ BCryptDestroyKey(key);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
|
||||
+
|
||||
+ BCryptDestroyKey(key);
|
||||
+ CryptMemFree(hash_value);
|
||||
+ CryptMemFree(sig_value);
|
||||
+
|
||||
+ if (status)
|
||||
+ {
|
||||
+ FIXME("Failed to verify signature: %08x\n", status);
|
||||
+ SetLastError(RtlNtStatusToDosError(status));
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
|
||||
+ DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
|
||||
+ const CERT_SIGNED_CONTENT_INFO *signedCert)
|
||||
+{
|
||||
+ PCCRYPT_OID_INFO info;
|
||||
+
|
||||
+ info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
|
||||
+ signedCert->SignatureAlgorithm.pszObjId, 0);
|
||||
+ if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
|
||||
+ {
|
||||
+ SetLastError(NTE_BAD_ALGID);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ if (info->u.Algid == CALG_OID_INFO_CNG_ONLY)
|
||||
+ return verify_signature_bcrypt(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
|
||||
+ else
|
||||
+ return verify_signature_crypt(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
|
||||
+}
|
||||
+
|
||||
BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
|
||||
DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
|
||||
DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
|
||||
diff --git a/dlls/crypt32/tests/chain.c b/dlls/crypt32/tests/chain.c
|
||||
index 1279735e496..e3b280b0884 100644
|
||||
--- a/dlls/crypt32/tests/chain.c
|
||||
+++ b/dlls/crypt32/tests/chain.c
|
||||
@@ -3945,7 +3945,7 @@ static ChainCheck chainCheckECDSA = {
|
||||
{ CERT_TRUST_IS_UNTRUSTED_ROOT, CERT_TRUST_HAS_PREFERRED_ISSUER },
|
||||
{ CERT_TRUST_IS_UNTRUSTED_ROOT, 0 },
|
||||
1, simpleStatusECDSA
|
||||
- }, TODO_ERROR
|
||||
+ }, 0
|
||||
};
|
||||
|
||||
#define test_name_blob(a,b) _test_name_blob(__LINE__,a,b)
|
||||
@@ -4226,7 +4226,7 @@ static void testGetCertChain(void)
|
||||
chain = getChain(NULL, &chainCheckECDSA.certs, 0, TRUE, &nov2017, FALSE, 0);
|
||||
if (chain)
|
||||
{
|
||||
- todo_wine ok(chain->TrustStatus.dwErrorStatus == CERT_TRUST_IS_UNTRUSTED_ROOT,
|
||||
+ ok(chain->TrustStatus.dwErrorStatus == CERT_TRUST_IS_UNTRUSTED_ROOT,
|
||||
"unexpected chain error status %08x\n", chain->TrustStatus.dwErrorStatus);
|
||||
checkChainStatus(chain, &chainCheckECDSA.status, chainCheckECDSA.todo, "chainCheckECDSA", 0);
|
||||
pCertFreeCertificateChain(chain);
|
||||
--
|
||||
2.14.1
|
||||
|
2
patches/crypt32-ECDSA_Cert_Chains/definition
Normal file
2
patches/crypt32-ECDSA_Cert_Chains/definition
Normal file
@ -0,0 +1,2 @@
|
||||
Fixes: Implement support for validating ECDSA certificate chains
|
||||
Depends: bcrypt-Improvements
|
@ -111,6 +111,7 @@ patch_enable_all ()
|
||||
enable_crypt32_CMS_Certificates="$1"
|
||||
enable_crypt32_Certificate_Check="$1"
|
||||
enable_crypt32_CryptUnprotectMemory="$1"
|
||||
enable_crypt32_ECDSA_Cert_Chains="$1"
|
||||
enable_crypt32_MS_Root_Certs="$1"
|
||||
enable_crypt32_SHA_OIDs="$1"
|
||||
enable_d3d10_1_Forwards="$1"
|
||||
@ -618,6 +619,9 @@ patch_enable ()
|
||||
crypt32-CryptUnprotectMemory)
|
||||
enable_crypt32_CryptUnprotectMemory="$2"
|
||||
;;
|
||||
crypt32-ECDSA_Cert_Chains)
|
||||
enable_crypt32_ECDSA_Cert_Chains="$2"
|
||||
;;
|
||||
crypt32-MS_Root_Certs)
|
||||
enable_crypt32_MS_Root_Certs="$2"
|
||||
;;
|
||||
@ -2919,6 +2923,13 @@ if test "$enable_d3d11_Deferred_Context" -eq 1; then
|
||||
enable_wined3d_1DTextures=1
|
||||
fi
|
||||
|
||||
if test "$enable_crypt32_ECDSA_Cert_Chains" -eq 1; then
|
||||
if test "$enable_bcrypt_Improvements" -gt 1; then
|
||||
abort "Patchset bcrypt-Improvements disabled, but crypt32-ECDSA_Cert_Chains depends on that."
|
||||
fi
|
||||
enable_bcrypt_Improvements=1
|
||||
fi
|
||||
|
||||
if test "$enable_api_ms_win_Stub_DLLs" -eq 1; then
|
||||
if test "$enable_combase_RoApi" -gt 1; then
|
||||
abort "Patchset combase-RoApi disabled, but api-ms-win-Stub_DLLs depends on that."
|
||||
@ -3775,6 +3786,48 @@ if test "$enable_crypt32_CryptUnprotectMemory" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset crypt32-ECDSA_Cert_Chains
|
||||
# |
|
||||
# | This patchset has the following (direct or indirect) dependencies:
|
||||
# | * bcrypt-Improvements
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/bcrypt/bcrypt.spec, dlls/bcrypt/bcrypt_main.c, dlls/bcrypt/tests/bcrypt.c, dlls/crypt32/Makefile.in,
|
||||
# | dlls/crypt32/cert.c, dlls/crypt32/chain.c, dlls/crypt32/crypt32_private.h, dlls/crypt32/decode.c, dlls/crypt32/oid.c,
|
||||
# | dlls/crypt32/tests/chain.c, dlls/crypt32/tests/encode.c, dlls/crypt32/tests/oid.c, include/bcrypt.h, include/ntstatus.h,
|
||||
# | include/wincrypt.h
|
||||
# |
|
||||
if test "$enable_crypt32_ECDSA_Cert_Chains" -eq 1; then
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0001-bcrypt-Preparation-for-asymmetric-keys.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0002-include-Add-ecdsa-and-asymmetric-key-related-bcrypt-.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0003-bcrypt-tests-Add-basic-test-for-ecdsa.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0004-bcrypt-Implement-importing-of-ecdsa-keys.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0005-bcrypt-Implement-BCryptVerifySignature-for-ecdsa-sig.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0006-crypt32-tests-Basic-tests-for-decoding-ECDSA-signed-.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0007-crypt32-Implement-decoding-of-X509_OBJECT_IDENTIFIER.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0008-crypt32-Implement-decoding-of-X509_ECC_SIGNATURE.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0009-crypt32-tests-Add-basic-test-for-ecdsa-oid.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0010-crypt32-Add-oids-for-sha256ECDSA-and-sha384ECDSA.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0011-crypt32-Correctly-return-how-the-issuer-of-a-self-si.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0012-crypt32-tets-Add-test-for-verifying-an-ecdsa-chain.patch
|
||||
patch_apply crypt32-ECDSA_Cert_Chains/0013-crypt32-Implement-verification-of-ECDSA-signatures.patch
|
||||
(
|
||||
printf '%s\n' '+ { "Michael Müller", "bcrypt: Preparation for asymmetric keys.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "include: Add ecdsa and asymmetric key related bcrypt definitions.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "bcrypt/tests: Add basic test for ecdsa.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "bcrypt: Implement importing of ecdsa keys.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "bcrypt: Implement BCryptVerifySignature for ecdsa signatures.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32/tests: Basic tests for decoding ECDSA signed certificate.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32: Implement decoding of X509_OBJECT_IDENTIFIER.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32: Implement decoding of X509_ECC_SIGNATURE.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32/tests: Add basic test for ecdsa oid.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32: Add oids for sha256ECDSA and sha384ECDSA.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32: Correctly return how the issuer of a self signed certificate was checked.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32/tets: Add test for verifying an ecdsa chain.", 1 },';
|
||||
printf '%s\n' '+ { "Michael Müller", "crypt32: Implement verification of ECDSA signatures.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset crypt32-MS_Root_Certs
|
||||
# |
|
||||
# | Modified files:
|
||||
|
Loading…
x
Reference in New Issue
Block a user