wpa_supplicant: Initial Revision 0.8.X

Based on:
commit 0725cc7b7efc434910e89865c42eda7ce61bbf08
Author: Jouni Malinen <j@w1.fi>
Date:   Thu Apr 21 20:41:01 2011 +0300

    Enable CONFIG_DRIVER_NL80211=y in the default configuration

    nl80211 should be preferred over WEXT with any recent Linux
    kernel version.

Change-Id: I26aec5afbbd4f4a1f5fd900912545b6f5050de64
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
new file mode 100644
index 0000000..4a94e99
--- /dev/null
+++ b/src/crypto/tls_schannel.c
@@ -0,0 +1,767 @@
+/*
+ * SSL/TLS interface functions for Microsoft Schannel
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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 (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;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+			  int tls_ia)
+{
+	return -1;
+}
+
+
+struct wpabuf * tls_connection_ia_send_phase_finished(
+	void *tls_ctx, struct tls_connection *conn, int final);
+{
+	return NULL;
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+					   struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const u8 *key, size_t key_len)
+{
+	return -1;
+}