secur32: Implement SECPKG_ATTR_CIPHER_INFO.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53180
This commit is contained in:
Hans Leidekker 2022-06-20 20:06:55 +02:00 committed by Alexandre Julliard
parent 4ce39cd09b
commit 99e2f4caca
4 changed files with 266 additions and 0 deletions

View file

@ -1244,6 +1244,12 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
struct get_application_protocol_params params = { ctx->session, protocol };
return GNUTLS_CALL( get_application_protocol, &params );
}
case SECPKG_ATTR_CIPHER_INFO:
{
SecPkgContext_CipherInfo *info = buffer;
struct get_cipher_info_params params = { ctx->session, info };
return GNUTLS_CALL( get_cipher_info, &params );
}
default:
FIXME("Unhandled attribute %#lx\n", attribute);
@ -1282,6 +1288,8 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA(
return schan_QueryContextAttributesW(context_handle, attribute, buffer);
case SECPKG_ATTR_APPLICATION_PROTOCOL:
return schan_QueryContextAttributesW(context_handle, attribute, buffer);
case SECPKG_ATTR_CIPHER_INFO:
return schan_QueryContextAttributesW(context_handle, attribute, buffer);
default:
FIXME("Unhandled attribute %#lx\n", attribute);

View file

@ -698,6 +698,211 @@ static NTSTATUS schan_get_connection_info( void *args )
return SEC_E_OK;
}
static DWORD get_protocol_version( gnutls_session_t session )
{
gnutls_protocol_t proto = pgnutls_protocol_get_version( session );
switch (proto)
{
case GNUTLS_SSL3: return 0x300;
case GNUTLS_TLS1_0: return 0x301;
case GNUTLS_TLS1_1: return 0x302;
case GNUTLS_TLS1_2: return 0x303;
case GNUTLS_DTLS1_0: return 0x201;
case GNUTLS_DTLS1_2: return 0x202;
default:
FIXME( "unknown protocol %u\n", proto );
return 0;
}
}
static const WCHAR *get_cipher_str( gnutls_session_t session )
{
static const WCHAR aesW[] = {'A','E','S',0};
static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
switch (cipher)
{
case GNUTLS_CIPHER_AES_128_CBC:
case GNUTLS_CIPHER_AES_192_CBC:
case GNUTLS_CIPHER_AES_256_CBC:
case GNUTLS_CIPHER_AES_128_GCM:
case GNUTLS_CIPHER_AES_256_GCM:
case GNUTLS_CIPHER_AES_128_CCM:
case GNUTLS_CIPHER_AES_256_CCM:
return aesW;
default:
FIXME( "unknown cipher %u\n", cipher );
return unknownW;
}
}
static DWORD get_cipher_len( gnutls_session_t session )
{
gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
switch (cipher)
{
case GNUTLS_CIPHER_AES_128_CBC:
case GNUTLS_CIPHER_AES_128_GCM:
case GNUTLS_CIPHER_AES_128_CCM:
return 128;
case GNUTLS_CIPHER_AES_192_CBC:
return 192;
case GNUTLS_CIPHER_AES_256_CBC:
case GNUTLS_CIPHER_AES_256_GCM:
case GNUTLS_CIPHER_AES_256_CCM:
return 256;
default:
FIXME( "unknown cipher %u\n", cipher );
return 0;
}
}
static DWORD get_cipher_block_len( gnutls_session_t session )
{
gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
return pgnutls_cipher_get_block_size( cipher );
}
static const WCHAR *get_hash_str( gnutls_session_t session, BOOL full )
{
static const WCHAR shaW[] = {'S','H','A',0};
static const WCHAR sha1W[] = {'S','H','A','1',0};
static const WCHAR sha224W[] = {'S','H','A','2','2','4',0};
static const WCHAR sha256W[] = {'S','H','A','2','5','6',0};
static const WCHAR sha384W[] = {'S','H','A','3','8','4',0};
static const WCHAR sha512W[] = {'S','H','A','5','1','2',0};
static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
gnutls_mac_algorithm_t mac = pgnutls_mac_get( session );
switch (mac)
{
case GNUTLS_MAC_SHA1: return full ? sha1W : shaW;
case GNUTLS_MAC_SHA224: return sha224W;
case GNUTLS_MAC_SHA256: return sha256W;
case GNUTLS_MAC_SHA384: return sha384W;
case GNUTLS_MAC_SHA512: return sha512W;
default:
FIXME( "unknown mac %u\n", mac );
return unknownW;
}
}
static DWORD get_hash_len( gnutls_session_t session )
{
gnutls_mac_algorithm_t mac = pgnutls_mac_get( session );
return pgnutls_mac_get_key_size( mac ) * 8;
}
static const WCHAR *get_exchange_str( gnutls_session_t session, BOOL full )
{
static const WCHAR ecdhW[] = {'E','C','D','H',0};
static const WCHAR ecdheW[] = {'E','C','D','H','E',0};
static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
gnutls_kx_algorithm_t kx = pgnutls_kx_get( session );
switch (kx)
{
case GNUTLS_KX_ECDHE_RSA:
case GNUTLS_KX_ECDHE_ECDSA:
return full ? ecdheW : ecdhW;
default:
FIXME( "unknown kx %u\n", kx );
return unknownW;
}
}
static const WCHAR *get_certificate_str( gnutls_session_t session )
{
static const WCHAR rsaW[] = {'R','S','A',0};
static const WCHAR ecdsaW[] = {'E','C','D','S','A',0};
static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
gnutls_kx_algorithm_t kx = pgnutls_kx_get( session );
switch (kx)
{
case GNUTLS_KX_RSA:
case GNUTLS_KX_RSA_EXPORT:
case GNUTLS_KX_DHE_RSA:
case GNUTLS_KX_ECDHE_RSA: return rsaW;
case GNUTLS_KX_ECDHE_ECDSA: return ecdsaW;
default:
FIXME( "unknown kx %u\n", kx );
return unknownW;
}
}
static const WCHAR *get_chaining_mode_str( gnutls_session_t session )
{
static const WCHAR cbcW[] = {'C','B','C',0};
static const WCHAR ccmW[] = {'C','C','M',0};
static const WCHAR gcmW[] = {'G','C','M',0};
static const WCHAR unknownW[] = {'<','u','n','k','n','o','w','n','>',0};
gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get( session );
switch (cipher)
{
case GNUTLS_CIPHER_AES_128_CBC:
case GNUTLS_CIPHER_AES_192_CBC:
case GNUTLS_CIPHER_AES_256_CBC:
return cbcW;
case GNUTLS_CIPHER_AES_128_GCM:
case GNUTLS_CIPHER_AES_256_GCM:
return gcmW;
case GNUTLS_CIPHER_AES_128_CCM:
case GNUTLS_CIPHER_AES_256_CCM:
return ccmW;
default:
FIXME( "unknown cipher %u\n", cipher );
return unknownW;
}
}
static NTSTATUS schan_get_cipher_info( void *args )
{
const WCHAR tlsW[] = {'T','L','S','_',0};
const WCHAR underscoreW[] = {'_',0};
const WCHAR widthW[] = {'_','W','I','T','H','_',0};
const struct get_cipher_info_params *params = args;
gnutls_session_t session = session_from_handle( params->session );
SecPkgContext_CipherInfo *info = params->info;
char buf[11];
WCHAR *ptr;
int len;
info->dwProtocol = get_protocol_version( session );
info->dwCipherSuite = 0; /* FIXME */
info->dwBaseCipherSuite = 0; /* FIXME */
wcscpy( info->szCipher, get_cipher_str( session ) );
info->dwCipherLen = get_cipher_len( session );
info->dwCipherBlockLen = get_cipher_block_len( session );
wcscpy( info->szHash, get_hash_str( session, TRUE ) );
info->dwHashLen = get_hash_len( session );
wcscpy( info->szExchange, get_exchange_str( session, FALSE ) );
info->dwMinExchangeLen = 0;
info->dwMaxExchangeLen = 65536;
wcscpy( info->szCertificate, get_certificate_str( session ) );
info->dwKeyType = 0; /* FIXME */
wcscpy( info->szCipherSuite, tlsW );
wcscat( info->szCipherSuite, get_exchange_str( session, TRUE ) );
wcscat( info->szCipherSuite, underscoreW );
wcscat( info->szCipherSuite, info->szCertificate );
wcscat( info->szCipherSuite, widthW );
wcscat( info->szCipherSuite, info->szCipher );
wcscat( info->szCipherSuite, underscoreW );
len = sprintf( buf, "%u", (unsigned int)info->dwCipherLen ) + 1;
ptr = info->szCipherSuite + wcslen( info->szCipherSuite );
ntdll_umbstowcs( buf, len, ptr, len );
wcscat( info->szCipherSuite, underscoreW );
wcscat( info->szCipherSuite, get_chaining_mode_str( session ) );
wcscat( info->szCipherSuite, underscoreW );
wcscat( info->szCipherSuite, get_hash_str( session, FALSE ) );
return SEC_E_OK;
}
static NTSTATUS schan_get_unique_channel_binding( void *args )
{
const struct get_unique_channel_binding_params *params = args;
@ -1271,6 +1476,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
schan_dispose_session,
schan_free_certificate_credentials,
schan_get_application_protocol,
schan_get_cipher_info,
schan_get_connection_info,
schan_get_enabled_protocols,
schan_get_key_signature_algorithm,
@ -1386,6 +1592,21 @@ static NTSTATUS wow64_schan_get_connection_info( void *args )
return schan_get_connection_info(&params);
}
static NTSTATUS wow64_schan_get_cipher_info( void *args )
{
struct
{
schan_session session;
PTR32 info;
} const *params32 = args;
struct get_cipher_info_params params =
{
params32->session,
ULongToPtr(params32->info),
};
return schan_get_cipher_info(&params);
}
static NTSTATUS wow64_schan_get_session_peer_certificate( void *args )
{
struct
@ -1582,6 +1803,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
schan_dispose_session,
wow64_schan_free_certificate_credentials,
wow64_schan_get_application_protocol,
wow64_schan_get_cipher_info,
wow64_schan_get_connection_info,
schan_get_enabled_protocols,
schan_get_key_signature_algorithm,

View file

@ -126,6 +126,12 @@ struct get_connection_info_params
SecPkgContext_ConnectionInfo *info;
};
struct get_cipher_info_params
{
schan_session session;
SecPkgContext_CipherInfo *info;
};
struct get_session_peer_certificate_params
{
schan_session session;
@ -206,6 +212,7 @@ enum schan_funcs
unix_dispose_session,
unix_free_certificate_credentials,
unix_get_application_protocol,
unix_get_cipher_info,
unix_get_connection_info,
unix_get_enabled_protocols,
unix_get_key_signature_algorithm,

View file

@ -1038,6 +1038,7 @@ static void test_communication(void)
CRYPT_DATA_BLOB pfx;
HCERTSTORE store;
SecPkgContext_NegotiationInfoA info;
SecPkgContext_CipherInfo cipher;
SecBufferDesc buffers[2];
SecBuffer *buf;
unsigned buf_size = 8192;
@ -1291,6 +1292,34 @@ static void test_communication(void)
ok(conn_info.dwHashStrength >= 128, "conn_info.dwHashStrength = %ld\n", conn_info.dwHashStrength);
}
memset(&cipher, 0, sizeof(cipher));
cipher.dwVersion = SECPKGCONTEXT_CIPHERINFO_V1;
status = pQueryContextAttributesA(&context, SECPKG_ATTR_CIPHER_INFO, &cipher);
ok(status == SEC_E_OK || broken(status == SEC_E_UNSUPPORTED_FUNCTION) /* < vista */, "got %08lx\n", status);
if (status == SEC_E_OK)
{
ok(cipher.dwProtocol == 0x301, "got %lx\n", cipher.dwProtocol);
todo_wine ok(cipher.dwCipherSuite == 0xc014, "got %lx\n", cipher.dwCipherSuite);
todo_wine ok(cipher.dwBaseCipherSuite == 0xc014, "got %lx\n", cipher.dwBaseCipherSuite);
ok(!wcscmp(cipher.szCipherSuite, L"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA") ||
!wcscmp(cipher.szCipherSuite, L"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256"), /* < win10 */
"got %s\n", wine_dbgstr_w(cipher.szCipherSuite));
ok(!wcscmp(cipher.szCipher, L"AES"), "got %s\n", wine_dbgstr_w(cipher.szCipher));
ok(cipher.dwCipherLen == 256, "got %lu\n", cipher.dwCipherLen);
ok(cipher.dwCipherBlockLen == 16, "got %lu\n", cipher.dwCipherBlockLen);
ok(!wcscmp(cipher.szHash, L"SHA1"), "got %s\n", wine_dbgstr_w(cipher.szHash));
ok(cipher.dwHashLen == 160, "got %lu\n", cipher.dwHashLen);
ok(!wcscmp(cipher.szExchange, L"ECDH") || !wcscmp(cipher.szExchange, L"ECDH_P256"), /* < win10 */
"got %s\n", wine_dbgstr_w(cipher.szExchange));
ok(cipher.dwMinExchangeLen == 0 || cipher.dwMinExchangeLen == 256, /* < win10 */
"got %lu\n", cipher.dwMinExchangeLen);
ok(cipher.dwMaxExchangeLen == 65536 || cipher.dwMaxExchangeLen == 256, /* < win10 */
"got %lu\n", cipher.dwMaxExchangeLen);
ok(!wcscmp(cipher.szCertificate, L"RSA"), "got %s\n", wine_dbgstr_w(cipher.szCertificate));
todo_wine ok(cipher.dwKeyType == 0x1d || cipher.dwKeyType == 0x17, /* < win10 */
"got %#lx\n", cipher.dwKeyType);
}
status = pQueryContextAttributesA(&context, SECPKG_ATTR_KEY_INFO, &key_info);
ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_KEY_INFO) failed: %08lx\n", status);
if(status == SEC_E_OK) {