reactos/dll/win32/bcrypt/bcrypt_main.c
Joachim Henze f81b2bb2cd [0.4.11][BCRYPT] Add ECDSA P384 to known algorithms (#4236)
Today 2022-10-25 was the day, when I spotted the first URL in rapps that is not longer happy with just having
ECDSA_P256 but now needs even ECDSA_P384 to make the rapps download succeed. *eye-rolling*
It was https://bitbucket.org/Swyter/tld-downloads/downloads/diabloiidemo.exe
that failed the rapps download with

fixme:(dll/win32/bcrypt/bcrypt_main.c:359) algorithm L"ECDSA_P384" not supported
err:(win32ss/user/user32/windows/messagebox.c:1048) MessageBox: L"Paket konnte nicht geladen werden! Pr\00fcfen Sie Ihre Internetverbindung!"

So I have no choice but to follow the totally stupid crypto-rat-race and
add the missing structs and handlers in BCryptOpenAlgorithmProvider().

When will the world ever learn that the new cryptos do outdate faster than the new shit even can be implemented in time everywhere?
Each additional crypto algorithm effectively enlarges the attack surface of the end-points instead of making stuff more secure.
The world is rushing towards totally breaking backward compatibility to older systems. This is built-in obsolescence. For which gain?
This race can never be won. Each crypto-iteration just intensifies the existing chaos. Enough ranting...

fix picked from 0.4.15-dev-3662-g c3e0df0611

It is a cherry-pick a part of Michael Müller's commit from Wine
76b6c360fa

The commit doesn't fix CORE-14198 at all, same like on master, but since the original commit was linked
to that JIRA ticket as well, I decided to do the same with the backport.
2022-10-25 02:19:06 +02:00

1153 lines
31 KiB
C

/*
* Copyright 2009 Henri Verbeet for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include <wine/config.h>
#include <wine/port.h>
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <ntsecapi.h>
#include <bcrypt.h>
#include <wine/debug.h>
#include <wine/unicode.h>
#include <wine/library.h>
#ifdef SONAME_LIBMBEDTLS
#include <mbedtls/md.h>
#include <mbedtls/md5.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#endif
WINE_DEFAULT_DEBUG_CHANNEL(bcrypt);
static HINSTANCE instance;
#if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
WINE_DECLARE_DEBUG_CHANNEL(winediag);
static void *libgnutls_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(gnutls_global_deinit);
MAKE_FUNCPTR(gnutls_global_init);
MAKE_FUNCPTR(gnutls_global_set_log_function);
MAKE_FUNCPTR(gnutls_global_set_log_level);
MAKE_FUNCPTR(gnutls_hash);
MAKE_FUNCPTR(gnutls_hash_deinit);
MAKE_FUNCPTR(gnutls_hash_init);
MAKE_FUNCPTR(gnutls_hmac);
MAKE_FUNCPTR(gnutls_hmac_deinit);
MAKE_FUNCPTR(gnutls_hmac_init);
MAKE_FUNCPTR(gnutls_perror);
#undef MAKE_FUNCPTR
static void gnutls_log( int level, const char *msg )
{
TRACE( "<%d> %s", level, msg );
}
static BOOL gnutls_initialize(void)
{
int ret;
if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 )))
{
ERR_(winediag)( "failed to load libgnutls, no support for crypto hashes\n" );
return FALSE;
}
#define LOAD_FUNCPTR(f) \
if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \
{ \
ERR( "failed to load %s\n", #f ); \
goto fail; \
}
LOAD_FUNCPTR(gnutls_global_deinit)
LOAD_FUNCPTR(gnutls_global_init)
LOAD_FUNCPTR(gnutls_global_set_log_function)
LOAD_FUNCPTR(gnutls_global_set_log_level)
LOAD_FUNCPTR(gnutls_hash);
LOAD_FUNCPTR(gnutls_hash_deinit);
LOAD_FUNCPTR(gnutls_hash_init);
LOAD_FUNCPTR(gnutls_hmac);
LOAD_FUNCPTR(gnutls_hmac_deinit);
LOAD_FUNCPTR(gnutls_hmac_init);
LOAD_FUNCPTR(gnutls_perror)
#undef LOAD_FUNCPTR
if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS)
{
pgnutls_perror( ret );
goto fail;
}
if (TRACE_ON( bcrypt ))
{
pgnutls_global_set_log_level( 4 );
pgnutls_global_set_log_function( gnutls_log );
}
return TRUE;
fail:
wine_dlclose( libgnutls_handle, NULL, 0 );
libgnutls_handle = NULL;
return FALSE;
}
static void gnutls_uninitialize(void)
{
pgnutls_global_deinit();
wine_dlclose( libgnutls_handle, NULL, 0 );
libgnutls_handle = NULL;
}
#elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
WINE_DECLARE_DEBUG_CHANNEL(winediag);
void *libmbedtls_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(mbedtls_md_init);
MAKE_FUNCPTR(mbedtls_md_setup);
MAKE_FUNCPTR(mbedtls_md_update);
MAKE_FUNCPTR(mbedtls_md_hmac_starts);
MAKE_FUNCPTR(mbedtls_md_hmac_finish);
MAKE_FUNCPTR(mbedtls_md_free);
MAKE_FUNCPTR(mbedtls_md5_init);
MAKE_FUNCPTR(mbedtls_md5_starts);
MAKE_FUNCPTR(mbedtls_md5_update);
MAKE_FUNCPTR(mbedtls_md5_finish);
MAKE_FUNCPTR(mbedtls_md5_free);
MAKE_FUNCPTR(mbedtls_sha1_init);
MAKE_FUNCPTR(mbedtls_sha1_starts);
MAKE_FUNCPTR(mbedtls_sha1_update);
MAKE_FUNCPTR(mbedtls_sha1_finish);
MAKE_FUNCPTR(mbedtls_sha1_free);
MAKE_FUNCPTR(mbedtls_sha256_init);
MAKE_FUNCPTR(mbedtls_sha256_starts);
MAKE_FUNCPTR(mbedtls_sha256_update);
MAKE_FUNCPTR(mbedtls_sha256_finish);
MAKE_FUNCPTR(mbedtls_sha256_free);
MAKE_FUNCPTR(mbedtls_sha512_init);
MAKE_FUNCPTR(mbedtls_sha512_starts);
MAKE_FUNCPTR(mbedtls_sha512_update);
MAKE_FUNCPTR(mbedtls_sha512_finish);
MAKE_FUNCPTR(mbedtls_sha512_free);
#undef MAKE_FUNCPTR
#define mbedtls_md_init pmbedtls_md_init
#define mbedtls_md_setup pmbedtls_md_setup
#define mbedtls_md_update pmbedtls_md_update
#define mbedtls_md_hmac_starts pmbedtls_md_hmac_starts
#define mbedtls_md_hmac_finish pmbedtls_md_hmac_finish
#define mbedtls_md_free pmbedtls_md_free
#define mbedtls_md5_init pmbedtls_md5_init
#define mbedtls_md5_starts pmbedtls_md5_starts
#define mbedtls_md5_update pmbedtls_md5_update
#define mbedtls_md5_finish pmbedtls_md5_finish
#define mbedtls_md5_free pmbedtls_md5_free
#define mbedtls_sha1_init pmbedtls_sha1_init
#define mbedtls_sha1_starts pmbedtls_sha1_starts
#define mbedtls_sha1_update pmbedtls_sha1_update
#define mbedtls_sha1_finish pmbedtls_sha1_finish
#define mbedtls_sha1_free pmbedtls_sha1_free
#define mbedtls_sha256_init pmbedtls_sha256_init
#define mbedtls_sha256_starts pmbedtls_sha256_starts
#define mbedtls_sha256_update pmbedtls_sha256_update
#define mbedtls_sha256_finish pmbedtls_sha256_finish
#define mbedtls_sha256_free pmbedtls_sha256_free
#define mbedtls_sha512_init pmbedtls_sha512_init
#define mbedtls_sha512_starts pmbedtls_sha512_starts
#define mbedtls_sha512_update pmbedtls_sha512_update
#define mbedtls_sha512_finish pmbedtls_sha512_finish
#define mbedtls_sha512_free pmbedtls_sha512_free
static BOOL mbedtls_initialize(void)
{
if (!(libmbedtls_handle = wine_dlopen( SONAME_LIBMBEDTLS, RTLD_NOW, NULL, 0 )))
{
ERR_(winediag)( "failed to load libmbedtls, no support for crypto hashes\n" );
return FALSE;
}
#define LOAD_FUNCPTR(f) \
if (!(p##f = wine_dlsym( libmbedtls_handle, #f, NULL, 0 ))) \
{ \
ERR( "failed to load %s\n", #f ); \
goto fail; \
}
LOAD_FUNCPTR(mbedtls_md_init)
LOAD_FUNCPTR(mbedtls_md_setup)
LOAD_FUNCPTR(mbedtls_md_update)
LOAD_FUNCPTR(mbedtls_md_hmac_starts)
LOAD_FUNCPTR(mbedtls_md_hmac_finish)
LOAD_FUNCPTR(mbedtls_md_free);
LOAD_FUNCPTR(mbedtls_md5_init)
LOAD_FUNCPTR(mbedtls_md5_starts)
LOAD_FUNCPTR(mbedtls_md5_update)
LOAD_FUNCPTR(mbedtls_md5_finish)
LOAD_FUNCPTR(mbedtls_md5_free);
LOAD_FUNCPTR(mbedtls_sha1_init)
LOAD_FUNCPTR(mbedtls_sha1_starts)
LOAD_FUNCPTR(mbedtls_sha1_update)
LOAD_FUNCPTR(mbedtls_sha1_finish)
LOAD_FUNCPTR(mbedtls_sha1_free);
LOAD_FUNCPTR(mbedtls_sha256_init)
LOAD_FUNCPTR(mbedtls_sha256_starts)
LOAD_FUNCPTR(mbedtls_sha256_update)
LOAD_FUNCPTR(mbedtls_sha256_finish)
LOAD_FUNCPTR(mbedtls_sha256_free);
LOAD_FUNCPTR(mbedtls_sha512_init)
LOAD_FUNCPTR(mbedtls_sha512_starts)
LOAD_FUNCPTR(mbedtls_sha512_update)
LOAD_FUNCPTR(mbedtls_sha512_finish)
LOAD_FUNCPTR(mbedtls_sha512_free);
#undef LOAD_FUNCPTR
return TRUE;
fail:
wine_dlclose( libmbedtls_handle, NULL, 0 );
libmbedtls_handle = NULL;
return FALSE;
}
static void mbedtls_uninitialize(void)
{
wine_dlclose( libmbedtls_handle, NULL, 0 );
libmbedtls_handle = NULL;
}
#endif /* SONAME_LIBMBEDTLS && !HAVE_COMMONCRYPTO_COMMONDIGEST_H && !__REACTOS__ */
NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG dwAlgOperations, ULONG *pAlgCount,
BCRYPT_ALGORITHM_IDENTIFIER **ppAlgList, ULONG dwFlags)
{
FIXME("%08x, %p, %p, %08x - stub\n", dwAlgOperations, pAlgCount, ppAlgList, dwFlags);
*ppAlgList=NULL;
*pAlgCount=0;
return STATUS_NOT_IMPLEMENTED;
}
#define MAGIC_ALG (('A' << 24) | ('L' << 16) | ('G' << 8) | '0')
#define MAGIC_HASH (('H' << 24) | ('A' << 16) | ('S' << 8) | 'H')
struct object
{
ULONG magic;
};
enum alg_id
{
ALG_ID_MD5,
ALG_ID_RNG,
ALG_ID_SHA1,
ALG_ID_SHA256,
ALG_ID_SHA384,
ALG_ID_SHA512,
ALG_ID_ECDSA_P256,
ALG_ID_ECDSA_P384,
};
static const struct {
ULONG hash_length;
const WCHAR *alg_name;
} alg_props[] = {
/* ALG_ID_MD5 */ { 16, BCRYPT_MD5_ALGORITHM },
/* ALG_ID_RNG */ { 0, BCRYPT_RNG_ALGORITHM },
/* ALG_ID_SHA1 */ { 20, BCRYPT_SHA1_ALGORITHM },
/* ALG_ID_SHA256 */ { 32, BCRYPT_SHA256_ALGORITHM },
/* ALG_ID_SHA384 */ { 48, BCRYPT_SHA384_ALGORITHM },
/* ALG_ID_SHA512 */ { 64, BCRYPT_SHA512_ALGORITHM },
/* ALG_ID_ECDSA_P256 */ { 0, BCRYPT_ECDSA_P256_ALGORITHM },
/* ALG_ID_ECDSA_P384 */ { 0, BCRYPT_ECDSA_P384_ALGORITHM },
};
struct algorithm
{
struct object hdr;
enum alg_id id;
BOOL hmac;
};
NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE handle, UCHAR *buffer, ULONG count, ULONG flags)
{
const DWORD supported_flags = BCRYPT_USE_SYSTEM_PREFERRED_RNG;
struct algorithm *algorithm = handle;
TRACE("%p, %p, %u, %08x - semi-stub\n", handle, buffer, count, flags);
if (!algorithm)
{
/* It's valid to call without an algorithm if BCRYPT_USE_SYSTEM_PREFERRED_RNG
* is set. In this case the preferred system RNG is used.
*/
if (!(flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
return STATUS_INVALID_HANDLE;
}
else if (algorithm->hdr.magic != MAGIC_ALG || algorithm->id != ALG_ID_RNG)
return STATUS_INVALID_HANDLE;
if (!buffer)
return STATUS_INVALID_PARAMETER;
if (flags & ~supported_flags)
FIXME("unsupported flags %08x\n", flags & ~supported_flags);
if (algorithm)
FIXME("ignoring selected algorithm\n");
/* When zero bytes are requested the function returns success too. */
if (!count)
return STATUS_SUCCESS;
if (algorithm || (flags & BCRYPT_USE_SYSTEM_PREFERRED_RNG))
{
if (RtlGenRandom(buffer, count))
return STATUS_SUCCESS;
}
FIXME("called with unsupported parameters, returning error\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR id, LPCWSTR implementation, DWORD flags )
{
struct algorithm *alg;
enum alg_id alg_id;
const DWORD supported_flags = BCRYPT_ALG_HANDLE_HMAC_FLAG;
TRACE( "%p, %s, %s, %08x\n", handle, wine_dbgstr_w(id), wine_dbgstr_w(implementation), flags );
if (!handle || !id) return STATUS_INVALID_PARAMETER;
if (flags & ~supported_flags)
{
FIXME( "unsupported flags %08x\n", flags & ~supported_flags);
return STATUS_NOT_IMPLEMENTED;
}
if (!strcmpW( id, BCRYPT_SHA1_ALGORITHM )) alg_id = ALG_ID_SHA1;
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_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) );
return STATUS_NOT_IMPLEMENTED;
}
if (implementation && strcmpW( implementation, MS_PRIMITIVE_PROVIDER ))
{
FIXME( "implementation %s not supported\n", debugstr_w(implementation) );
return STATUS_NOT_IMPLEMENTED;
}
if (!(alg = HeapAlloc( GetProcessHeap(), 0, sizeof(*alg) ))) return STATUS_NO_MEMORY;
alg->hdr.magic = MAGIC_ALG;
alg->id = alg_id;
alg->hmac = flags & BCRYPT_ALG_HANDLE_HMAC_FLAG;
*handle = alg;
return STATUS_SUCCESS;
}
NTSTATUS WINAPI BCryptCloseAlgorithmProvider( BCRYPT_ALG_HANDLE handle, DWORD flags )
{
struct algorithm *alg = handle;
TRACE( "%p, %08x\n", handle, flags );
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
HeapFree( GetProcessHeap(), 0, alg );
return STATUS_SUCCESS;
}
NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
{
FIXME("%p - semi-stub\n", enabled);
if (!enabled)
return STATUS_INVALID_PARAMETER;
*enabled = FALSE;
return STATUS_SUCCESS;
}
#ifdef HAVE_COMMONCRYPTO_COMMONDIGEST_H
struct hash
{
struct object hdr;
enum alg_id alg_id;
BOOL hmac;
union
{
CC_MD5_CTX md5_ctx;
CC_SHA1_CTX sha1_ctx;
CC_SHA256_CTX sha256_ctx;
CC_SHA512_CTX sha512_ctx;
CCHmacContext hmac_ctx;
} u;
};
static NTSTATUS hash_init( struct hash *hash )
{
switch (hash->alg_id)
{
case ALG_ID_MD5:
CC_MD5_Init( &hash->u.md5_ctx );
break;
case ALG_ID_SHA1:
CC_SHA1_Init( &hash->u.sha1_ctx );
break;
case ALG_ID_SHA256:
CC_SHA256_Init( &hash->u.sha256_ctx );
break;
case ALG_ID_SHA384:
CC_SHA384_Init( &hash->u.sha512_ctx );
break;
case ALG_ID_SHA512:
CC_SHA512_Init( &hash->u.sha512_ctx );
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
{
CCHmacAlgorithm cc_algorithm;
switch (hash->alg_id)
{
case ALG_ID_MD5:
cc_algorithm = kCCHmacAlgMD5;
break;
case ALG_ID_SHA1:
cc_algorithm = kCCHmacAlgSHA1;
break;
case ALG_ID_SHA256:
cc_algorithm = kCCHmacAlgSHA256;
break;
case ALG_ID_SHA384:
cc_algorithm = kCCHmacAlgSHA384;
break;
case ALG_ID_SHA512:
cc_algorithm = kCCHmacAlgSHA512;
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
CCHmacInit( &hash->u.hmac_ctx, cc_algorithm, key, key_size );
return STATUS_SUCCESS;
}
static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
{
switch (hash->alg_id)
{
case ALG_ID_MD5:
CC_MD5_Update( &hash->u.md5_ctx, input, size );
break;
case ALG_ID_SHA1:
CC_SHA1_Update( &hash->u.sha1_ctx, input, size );
break;
case ALG_ID_SHA256:
CC_SHA256_Update( &hash->u.sha256_ctx, input, size );
break;
case ALG_ID_SHA384:
CC_SHA384_Update( &hash->u.sha512_ctx, input, size );
break;
case ALG_ID_SHA512:
CC_SHA512_Update( &hash->u.sha512_ctx, input, size );
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
{
CCHmacUpdate( &hash->u.hmac_ctx, input, size );
return STATUS_SUCCESS;
}
static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
{
switch (hash->alg_id)
{
case ALG_ID_MD5:
CC_MD5_Final( output, &hash->u.md5_ctx );
break;
case ALG_ID_SHA1:
CC_SHA1_Final( output, &hash->u.sha1_ctx );
break;
case ALG_ID_SHA256:
CC_SHA256_Final( output, &hash->u.sha256_ctx );
break;
case ALG_ID_SHA384:
CC_SHA384_Final( output, &hash->u.sha512_ctx );
break;
case ALG_ID_SHA512:
CC_SHA512_Final( output, &hash->u.sha512_ctx );
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
break;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
{
CCHmacFinal( &hash->u.hmac_ctx, output );
return STATUS_SUCCESS;
}
#elif defined(HAVE_GNUTLS_HASH)
struct hash
{
struct object hdr;
enum alg_id alg_id;
BOOL hmac;
union
{
gnutls_hash_hd_t hash_handle;
gnutls_hmac_hd_t hmac_handle;
} u;
};
static NTSTATUS hash_init( struct hash *hash )
{
gnutls_digest_algorithm_t alg;
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
switch (hash->alg_id)
{
case ALG_ID_MD5:
alg = GNUTLS_DIG_MD5;
break;
case ALG_ID_SHA1:
alg = GNUTLS_DIG_SHA1;
break;
case ALG_ID_SHA256:
alg = GNUTLS_DIG_SHA256;
break;
case ALG_ID_SHA384:
alg = GNUTLS_DIG_SHA384;
break;
case ALG_ID_SHA512:
alg = GNUTLS_DIG_SHA512;
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
if (pgnutls_hash_init( &hash->u.hash_handle, alg )) return STATUS_INTERNAL_ERROR;
return STATUS_SUCCESS;
}
static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
{
gnutls_mac_algorithm_t alg;
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
switch (hash->alg_id)
{
case ALG_ID_MD5:
alg = GNUTLS_MAC_MD5;
break;
case ALG_ID_SHA1:
alg = GNUTLS_MAC_SHA1;
break;
case ALG_ID_SHA256:
alg = GNUTLS_MAC_SHA256;
break;
case ALG_ID_SHA384:
alg = GNUTLS_MAC_SHA384;
break;
case ALG_ID_SHA512:
alg = GNUTLS_MAC_SHA512;
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
if (pgnutls_hmac_init( &hash->u.hmac_handle, alg, key, key_size )) return STATUS_INTERNAL_ERROR;
return STATUS_SUCCESS;
}
static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
{
if (pgnutls_hash( hash->u.hash_handle, input, size )) return STATUS_INTERNAL_ERROR;
return STATUS_SUCCESS;
}
static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
{
if (pgnutls_hmac( hash->u.hmac_handle, input, size )) return STATUS_INTERNAL_ERROR;
return STATUS_SUCCESS;
}
static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
{
pgnutls_hash_deinit( hash->u.hash_handle, output );
return STATUS_SUCCESS;
}
static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
{
pgnutls_hmac_deinit( hash->u.hmac_handle, output );
return STATUS_SUCCESS;
}
#elif defined(SONAME_LIBMBEDTLS)
struct hash
{
struct object hdr;
BOOL hmac;
enum alg_id alg_id;
union
{
mbedtls_md5_context md5_ctx;
mbedtls_sha1_context sha1_ctx;
mbedtls_sha256_context sha256_ctx;
mbedtls_sha512_context sha512_ctx;
mbedtls_md_context_t hmac_ctx;
} u;
};
static NTSTATUS hash_init( struct hash *hash )
{
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
switch (hash->alg_id)
{
case ALG_ID_MD5:
mbedtls_md5_init(&hash->u.md5_ctx);
mbedtls_md5_starts(&hash->u.md5_ctx);
break;
case ALG_ID_SHA1:
mbedtls_sha1_init(&hash->u.sha1_ctx);
mbedtls_sha1_starts(&hash->u.sha1_ctx);
break;
case ALG_ID_SHA256:
mbedtls_sha256_init(&hash->u.sha256_ctx);
mbedtls_sha256_starts(&hash->u.sha256_ctx, FALSE);
break;
case ALG_ID_SHA384:
case ALG_ID_SHA512:
mbedtls_sha512_init(&hash->u.sha512_ctx);
mbedtls_sha512_starts(&hash->u.sha512_ctx, hash->alg_id==ALG_ID_SHA384);
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_init( struct hash *hash, UCHAR *key, ULONG key_size )
{
const mbedtls_md_info_t *md_info;
mbedtls_md_type_t md_type;
int ret;
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
mbedtls_md_init(&hash->u.hmac_ctx);
switch (hash->alg_id)
{
case ALG_ID_MD5:
md_type = MBEDTLS_MD_MD5;
break;
case ALG_ID_SHA1:
md_type = MBEDTLS_MD_SHA1;
break;
case ALG_ID_SHA256:
md_type = MBEDTLS_MD_SHA256;
break;
case ALG_ID_SHA384:
md_type = MBEDTLS_MD_SHA384;
break;
case ALG_ID_SHA512:
md_type = MBEDTLS_MD_SHA512;
break;
default:
ERR("unhandled id %u\n", hash->alg_id);
return STATUS_NOT_IMPLEMENTED;
}
if ((md_info = mbedtls_md_info_from_type(md_type)) == NULL)
{
mbedtls_md_free(&hash->u.hmac_ctx);
return STATUS_INTERNAL_ERROR;
}
if ((ret = mbedtls_md_setup(&hash->u.hmac_ctx, md_info, 1)) != 0)
{
mbedtls_md_free(&hash->u.hmac_ctx);
return STATUS_INTERNAL_ERROR;
}
mbedtls_md_hmac_starts(&hash->u.hmac_ctx, key, key_size);
return STATUS_SUCCESS;
}
static NTSTATUS hash_update( struct hash *hash, UCHAR *input, ULONG size )
{
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
switch (hash->alg_id)
{
case ALG_ID_MD5:
mbedtls_md5_update(&hash->u.md5_ctx, input, size);
break;
case ALG_ID_SHA1:
mbedtls_sha1_update(&hash->u.sha1_ctx, input, size);
break;
case ALG_ID_SHA256:
mbedtls_sha256_update(&hash->u.sha256_ctx, input, size);
break;
case ALG_ID_SHA384:
case ALG_ID_SHA512:
mbedtls_sha512_update(&hash->u.sha512_ctx, input, size);
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_update( struct hash *hash, UCHAR *input, ULONG size )
{
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
mbedtls_md_update(&hash->u.hmac_ctx, input, size);
return STATUS_SUCCESS;
}
static NTSTATUS hash_finish( struct hash *hash, UCHAR *output, ULONG size )
{
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
switch (hash->alg_id)
{
case ALG_ID_MD5:
mbedtls_md5_finish(&hash->u.md5_ctx, output);
mbedtls_md5_free(&hash->u.md5_ctx);
break;
case ALG_ID_SHA1:
mbedtls_sha1_finish(&hash->u.sha1_ctx, output);
mbedtls_sha1_free(&hash->u.sha1_ctx);
break;
case ALG_ID_SHA256:
mbedtls_sha256_finish(&hash->u.sha256_ctx, output);
mbedtls_sha256_free(&hash->u.sha256_ctx);
break;
case ALG_ID_SHA384:
case ALG_ID_SHA512:
mbedtls_sha512_finish(&hash->u.sha512_ctx, output);
mbedtls_sha512_free(&hash->u.sha512_ctx);
break;
default:
ERR( "unhandled id %u\n", hash->alg_id );
return STATUS_NOT_IMPLEMENTED;
}
return STATUS_SUCCESS;
}
static NTSTATUS hmac_finish( struct hash *hash, UCHAR *output, ULONG size )
{
#ifndef __REACTOS__
if (!libmbedtls_handle) return STATUS_INTERNAL_ERROR;
#endif
mbedtls_md_hmac_finish(&hash->u.hmac_ctx, output);
mbedtls_md_free(&hash->u.hmac_ctx);
return STATUS_SUCCESS;
}
#endif
#define OBJECT_LENGTH_MD5 274
#define OBJECT_LENGTH_SHA1 278
#define OBJECT_LENGTH_SHA256 286
#define OBJECT_LENGTH_SHA384 382
#define OBJECT_LENGTH_SHA512 382
static NTSTATUS generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
{
if (!strcmpW( prop, BCRYPT_HASH_LENGTH ))
{
*ret_size = sizeof(ULONG);
if (size < sizeof(ULONG))
return STATUS_BUFFER_TOO_SMALL;
if(buf)
*(ULONG*)buf = alg_props[id].hash_length;
return STATUS_SUCCESS;
}
if (!strcmpW( prop, BCRYPT_ALGORITHM_NAME ))
{
*ret_size = (strlenW(alg_props[id].alg_name)+1)*sizeof(WCHAR);
if (size < *ret_size)
return STATUS_BUFFER_TOO_SMALL;
if(buf)
memcpy(buf, alg_props[id].alg_name, *ret_size);
return STATUS_SUCCESS;
}
return STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS get_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
{
NTSTATUS status;
ULONG value;
status = generic_alg_property( id, prop, buf, size, ret_size );
if (status != STATUS_NOT_IMPLEMENTED)
return status;
switch (id)
{
case ALG_ID_MD5:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
{
value = OBJECT_LENGTH_MD5;
break;
}
FIXME( "unsupported md5 algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
case ALG_ID_RNG:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH )) return STATUS_NOT_SUPPORTED;
FIXME( "unsupported rng algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
case ALG_ID_SHA1:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
{
value = OBJECT_LENGTH_SHA1;
break;
}
FIXME( "unsupported sha1 algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
case ALG_ID_SHA256:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
{
value = OBJECT_LENGTH_SHA256;
break;
}
FIXME( "unsupported sha256 algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
case ALG_ID_SHA384:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
{
value = OBJECT_LENGTH_SHA384;
break;
}
FIXME( "unsupported sha384 algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
case ALG_ID_SHA512:
if (!strcmpW( prop, BCRYPT_OBJECT_LENGTH ))
{
value = OBJECT_LENGTH_SHA512;
break;
}
FIXME( "unsupported sha512 algorithm property %s\n", debugstr_w(prop) );
return STATUS_NOT_IMPLEMENTED;
default:
FIXME( "unsupported algorithm %u\n", id );
return STATUS_NOT_IMPLEMENTED;
}
if (size < sizeof(ULONG))
{
*ret_size = sizeof(ULONG);
return STATUS_BUFFER_TOO_SMALL;
}
if (buf) *(ULONG *)buf = value;
*ret_size = sizeof(ULONG);
return STATUS_SUCCESS;
}
static NTSTATUS get_hash_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
{
NTSTATUS status;
status = generic_alg_property( id, prop, buf, size, ret_size );
if (status == STATUS_NOT_IMPLEMENTED)
FIXME( "unsupported property %s\n", debugstr_w(prop) );
return status;
}
NTSTATUS WINAPI BCryptGetProperty( BCRYPT_HANDLE handle, LPCWSTR prop, UCHAR *buffer, ULONG count, ULONG *res, ULONG flags )
{
struct object *object = handle;
TRACE( "%p, %s, %p, %u, %p, %08x\n", handle, wine_dbgstr_w(prop), buffer, count, res, flags );
if (!object) return STATUS_INVALID_HANDLE;
if (!prop || !res) return STATUS_INVALID_PARAMETER;
switch (object->magic)
{
case MAGIC_ALG:
{
const struct algorithm *alg = (const struct algorithm *)object;
return get_alg_property( alg->id, prop, buffer, count, res );
}
case MAGIC_HASH:
{
const struct hash *hash = (const struct hash *)object;
return get_hash_property( hash->alg_id, prop, buffer, count, res );
}
default:
WARN( "unknown magic %08x\n", object->magic );
return STATUS_INVALID_HANDLE;
}
}
NTSTATUS WINAPI BCryptCreateHash( BCRYPT_ALG_HANDLE algorithm, BCRYPT_HASH_HANDLE *handle, UCHAR *object, ULONG objectlen,
UCHAR *secret, ULONG secretlen, ULONG flags )
{
struct algorithm *alg = algorithm;
struct hash *hash;
NTSTATUS status;
TRACE( "%p, %p, %p, %u, %p, %u, %08x - stub\n", algorithm, handle, object, objectlen,
secret, secretlen, flags );
if (flags)
{
FIXME( "unimplemented flags %08x\n", flags );
return STATUS_NOT_IMPLEMENTED;
}
if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
if (object) FIXME( "ignoring object buffer\n" );
if (!(hash = HeapAlloc( GetProcessHeap(), 0, sizeof(*hash) ))) return STATUS_NO_MEMORY;
hash->hdr.magic = MAGIC_HASH;
hash->alg_id = alg->id;
hash->hmac = alg->hmac;
if (hash->hmac)
{
status = hmac_init( hash, secret, secretlen );
}
else
{
status = hash_init( hash );
}
if (status != STATUS_SUCCESS)
{
HeapFree( GetProcessHeap(), 0, hash );
return status;
}
*handle = hash;
return STATUS_SUCCESS;
}
NTSTATUS WINAPI BCryptDestroyHash( BCRYPT_HASH_HANDLE handle )
{
struct hash *hash = handle;
TRACE( "%p\n", handle );
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
HeapFree( GetProcessHeap(), 0, hash );
return STATUS_SUCCESS;
}
NTSTATUS WINAPI BCryptHashData( BCRYPT_HASH_HANDLE handle, UCHAR *input, ULONG size, ULONG flags )
{
struct hash *hash = handle;
TRACE( "%p, %p, %u, %08x\n", handle, input, size, flags );
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
if (!input) return STATUS_SUCCESS;
if (hash->hmac)
{
return hmac_update( hash, input, size );
}
else
{
return hash_update( hash, input, size );
}
}
NTSTATUS WINAPI BCryptFinishHash( BCRYPT_HASH_HANDLE handle, UCHAR *output, ULONG size, ULONG flags )
{
struct hash *hash = handle;
TRACE( "%p, %p, %u, %08x\n", handle, output, size, flags );
if (!hash || hash->hdr.magic != MAGIC_HASH) return STATUS_INVALID_HANDLE;
if (!output) return STATUS_INVALID_PARAMETER;
if (hash->hmac)
{
return hmac_finish( hash, output, size );
}
else
{
return hash_finish( hash, output, size );
}
}
NTSTATUS WINAPI BCryptHash( BCRYPT_ALG_HANDLE algorithm, UCHAR *secret, ULONG secretlen,
UCHAR *input, ULONG inputlen, UCHAR *output, ULONG outputlen )
{
NTSTATUS status;
BCRYPT_HASH_HANDLE handle;
TRACE( "%p, %p, %u, %p, %u, %p, %u\n", algorithm, secret, secretlen,
input, inputlen, output, outputlen );
status = BCryptCreateHash( algorithm, &handle, NULL, 0, secret, secretlen, 0);
if (status != STATUS_SUCCESS)
{
return status;
}
status = BCryptHashData( handle, input, inputlen, 0 );
if (status != STATUS_SUCCESS)
{
BCryptDestroyHash( handle );
return status;
}
status = BCryptFinishHash( handle, output, outputlen, 0 );
if (status != STATUS_SUCCESS)
{
BCryptDestroyHash( handle );
return status;
}
return BCryptDestroyHash( handle );
}
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
instance = hinst;
DisableThreadLibraryCalls( hinst );
#if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
gnutls_initialize();
#elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
mbedtls_initialize();
#endif
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
#if defined(HAVE_GNUTLS_HASH) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
gnutls_uninitialize();
#elif defined(SONAME_LIBMBEDTLS) && !defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H) && !defined(__REACTOS__)
mbedtls_uninitialize();
#endif
break;
}
return TRUE;
}