From b3c8723bd4f3b23f02a7460e1a228fb5855e3475 Mon Sep 17 00:00:00 2001 From: Kimmo Myllyvirta Date: Mon, 26 Mar 2018 15:04:35 +0200 Subject: [PATCH] bcrypt: Initial implementation for RSA key import and signature verification. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/bcrypt/bcrypt_main.c | 127 +++++++++++++++++++++++++++++++++----- include/bcrypt.h | 17 +++++ 2 files changed, 130 insertions(+), 14 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index d41195e00d3..1490089cf72 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -76,6 +76,9 @@ static gnutls_sign_algorithm_t (*pgnutls_pk_to_sign)(gnutls_pk_algorithm_t, gnut static int (*pgnutls_pubkey_verify_hash2)(gnutls_pubkey_t, gnutls_sign_algorithm_t, unsigned int, const gnutls_datum_t *, const gnutls_datum_t *); +/* Not present in gnutls version < 2.11.0 */ +static int (*pgnutls_pubkey_import_rsa_raw)(gnutls_pubkey_t key, const gnutls_datum_t *m, const gnutls_datum_t *e); + static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); @@ -119,6 +122,11 @@ static int compat_gnutls_pubkey_verify_hash2(gnutls_pubkey_t key, gnutls_sign_al return GNUTLS_E_UNKNOWN_CIPHER_TYPE; } +static int compat_gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key, const gnutls_datum_t *m, const gnutls_datum_t *e) +{ + return GNUTLS_E_UNKNOWN_CIPHER_TYPE; +} + static void gnutls_log( int level, const char *msg ) { TRACE( "<%d> %s", level, msg ); @@ -185,6 +193,11 @@ static BOOL gnutls_initialize(void) WARN("gnutls_pubkey_verify_hash2 not found\n"); pgnutls_pubkey_verify_hash2 = compat_gnutls_pubkey_verify_hash2; } + if (!(pgnutls_pubkey_import_rsa_raw = wine_dlsym( libgnutls_handle, "gnutls_pubkey_import_rsa_raw", NULL, 0 ))) + { + WARN("gnutls_pubkey_import_rsa_raw not found\n"); + pgnutls_pubkey_import_rsa_raw = compat_gnutls_pubkey_import_rsa_raw; + } if (TRACE_ON( bcrypt )) { @@ -270,6 +283,7 @@ enum alg_id ALG_ID_MD4, ALG_ID_MD5, ALG_ID_RNG, + ALG_ID_RSA, ALG_ID_SHA1, ALG_ID_SHA256, ALG_ID_SHA384, @@ -303,6 +317,7 @@ alg_props[] = /* ALG_ID_MD4 */ { 270, 16, 512, BCRYPT_MD4_ALGORITHM, FALSE }, /* ALG_ID_MD5 */ { 274, 16, 512, BCRYPT_MD5_ALGORITHM, FALSE }, /* ALG_ID_RNG */ { 0, 0, 0, BCRYPT_RNG_ALGORITHM, FALSE }, + /* ALG_ID_RSA */ { 0, 0, 0, BCRYPT_RSA_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 }, @@ -380,6 +395,7 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR else if (!strcmpW( id, BCRYPT_MD4_ALGORITHM )) alg_id = ALG_ID_MD4; else if (!strcmpW( id, BCRYPT_MD5_ALGORITHM )) alg_id = ALG_ID_MD5; else if (!strcmpW( id, BCRYPT_RNG_ALGORITHM )) alg_id = ALG_ID_RNG; + else if (!strcmpW( id, BCRYPT_RSA_ALGORITHM )) alg_id = ALG_ID_RSA; else if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1; else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256; else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384; @@ -1242,6 +1258,7 @@ static NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, con { case ALG_ID_ECDSA_P256: case ALG_ID_ECDSA_P384: + case ALG_ID_RSA: break; default: @@ -1401,6 +1418,34 @@ static NTSTATUS import_gnutls_pubkey_ecc( struct key *key, gnutls_pubkey_t *gnut return STATUS_SUCCESS; } +static NTSTATUS import_gnutls_pubkey_rsa( struct key *key, gnutls_pubkey_t *gnutls_key ) +{ + BCRYPT_RSAKEY_BLOB *rsa_blob; + gnutls_datum_t m, e; + int ret; + + if ((ret = pgnutls_pubkey_init( gnutls_key ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + rsa_blob = (BCRYPT_RSAKEY_BLOB *)key->u.a.pubkey; + e.data = key->u.a.pubkey + sizeof(*rsa_blob); + e.size = rsa_blob->cbPublicExp; + m.data = key->u.a.pubkey + sizeof(*rsa_blob) + rsa_blob->cbPublicExp; + m.size = rsa_blob->cbModulus; + + if ((ret = pgnutls_pubkey_import_rsa_raw( *gnutls_key, &m, &e ))) + { + 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) @@ -1409,6 +1454,9 @@ static NTSTATUS import_gnutls_pubkey( struct key *key, gnutls_pubkey_t *gnutls_k case ALG_ID_ECDSA_P384: return import_gnutls_pubkey_ecc( key, gnutls_key ); + case ALG_ID_RSA: + return import_gnutls_pubkey_rsa( key, gnutls_key ); + default: FIXME("algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1437,6 +1485,14 @@ static NTSTATUS prepare_gnutls_signature_ecc( struct key *key, UCHAR *signature, return STATUS_SUCCESS; } +static NTSTATUS prepare_gnutls_signature_rsa( struct key *key, UCHAR *signature, ULONG signature_len, + gnutls_datum_t *gnutls_signature ) +{ + gnutls_signature->data = signature; + gnutls_signature->size = signature_len; + return STATUS_SUCCESS; +} + static NTSTATUS prepare_gnutls_signature( struct key *key, UCHAR *signature, ULONG signature_len, gnutls_datum_t *gnutls_signature ) { @@ -1446,6 +1502,9 @@ static NTSTATUS prepare_gnutls_signature( struct key *key, UCHAR *signature, ULO case ALG_ID_ECDSA_P384: return prepare_gnutls_signature_ecc( key, signature, signature_len, gnutls_signature ); + case ALG_ID_RSA: + return prepare_gnutls_signature_rsa( key, signature, signature_len, gnutls_signature ); + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1463,26 +1522,45 @@ static NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *ha 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_alg = GNUTLS_DIG_SHA256; break; - case 48: hash_alg = 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: + { + 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_alg = GNUTLS_DIG_SHA256; break; + case 48: hash_alg = GNUTLS_DIG_SHA384; break; + + default: + FIXME( "hash size %u not yet supported\n", hash_len ); + return STATUS_INVALID_SIGNATURE; + } pk_alg = GNUTLS_PK_ECC; break; + } + case ALG_ID_RSA: + { + BCRYPT_PKCS1_PADDING_INFO *info = (BCRYPT_PKCS1_PADDING_INFO *)padding; + if (!(flags & BCRYPT_PAD_PKCS1) || !info) return STATUS_INVALID_PARAMETER; + if (!info->pszAlgId) return STATUS_INVALID_SIGNATURE; + + if (!strcmpW( info->pszAlgId, BCRYPT_SHA1_ALGORITHM )) hash_alg = GNUTLS_DIG_SHA1; + else if (!strcmpW( info->pszAlgId, BCRYPT_SHA256_ALGORITHM )) hash_alg = GNUTLS_DIG_SHA256; + else if (!strcmpW( info->pszAlgId, BCRYPT_SHA384_ALGORITHM )) hash_alg = GNUTLS_DIG_SHA384; + else if (!strcmpW( info->pszAlgId, BCRYPT_SHA512_ALGORITHM )) hash_alg = GNUTLS_DIG_SHA512; + else + { + FIXME( "hash algorithm %s not supported\n", debugstr_w(info->pszAlgId) ); + return STATUS_NOT_SUPPORTED; + } + pk_alg = GNUTLS_PK_RSA; + break; + } default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1505,7 +1583,7 @@ static NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *ha gnutls_hash.size = hash_len; ret = pgnutls_pubkey_verify_hash2( gnutls_key, sign_alg, 0, &gnutls_hash, &gnutls_signature ); - heap_free( gnutls_signature.data ); + if (gnutls_signature.data != signature) heap_free( gnutls_signature.data ); pgnutls_pubkey_deinit( gnutls_key ); return (ret < 0) ? STATUS_INVALID_SIGNATURE : STATUS_SUCCESS; } @@ -1945,6 +2023,27 @@ NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HAN *ret_key = key; return STATUS_SUCCESS; } + else if (!strcmpW( type, BCRYPT_RSAPUBLIC_BLOB )) + { + BCRYPT_RSAKEY_BLOB *rsa_blob = (BCRYPT_RSAKEY_BLOB *)input; + ULONG size; + + if (input_len < sizeof(*rsa_blob)) return STATUS_INVALID_PARAMETER; + if (alg->id != ALG_ID_RSA || rsa_blob->Magic != BCRYPT_RSAPUBLIC_MAGIC) return STATUS_NOT_SUPPORTED; + + if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY; + key->hdr.magic = MAGIC_KEY; + + size = sizeof(*rsa_blob) + rsa_blob->cbPublicExp + rsa_blob->cbModulus; + if ((status = key_asymmetric_init( key, alg, (BYTE *)rsa_blob, size ))) + { + heap_free( key ); + return status; + } + + *ret_key = key; + return STATUS_SUCCESS; + } FIXME( "unsupported key type %s\n", debugstr_w(type) ); return STATUS_NOT_SUPPORTED; diff --git a/include/bcrypt.h b/include/bcrypt.h index f28b0d395d1..df54f621fa7 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -63,6 +63,8 @@ typedef LONG NTSTATUS; #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 BCRYPT_RSAPUBLIC_BLOB (const WCHAR []){'R','S','A','P','U','B','L','I','C','B','L','O','B',0} +#define BCRYPT_RSAPRIVATE_BLOB (const WCHAR []){'R','S','A','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,7 @@ typedef LONG NTSTATUS; #define BCRYPT_MD4_ALGORITHM (const WCHAR []){'M','D','4',0} #define BCRYPT_MD5_ALGORITHM (const WCHAR []){'M','D','5',0} #define BCRYPT_RNG_ALGORITHM (const WCHAR []){'R','N','G',0} +#define BCRYPT_RSA_ALGORITHM (const WCHAR []){'R','S','A',0} #define BCRYPT_SHA1_ALGORITHM (const WCHAR []){'S','H','A','1',0} #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} @@ -133,6 +136,20 @@ typedef struct _BCRYPT_ECCKEY_BLOB ULONG cbKey; } BCRYPT_ECCKEY_BLOB, *PBCRYPT_ECCKEY_BLOB; +#define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 +#define BCRYPT_RSAPRIVATE_MAGIC 0x32415352 +#define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 + +typedef struct _BCRYPT_RSAKEY_BLOB +{ + ULONG Magic; + ULONG BitLength; + ULONG cbPublicExp; + ULONG cbModulus; + ULONG cbPrime1; + ULONG cbPrime2; +} BCRYPT_RSAKEY_BLOB; + typedef struct _BCRYPT_PKCS1_PADDING_INFO { LPCWSTR pszAlgId;