bcrypt: Initial implementation for RSA key import and signature verification.
Signed-off-by: Hans Leidekker <hans@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
19e0f97f71
commit
b3c8723bd4
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue