fragattacks/src/crypto/tls_schannel.c
Jouni Malinen 224104ddf6 TLS: Reject openssl_ciphers parameter in non-OpenSSL cases
This TLS configuration parameter is explicitly for OpenSSL. Instead of
ignoring it silently, reject any configuration trying to use it in
builds that use other options for TLS implementation.

Signed-off-by: Jouni Malinen <j@w1.fi>
2015-01-11 01:35:54 +02:00

753 lines
19 KiB
C

/*
* SSL/TLS interface functions for Microsoft Schannel
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
/*
* FIX: Go through all SSPI functions and verify what needs to be freed
* FIX: session resumption
* TODO: add support for server cert chain validation
* TODO: add support for CA cert validation
* TODO: add support for EAP-TLS (client cert/key conf)
*/
#include "includes.h"
#include <windows.h>
#include <wincrypt.h>
#include <schannel.h>
#define SECURITY_WIN32
#include <security.h>
#include <sspi.h>
#include "common.h"
#include "tls.h"
struct tls_global {
HMODULE hsecurity;
PSecurityFunctionTable sspi;
HCERTSTORE my_cert_store;
};
struct tls_connection {
int established, start;
int failed, read_alerts, write_alerts;
SCHANNEL_CRED schannel_cred;
CredHandle creds;
CtxtHandle context;
u8 eap_tls_prf[128];
int eap_tls_prf_set;
};
static int schannel_load_lib(struct tls_global *global)
{
INIT_SECURITY_INTERFACE pInitSecurityInterface;
global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
if (global->hsecurity == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
global->hsecurity, "InitSecurityInterfaceA");
if (pInitSecurityInterface == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not find "
"InitSecurityInterfaceA from Secur32.dll",
__func__);
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
global->sspi = pInitSecurityInterface();
if (global->sspi == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not read security "
"interface - 0x%x",
__func__, (unsigned int) GetLastError());
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
return 0;
}
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
if (schannel_load_lib(global)) {
os_free(global);
return NULL;
}
return global;
}
void tls_deinit(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
if (global->my_cert_store)
CertCloseStore(global->my_cert_store, 0);
FreeLibrary(global->hsecurity);
os_free(global);
}
int tls_get_errors(void *ssl_ctx)
{
return 0;
}
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_connection *conn;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->start = 1;
return conn;
}
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
os_free(conn);
}
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? conn->established : 0;
}
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
if (conn == NULL)
return -1;
conn->eap_tls_prf_set = 0;
conn->established = conn->failed = 0;
conn->read_alerts = conn->write_alerts = 0;
global->sspi->DeleteSecurityContext(&conn->context);
/* FIX: what else needs to be reseted? */
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
return -1;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
return -1;
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
/* Schannel does not export master secret or client/server random. */
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
/*
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
* EAP-TTLS cannot use this, though, since they are using different
* labels. The only option could be to implement TLSv1 completely here
* and just use Schannel or CryptoAPI for low-level crypto
* functionality..
*/
if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
os_strcmp(label, "client EAP encryption") != 0 ||
out_len > sizeof(conn->eap_tls_prf))
return -1;
os_memcpy(out, conn->eap_tls_prf, out_len);
return 0;
}
static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
struct tls_connection *conn)
{
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc outbuf;
SecBuffer outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
outbufs[0].pvBuffer = NULL;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbufs[0].cbBuffer = 0;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_I_CONTINUE_NEEDED) {
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
"failed - 0x%x",
__func__, (unsigned int) status);
return NULL;
}
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
struct wpabuf *buf;
wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
conn->start = 0;
buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
if (buf == NULL)
return NULL;
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
return buf;
}
wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
return NULL;
}
#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
typedef struct _SecPkgContext_EapKeyBlock {
BYTE rgbKeys[128];
BYTE rgbIVs[64];
} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
{
SECURITY_STATUS status;
SecPkgContext_EapKeyBlock kb;
/* Note: Windows NT and Windows Me/98/95 do not support getting
* EapKeyBlock */
status = global->sspi->QueryContextAttributes(
&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
"SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
__func__, (int) status);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
kb.rgbKeys, sizeof(kb.rgbKeys));
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
kb.rgbIVs, sizeof(kb.rgbIVs));
os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
conn->eap_tls_prf_set = 1;
return 0;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
struct tls_global *global = tls_ctx;
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc inbuf, outbuf;
SecBuffer inbufs[2], outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
struct wpabuf *out_buf = NULL;
if (appl_data)
*appl_data = NULL;
if (conn->start)
return tls_conn_hs_clienthello(global, conn);
wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
(int) wpabuf_len(in_data));
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
/* Input buffer for Schannel */
inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
inbufs[0].cbBuffer = wpabuf_len(in_data);
inbufs[0].BufferType = SECBUFFER_TOKEN;
/* Place for leftover data from Schannel */
inbufs[1].pvBuffer = NULL;
inbufs[1].cbBuffer = 0;
inbufs[1].BufferType = SECBUFFER_EMPTY;
inbuf.cBuffers = 2;
inbuf.pBuffers = inbufs;
inbuf.ulVersion = SECBUFFER_VERSION;
/* Output buffer for Schannel */
outbufs[0].pvBuffer = NULL;
outbufs[0].cbBuffer = 0;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
"intype[1]=%d outlen[0]=%d",
(int) status, (int) inbufs[0].cbBuffer,
(int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
(int) inbufs[1].BufferType,
(int) outbufs[0].cbBuffer);
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
(FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
outbufs[0].pvBuffer = NULL;
if (out_buf == NULL)
return NULL;
}
}
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
break;
case SEC_I_CONTINUE_NEEDED:
wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
break;
case SEC_E_OK:
/* TODO: verify server certificate chain */
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
"completed successfully");
conn->established = 1;
tls_get_eap(global, conn);
/* Need to return something to get final TLS ACK. */
if (out_buf == NULL)
out_buf = wpabuf_alloc(0);
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
"application data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
if (appl_data) {
*appl_data = wpabuf_alloc_copy(
outbufs[1].pvBuffer,
outbufs[1].cbBuffer);
}
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
break;
case SEC_I_INCOMPLETE_CREDENTIALS:
wpa_printf(MSG_DEBUG,
"Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
break;
case SEC_E_WRONG_PRINCIPAL:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
break;
case SEC_E_INTERNAL_ERROR:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
break;
}
if (FAILED(status)) {
wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
"(out_buf=%p)", out_buf);
conn->failed++;
global->sspi->DeleteSecurityContext(&conn->context);
return out_buf;
}
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
/* TODO: Can this happen? What to do with this data? */
wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
return out_buf;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
SecPkgContext_StreamSizes sizes;
int i;
struct wpabuf *out;
status = global->sspi->QueryContextAttributes(&conn->context,
SECPKG_ATTR_STREAM_SIZES,
&sizes);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
__func__);
return NULL;
}
wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
__func__,
(unsigned int) sizes.cbHeader,
(unsigned int) sizes.cbTrailer);
out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
sizes.cbTrailer);
os_memset(&bufs, 0, sizeof(bufs));
bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
bufs[0].cbBuffer = sizes.cbHeader;
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
bufs[1].pvBuffer = wpabuf_put(out, 0);
wpabuf_put_buf(out, in_data);
bufs[1].cbBuffer = wpabuf_len(in_data);
bufs[1].BufferType = SECBUFFER_DATA;
bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
bufs[2].cbBuffer = sizes.cbTrailer;
bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 3;
buf.pBuffers = bufs;
status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
"out_data=%p bufs %p %p %p",
wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer);
for (i = 0; i < 3; i++) {
if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
{
wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
bufs[i].pvBuffer, bufs[i].cbBuffer);
}
}
if (status == SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
"from EncryptMessage", out);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(out);
return NULL;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
int i;
struct wpabuf *out, *tmp;
wpa_hexdump_buf(MSG_MSGDUMP,
"Schannel: Encrypted data to DecryptMessage", in_data);
os_memset(&bufs, 0, sizeof(bufs));
tmp = wpabuf_dup(in_data);
if (tmp == NULL)
return NULL;
bufs[0].pvBuffer = wpabuf_mhead(tmp);
bufs[0].cbBuffer = wpabuf_len(in_data);
bufs[0].BufferType = SECBUFFER_DATA;
bufs[1].BufferType = SECBUFFER_EMPTY;
bufs[2].BufferType = SECBUFFER_EMPTY;
bufs[3].BufferType = SECBUFFER_EMPTY;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 4;
buf.pBuffers = bufs;
status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
NULL);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
(int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
"out_data=%p bufs %p %p %p %p",
wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer, bufs[3].pvBuffer);
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
__func__);
break;
case SEC_E_OK:
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
for (i = 0; i < 4; i++) {
if (bufs[i].BufferType == SECBUFFER_DATA)
break;
}
if (i == 4) {
wpa_printf(MSG_DEBUG, "%s: No output data from "
"DecryptMessage", __func__);
wpabuf_free(tmp);
return NULL;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
"DecryptMessage",
bufs[i].pvBuffer, bufs[i].cbBuffer);
out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
wpabuf_free(tmp);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(tmp);
return NULL;
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
return -1;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_connection_enable_workaround(void *ssl_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
return -1;
}
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->failed;
}
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->read_alerts;
}
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->write_alerts;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
ALG_ID algs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
if (conn == NULL)
return -1;
if (params->subject_match) {
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
return -1;
}
if (params->altsubject_match) {
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
return -1;
}
if (params->suffix_match) {
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
return -1;
}
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
return -1;
}
if (global->my_cert_store == NULL &&
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
NULL) {
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
algs[0] = CALG_RSA_KEYX;
conn->schannel_cred.cSupportedAlgs = 1;
conn->schannel_cred.palgSupportedAlgs = algs;
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
#ifdef UNICODE
status = global->sspi->AcquireCredentialsHandleW(
NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#else /* UNICODE */
status = global->sspi->AcquireCredentialsHandleA(
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
"0x%x", __func__, (unsigned int) status);
return -1;
}
return 0;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}