1189251Ssam/*
2214734Srpaulo * SSL/TLS interface functions for Microsoft Schannel
3214734Srpaulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam/*
16189251Ssam * FIX: Go through all SSPI functions and verify what needs to be freed
17189251Ssam * FIX: session resumption
18189251Ssam * TODO: add support for server cert chain validation
19189251Ssam * TODO: add support for CA cert validation
20189251Ssam * TODO: add support for EAP-TLS (client cert/key conf)
21189251Ssam */
22189251Ssam
23189251Ssam#include "includes.h"
24189251Ssam#include <windows.h>
25189251Ssam#include <wincrypt.h>
26189251Ssam#include <schannel.h>
27189251Ssam#define SECURITY_WIN32
28189251Ssam#include <security.h>
29189251Ssam#include <sspi.h>
30189251Ssam
31189251Ssam#include "common.h"
32189251Ssam#include "tls.h"
33189251Ssam
34189251Ssam
35189251Ssamstruct tls_global {
36189251Ssam	HMODULE hsecurity;
37189251Ssam	PSecurityFunctionTable sspi;
38189251Ssam	HCERTSTORE my_cert_store;
39189251Ssam};
40189251Ssam
41189251Ssamstruct tls_connection {
42189251Ssam	int established, start;
43189251Ssam	int failed, read_alerts, write_alerts;
44189251Ssam
45189251Ssam	SCHANNEL_CRED schannel_cred;
46189251Ssam	CredHandle creds;
47189251Ssam	CtxtHandle context;
48189251Ssam
49189251Ssam	u8 eap_tls_prf[128];
50189251Ssam	int eap_tls_prf_set;
51189251Ssam};
52189251Ssam
53189251Ssam
54189251Ssamstatic int schannel_load_lib(struct tls_global *global)
55189251Ssam{
56189251Ssam	INIT_SECURITY_INTERFACE pInitSecurityInterface;
57189251Ssam
58189251Ssam	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
59189251Ssam	if (global->hsecurity == NULL) {
60189251Ssam		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
61189251Ssam			   __func__, (unsigned int) GetLastError());
62189251Ssam		return -1;
63189251Ssam	}
64189251Ssam
65189251Ssam	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
66189251Ssam		global->hsecurity, "InitSecurityInterfaceA");
67189251Ssam	if (pInitSecurityInterface == NULL) {
68189251Ssam		wpa_printf(MSG_ERROR, "%s: Could not find "
69189251Ssam			   "InitSecurityInterfaceA from Secur32.dll",
70189251Ssam			   __func__);
71189251Ssam		FreeLibrary(global->hsecurity);
72189251Ssam		global->hsecurity = NULL;
73189251Ssam		return -1;
74189251Ssam	}
75189251Ssam
76189251Ssam	global->sspi = pInitSecurityInterface();
77189251Ssam	if (global->sspi == NULL) {
78189251Ssam		wpa_printf(MSG_ERROR, "%s: Could not read security "
79189251Ssam			   "interface - 0x%x",
80189251Ssam			   __func__, (unsigned int) GetLastError());
81189251Ssam		FreeLibrary(global->hsecurity);
82189251Ssam		global->hsecurity = NULL;
83189251Ssam		return -1;
84189251Ssam	}
85189251Ssam
86189251Ssam	return 0;
87189251Ssam}
88189251Ssam
89189251Ssam
90189251Ssamvoid * tls_init(const struct tls_config *conf)
91189251Ssam{
92189251Ssam	struct tls_global *global;
93189251Ssam
94189251Ssam	global = os_zalloc(sizeof(*global));
95189251Ssam	if (global == NULL)
96189251Ssam		return NULL;
97189251Ssam	if (schannel_load_lib(global)) {
98189251Ssam		os_free(global);
99189251Ssam		return NULL;
100189251Ssam	}
101189251Ssam	return global;
102189251Ssam}
103189251Ssam
104189251Ssam
105189251Ssamvoid tls_deinit(void *ssl_ctx)
106189251Ssam{
107189251Ssam	struct tls_global *global = ssl_ctx;
108189251Ssam
109189251Ssam	if (global->my_cert_store)
110189251Ssam		CertCloseStore(global->my_cert_store, 0);
111189251Ssam	FreeLibrary(global->hsecurity);
112189251Ssam	os_free(global);
113189251Ssam}
114189251Ssam
115189251Ssam
116189251Ssamint tls_get_errors(void *ssl_ctx)
117189251Ssam{
118189251Ssam	return 0;
119189251Ssam}
120189251Ssam
121189251Ssam
122189251Ssamstruct tls_connection * tls_connection_init(void *ssl_ctx)
123189251Ssam{
124189251Ssam	struct tls_connection *conn;
125189251Ssam
126189251Ssam	conn = os_zalloc(sizeof(*conn));
127189251Ssam	if (conn == NULL)
128189251Ssam		return NULL;
129189251Ssam	conn->start = 1;
130189251Ssam
131189251Ssam	return conn;
132189251Ssam}
133189251Ssam
134189251Ssam
135189251Ssamvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
136189251Ssam{
137189251Ssam	if (conn == NULL)
138189251Ssam		return;
139189251Ssam
140189251Ssam	os_free(conn);
141189251Ssam}
142189251Ssam
143189251Ssam
144189251Ssamint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
145189251Ssam{
146189251Ssam	return conn ? conn->established : 0;
147189251Ssam}
148189251Ssam
149189251Ssam
150189251Ssamint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
151189251Ssam{
152189251Ssam	struct tls_global *global = ssl_ctx;
153189251Ssam	if (conn == NULL)
154189251Ssam		return -1;
155189251Ssam
156189251Ssam	conn->eap_tls_prf_set = 0;
157189251Ssam	conn->established = conn->failed = 0;
158189251Ssam	conn->read_alerts = conn->write_alerts = 0;
159189251Ssam	global->sspi->DeleteSecurityContext(&conn->context);
160189251Ssam	/* FIX: what else needs to be reseted? */
161189251Ssam
162189251Ssam	return 0;
163189251Ssam}
164189251Ssam
165189251Ssam
166189251Ssamint tls_global_set_params(void *tls_ctx,
167189251Ssam			  const struct tls_connection_params *params)
168189251Ssam{
169189251Ssam	return -1;
170189251Ssam}
171189251Ssam
172189251Ssam
173189251Ssamint tls_global_set_verify(void *ssl_ctx, int check_crl)
174189251Ssam{
175189251Ssam	return -1;
176189251Ssam}
177189251Ssam
178189251Ssam
179189251Ssamint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
180189251Ssam			      int verify_peer)
181189251Ssam{
182189251Ssam	return -1;
183189251Ssam}
184189251Ssam
185189251Ssam
186189251Ssamint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
187189251Ssam			    struct tls_keys *keys)
188189251Ssam{
189189251Ssam	/* Schannel does not export master secret or client/server random. */
190189251Ssam	return -1;
191189251Ssam}
192189251Ssam
193189251Ssam
194189251Ssamint tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
195189251Ssam		       const char *label, int server_random_first,
196189251Ssam		       u8 *out, size_t out_len)
197189251Ssam{
198189251Ssam	/*
199189251Ssam	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
200189251Ssam	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
201189251Ssam	 * EAP-TTLS cannot use this, though, since they are using different
202189251Ssam	 * labels. The only option could be to implement TLSv1 completely here
203189251Ssam	 * and just use Schannel or CryptoAPI for low-level crypto
204189251Ssam	 * functionality..
205189251Ssam	 */
206189251Ssam
207189251Ssam	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
208189251Ssam	    os_strcmp(label, "client EAP encryption") != 0 ||
209189251Ssam	    out_len > sizeof(conn->eap_tls_prf))
210189251Ssam		return -1;
211189251Ssam
212189251Ssam	os_memcpy(out, conn->eap_tls_prf, out_len);
213189251Ssam
214189251Ssam	return 0;
215189251Ssam}
216189251Ssam
217189251Ssam
218214734Srpaulostatic struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
219214734Srpaulo					       struct tls_connection *conn)
220189251Ssam{
221189251Ssam	DWORD sspi_flags, sspi_flags_out;
222189251Ssam	SecBufferDesc outbuf;
223189251Ssam	SecBuffer outbufs[1];
224189251Ssam	SECURITY_STATUS status;
225189251Ssam	TimeStamp ts_expiry;
226189251Ssam
227189251Ssam	sspi_flags = ISC_REQ_REPLAY_DETECT |
228189251Ssam		ISC_REQ_CONFIDENTIALITY |
229189251Ssam		ISC_RET_EXTENDED_ERROR |
230189251Ssam		ISC_REQ_ALLOCATE_MEMORY |
231189251Ssam		ISC_REQ_MANUAL_CRED_VALIDATION;
232189251Ssam
233189251Ssam	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
234189251Ssam
235189251Ssam	outbufs[0].pvBuffer = NULL;
236189251Ssam	outbufs[0].BufferType = SECBUFFER_TOKEN;
237189251Ssam	outbufs[0].cbBuffer = 0;
238189251Ssam
239189251Ssam	outbuf.cBuffers = 1;
240189251Ssam	outbuf.pBuffers = outbufs;
241189251Ssam	outbuf.ulVersion = SECBUFFER_VERSION;
242189251Ssam
243189251Ssam#ifdef UNICODE
244189251Ssam	status = global->sspi->InitializeSecurityContextW(
245189251Ssam		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
246189251Ssam		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
247189251Ssam		&outbuf, &sspi_flags_out, &ts_expiry);
248189251Ssam#else /* UNICODE */
249189251Ssam	status = global->sspi->InitializeSecurityContextA(
250189251Ssam		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
251189251Ssam		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
252189251Ssam		&outbuf, &sspi_flags_out, &ts_expiry);
253189251Ssam#endif /* UNICODE */
254189251Ssam	if (status != SEC_I_CONTINUE_NEEDED) {
255189251Ssam		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
256189251Ssam			   "failed - 0x%x",
257189251Ssam			   __func__, (unsigned int) status);
258189251Ssam		return NULL;
259189251Ssam	}
260189251Ssam
261189251Ssam	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
262214734Srpaulo		struct wpabuf *buf;
263189251Ssam		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
264189251Ssam			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
265189251Ssam		conn->start = 0;
266214734Srpaulo		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
267214734Srpaulo					outbufs[0].cbBuffer);
268189251Ssam		if (buf == NULL)
269189251Ssam			return NULL;
270189251Ssam		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
271189251Ssam		return buf;
272189251Ssam	}
273189251Ssam
274189251Ssam	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
275189251Ssam
276189251Ssam	return NULL;
277189251Ssam}
278189251Ssam
279189251Ssam
280189251Ssam#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
281189251Ssam#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
282189251Ssam
283189251Ssamtypedef struct _SecPkgContext_EapKeyBlock {
284189251Ssam	BYTE rgbKeys[128];
285189251Ssam	BYTE rgbIVs[64];
286189251Ssam} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
287189251Ssam#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
288189251Ssam
289189251Ssamstatic int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
290189251Ssam{
291189251Ssam	SECURITY_STATUS status;
292189251Ssam	SecPkgContext_EapKeyBlock kb;
293189251Ssam
294189251Ssam	/* Note: Windows NT and Windows Me/98/95 do not support getting
295189251Ssam	 * EapKeyBlock */
296189251Ssam
297189251Ssam	status = global->sspi->QueryContextAttributes(
298189251Ssam		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
299189251Ssam	if (status != SEC_E_OK) {
300189251Ssam		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
301189251Ssam			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
302189251Ssam			   __func__, (int) status);
303189251Ssam		return -1;
304189251Ssam	}
305189251Ssam
306189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
307189251Ssam			kb.rgbKeys, sizeof(kb.rgbKeys));
308189251Ssam	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
309189251Ssam			kb.rgbIVs, sizeof(kb.rgbIVs));
310189251Ssam
311189251Ssam	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
312189251Ssam	conn->eap_tls_prf_set = 1;
313189251Ssam	return 0;
314189251Ssam}
315189251Ssam
316189251Ssam
317214734Srpaulostruct wpabuf * tls_connection_handshake(void *tls_ctx,
318214734Srpaulo					 struct tls_connection *conn,
319214734Srpaulo					 const struct wpabuf *in_data,
320214734Srpaulo					 struct wpabuf **appl_data)
321189251Ssam{
322214734Srpaulo	struct tls_global *global = tls_ctx;
323189251Ssam	DWORD sspi_flags, sspi_flags_out;
324189251Ssam	SecBufferDesc inbuf, outbuf;
325189251Ssam	SecBuffer inbufs[2], outbufs[1];
326189251Ssam	SECURITY_STATUS status;
327189251Ssam	TimeStamp ts_expiry;
328214734Srpaulo	struct wpabuf *out_buf = NULL;
329189251Ssam
330189251Ssam	if (appl_data)
331189251Ssam		*appl_data = NULL;
332189251Ssam
333214734Srpaulo	if (conn->start)
334214734Srpaulo		return tls_conn_hs_clienthello(global, conn);
335189251Ssam
336189251Ssam	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
337214734Srpaulo		   (int) wpabuf_len(in_data));
338189251Ssam
339189251Ssam	sspi_flags = ISC_REQ_REPLAY_DETECT |
340189251Ssam		ISC_REQ_CONFIDENTIALITY |
341189251Ssam		ISC_RET_EXTENDED_ERROR |
342189251Ssam		ISC_REQ_ALLOCATE_MEMORY |
343189251Ssam		ISC_REQ_MANUAL_CRED_VALIDATION;
344189251Ssam
345189251Ssam	/* Input buffer for Schannel */
346214734Srpaulo	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
347214734Srpaulo	inbufs[0].cbBuffer = wpabuf_len(in_data);
348189251Ssam	inbufs[0].BufferType = SECBUFFER_TOKEN;
349189251Ssam
350189251Ssam	/* Place for leftover data from Schannel */
351189251Ssam	inbufs[1].pvBuffer = NULL;
352189251Ssam	inbufs[1].cbBuffer = 0;
353189251Ssam	inbufs[1].BufferType = SECBUFFER_EMPTY;
354189251Ssam
355189251Ssam	inbuf.cBuffers = 2;
356189251Ssam	inbuf.pBuffers = inbufs;
357189251Ssam	inbuf.ulVersion = SECBUFFER_VERSION;
358189251Ssam
359189251Ssam	/* Output buffer for Schannel */
360189251Ssam	outbufs[0].pvBuffer = NULL;
361189251Ssam	outbufs[0].cbBuffer = 0;
362189251Ssam	outbufs[0].BufferType = SECBUFFER_TOKEN;
363189251Ssam
364189251Ssam	outbuf.cBuffers = 1;
365189251Ssam	outbuf.pBuffers = outbufs;
366189251Ssam	outbuf.ulVersion = SECBUFFER_VERSION;
367189251Ssam
368189251Ssam#ifdef UNICODE
369189251Ssam	status = global->sspi->InitializeSecurityContextW(
370189251Ssam		&conn->creds, &conn->context, NULL, sspi_flags, 0,
371189251Ssam		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
372189251Ssam		&outbuf, &sspi_flags_out, &ts_expiry);
373189251Ssam#else /* UNICODE */
374189251Ssam	status = global->sspi->InitializeSecurityContextA(
375189251Ssam		&conn->creds, &conn->context, NULL, sspi_flags, 0,
376189251Ssam		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
377189251Ssam		&outbuf, &sspi_flags_out, &ts_expiry);
378189251Ssam#endif /* UNICODE */
379189251Ssam
380189251Ssam	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
381189251Ssam		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
382189251Ssam		   "intype[1]=%d outlen[0]=%d",
383189251Ssam		   (int) status, (int) inbufs[0].cbBuffer,
384189251Ssam		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
385189251Ssam		   (int) inbufs[1].BufferType,
386189251Ssam		   (int) outbufs[0].cbBuffer);
387189251Ssam	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
388189251Ssam	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
389189251Ssam		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
390189251Ssam			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
391189251Ssam				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
392214734Srpaulo			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
393214734Srpaulo						    outbufs[0].cbBuffer);
394189251Ssam			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
395189251Ssam			outbufs[0].pvBuffer = NULL;
396189251Ssam			if (out_buf == NULL)
397189251Ssam				return NULL;
398189251Ssam		}
399189251Ssam	}
400189251Ssam
401189251Ssam	switch (status) {
402189251Ssam	case SEC_E_INCOMPLETE_MESSAGE:
403189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
404189251Ssam		break;
405189251Ssam	case SEC_I_CONTINUE_NEEDED:
406189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
407189251Ssam		break;
408189251Ssam	case SEC_E_OK:
409189251Ssam		/* TODO: verify server certificate chain */
410189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
411189251Ssam			   "completed successfully");
412189251Ssam		conn->established = 1;
413189251Ssam		tls_get_eap(global, conn);
414189251Ssam
415189251Ssam		/* Need to return something to get final TLS ACK. */
416189251Ssam		if (out_buf == NULL)
417214734Srpaulo			out_buf = wpabuf_alloc(0);
418189251Ssam
419189251Ssam		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
420189251Ssam			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
421189251Ssam				    "application data",
422189251Ssam				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
423189251Ssam			if (appl_data) {
424214734Srpaulo				*appl_data = wpabuf_alloc_copy(
425214734Srpaulo					outbufs[1].pvBuffer,
426214734Srpaulo					outbufs[1].cbBuffer);
427189251Ssam			}
428189251Ssam			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
429189251Ssam			inbufs[1].pvBuffer = NULL;
430189251Ssam		}
431189251Ssam		break;
432189251Ssam	case SEC_I_INCOMPLETE_CREDENTIALS:
433189251Ssam		wpa_printf(MSG_DEBUG,
434189251Ssam			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
435189251Ssam		break;
436189251Ssam	case SEC_E_WRONG_PRINCIPAL:
437189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
438189251Ssam		break;
439189251Ssam	case SEC_E_INTERNAL_ERROR:
440189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
441189251Ssam		break;
442189251Ssam	}
443189251Ssam
444189251Ssam	if (FAILED(status)) {
445189251Ssam		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
446189251Ssam			   "(out_buf=%p)", out_buf);
447189251Ssam		conn->failed++;
448189251Ssam		global->sspi->DeleteSecurityContext(&conn->context);
449189251Ssam		return out_buf;
450189251Ssam	}
451189251Ssam
452189251Ssam	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
453189251Ssam		/* TODO: Can this happen? What to do with this data? */
454189251Ssam		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
455189251Ssam			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
456189251Ssam		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
457189251Ssam		inbufs[1].pvBuffer = NULL;
458189251Ssam	}
459189251Ssam
460189251Ssam	return out_buf;
461189251Ssam}
462189251Ssam
463189251Ssam
464214734Srpaulostruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
465214734Srpaulo						struct tls_connection *conn,
466214734Srpaulo						const struct wpabuf *in_data,
467214734Srpaulo						struct wpabuf **appl_data)
468189251Ssam{
469189251Ssam	return NULL;
470189251Ssam}
471189251Ssam
472189251Ssam
473214734Srpaulostruct wpabuf * tls_connection_encrypt(void *tls_ctx,
474214734Srpaulo				       struct tls_connection *conn,
475214734Srpaulo				       const struct wpabuf *in_data)
476189251Ssam{
477214734Srpaulo	struct tls_global *global = tls_ctx;
478189251Ssam	SECURITY_STATUS status;
479189251Ssam	SecBufferDesc buf;
480189251Ssam	SecBuffer bufs[4];
481189251Ssam	SecPkgContext_StreamSizes sizes;
482189251Ssam	int i;
483214734Srpaulo	struct wpabuf *out;
484189251Ssam
485189251Ssam	status = global->sspi->QueryContextAttributes(&conn->context,
486189251Ssam						      SECPKG_ATTR_STREAM_SIZES,
487189251Ssam						      &sizes);
488189251Ssam	if (status != SEC_E_OK) {
489189251Ssam		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
490189251Ssam			   __func__);
491214734Srpaulo		return NULL;
492189251Ssam	}
493189251Ssam	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
494189251Ssam		   __func__,
495189251Ssam		   (unsigned int) sizes.cbHeader,
496189251Ssam		   (unsigned int) sizes.cbTrailer);
497189251Ssam
498214734Srpaulo	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
499214734Srpaulo			   sizes.cbTrailer);
500189251Ssam
501189251Ssam	os_memset(&bufs, 0, sizeof(bufs));
502214734Srpaulo	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
503189251Ssam	bufs[0].cbBuffer = sizes.cbHeader;
504189251Ssam	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
505189251Ssam
506214734Srpaulo	bufs[1].pvBuffer = wpabuf_put(out, 0);
507214734Srpaulo	wpabuf_put_buf(out, in_data);
508214734Srpaulo	bufs[1].cbBuffer = wpabuf_len(in_data);
509189251Ssam	bufs[1].BufferType = SECBUFFER_DATA;
510189251Ssam
511214734Srpaulo	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
512189251Ssam	bufs[2].cbBuffer = sizes.cbTrailer;
513189251Ssam	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
514189251Ssam
515189251Ssam	buf.ulVersion = SECBUFFER_VERSION;
516189251Ssam	buf.cBuffers = 3;
517189251Ssam	buf.pBuffers = bufs;
518189251Ssam
519189251Ssam	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
520189251Ssam
521189251Ssam	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
522189251Ssam		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
523189251Ssam		   "len[2]=%d type[2]=%d",
524189251Ssam		   (int) status,
525189251Ssam		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
526189251Ssam		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
527189251Ssam		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
528189251Ssam	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
529189251Ssam		   "out_data=%p bufs %p %p %p",
530214734Srpaulo		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
531189251Ssam		   bufs[2].pvBuffer);
532189251Ssam
533189251Ssam	for (i = 0; i < 3; i++) {
534189251Ssam		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
535189251Ssam		{
536189251Ssam			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
537189251Ssam				    bufs[i].pvBuffer, bufs[i].cbBuffer);
538189251Ssam		}
539189251Ssam	}
540189251Ssam
541189251Ssam	if (status == SEC_E_OK) {
542189251Ssam		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
543214734Srpaulo		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
544214734Srpaulo				    "from EncryptMessage", out);
545214734Srpaulo		return out;
546189251Ssam	}
547189251Ssam
548189251Ssam	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
549189251Ssam		   __func__, (int) status);
550214734Srpaulo	wpabuf_free(out);
551214734Srpaulo	return NULL;
552189251Ssam}
553189251Ssam
554189251Ssam
555214734Srpaulostruct wpabuf * tls_connection_decrypt(void *tls_ctx,
556214734Srpaulo				       struct tls_connection *conn,
557214734Srpaulo				       const struct wpabuf *in_data)
558189251Ssam{
559214734Srpaulo	struct tls_global *global = tls_ctx;
560189251Ssam	SECURITY_STATUS status;
561189251Ssam	SecBufferDesc buf;
562189251Ssam	SecBuffer bufs[4];
563189251Ssam	int i;
564214734Srpaulo	struct wpabuf *out, *tmp;
565189251Ssam
566214734Srpaulo	wpa_hexdump_buf(MSG_MSGDUMP,
567214734Srpaulo			"Schannel: Encrypted data to DecryptMessage", in_data);
568189251Ssam	os_memset(&bufs, 0, sizeof(bufs));
569214734Srpaulo	tmp = wpabuf_dup(in_data);
570214734Srpaulo	if (tmp == NULL)
571214734Srpaulo		return NULL;
572214734Srpaulo	bufs[0].pvBuffer = wpabuf_mhead(tmp);
573214734Srpaulo	bufs[0].cbBuffer = wpabuf_len(in_data);
574189251Ssam	bufs[0].BufferType = SECBUFFER_DATA;
575189251Ssam
576189251Ssam	bufs[1].BufferType = SECBUFFER_EMPTY;
577189251Ssam	bufs[2].BufferType = SECBUFFER_EMPTY;
578189251Ssam	bufs[3].BufferType = SECBUFFER_EMPTY;
579189251Ssam
580189251Ssam	buf.ulVersion = SECBUFFER_VERSION;
581189251Ssam	buf.cBuffers = 4;
582189251Ssam	buf.pBuffers = bufs;
583189251Ssam
584189251Ssam	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
585189251Ssam						    NULL);
586189251Ssam	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
587189251Ssam		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
588189251Ssam		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
589189251Ssam		   (int) status,
590189251Ssam		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
591189251Ssam		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
592189251Ssam		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
593189251Ssam		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
594189251Ssam	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
595189251Ssam		   "out_data=%p bufs %p %p %p %p",
596214734Srpaulo		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
597189251Ssam		   bufs[2].pvBuffer, bufs[3].pvBuffer);
598189251Ssam
599189251Ssam	switch (status) {
600189251Ssam	case SEC_E_INCOMPLETE_MESSAGE:
601189251Ssam		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
602189251Ssam			   __func__);
603189251Ssam		break;
604189251Ssam	case SEC_E_OK:
605189251Ssam		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
606189251Ssam		for (i = 0; i < 4; i++) {
607189251Ssam			if (bufs[i].BufferType == SECBUFFER_DATA)
608189251Ssam				break;
609189251Ssam		}
610189251Ssam		if (i == 4) {
611189251Ssam			wpa_printf(MSG_DEBUG, "%s: No output data from "
612189251Ssam				   "DecryptMessage", __func__);
613214734Srpaulo			wpabuf_free(tmp);
614214734Srpaulo			return NULL;
615189251Ssam		}
616189251Ssam		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
617189251Ssam				"DecryptMessage",
618189251Ssam				bufs[i].pvBuffer, bufs[i].cbBuffer);
619214734Srpaulo		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
620214734Srpaulo		wpabuf_free(tmp);
621214734Srpaulo		return out;
622189251Ssam	}
623189251Ssam
624189251Ssam	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
625189251Ssam		   __func__, (int) status);
626214734Srpaulo	wpabuf_free(tmp);
627214734Srpaulo	return NULL;
628189251Ssam}
629189251Ssam
630189251Ssam
631189251Ssamint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
632189251Ssam{
633189251Ssam	return 0;
634189251Ssam}
635189251Ssam
636189251Ssam
637189251Ssamint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
638189251Ssam				   u8 *ciphers)
639189251Ssam{
640189251Ssam	return -1;
641189251Ssam}
642189251Ssam
643189251Ssam
644189251Ssamint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
645189251Ssam		   char *buf, size_t buflen)
646189251Ssam{
647189251Ssam	return -1;
648189251Ssam}
649189251Ssam
650189251Ssam
651189251Ssamint tls_connection_enable_workaround(void *ssl_ctx,
652189251Ssam				     struct tls_connection *conn)
653189251Ssam{
654189251Ssam	return 0;
655189251Ssam}
656189251Ssam
657189251Ssam
658189251Ssamint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
659189251Ssam				    int ext_type, const u8 *data,
660189251Ssam				    size_t data_len)
661189251Ssam{
662189251Ssam	return -1;
663189251Ssam}
664189251Ssam
665189251Ssam
666189251Ssamint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
667189251Ssam{
668189251Ssam	if (conn == NULL)
669189251Ssam		return -1;
670189251Ssam	return conn->failed;
671189251Ssam}
672189251Ssam
673189251Ssam
674189251Ssamint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
675189251Ssam{
676189251Ssam	if (conn == NULL)
677189251Ssam		return -1;
678189251Ssam	return conn->read_alerts;
679189251Ssam}
680189251Ssam
681189251Ssam
682189251Ssamint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
683189251Ssam{
684189251Ssam	if (conn == NULL)
685189251Ssam		return -1;
686189251Ssam	return conn->write_alerts;
687189251Ssam}
688189251Ssam
689189251Ssam
690189251Ssamint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
691189251Ssam			      const struct tls_connection_params *params)
692189251Ssam{
693189251Ssam	struct tls_global *global = tls_ctx;
694189251Ssam	ALG_ID algs[1];
695189251Ssam	SECURITY_STATUS status;
696189251Ssam	TimeStamp ts_expiry;
697189251Ssam
698189251Ssam	if (conn == NULL)
699189251Ssam		return -1;
700189251Ssam
701189251Ssam	if (global->my_cert_store == NULL &&
702189251Ssam	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
703189251Ssam	    NULL) {
704189251Ssam		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
705189251Ssam			   __func__, (unsigned int) GetLastError());
706189251Ssam		return -1;
707189251Ssam	}
708189251Ssam
709189251Ssam	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
710189251Ssam	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
711189251Ssam	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
712189251Ssam	algs[0] = CALG_RSA_KEYX;
713189251Ssam	conn->schannel_cred.cSupportedAlgs = 1;
714189251Ssam	conn->schannel_cred.palgSupportedAlgs = algs;
715189251Ssam	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
716189251Ssam#ifdef UNICODE
717189251Ssam	status = global->sspi->AcquireCredentialsHandleW(
718189251Ssam		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
719189251Ssam		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
720189251Ssam#else /* UNICODE */
721189251Ssam	status = global->sspi->AcquireCredentialsHandleA(
722189251Ssam		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
723189251Ssam		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
724189251Ssam#endif /* UNICODE */
725189251Ssam	if (status != SEC_E_OK) {
726189251Ssam		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
727189251Ssam			   "0x%x", __func__, (unsigned int) status);
728189251Ssam		return -1;
729189251Ssam	}
730189251Ssam
731189251Ssam	return 0;
732189251Ssam}
733189251Ssam
734189251Ssam
735189251Ssamunsigned int tls_capabilities(void *tls_ctx)
736189251Ssam{
737189251Ssam	return 0;
738189251Ssam}
739189251Ssam
740189251Ssam
741189251Ssamint tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
742189251Ssam			  int tls_ia)
743189251Ssam{
744189251Ssam	return -1;
745189251Ssam}
746189251Ssam
747189251Ssam
748214734Srpaulostruct wpabuf * tls_connection_ia_send_phase_finished(
749214734Srpaulo	void *tls_ctx, struct tls_connection *conn, int final);
750189251Ssam{
751214734Srpaulo	return NULL;
752189251Ssam}
753189251Ssam
754189251Ssam
755189251Ssamint tls_connection_ia_final_phase_finished(void *tls_ctx,
756189251Ssam					   struct tls_connection *conn)
757189251Ssam{
758189251Ssam	return -1;
759189251Ssam}
760189251Ssam
761189251Ssam
762189251Ssamint tls_connection_ia_permute_inner_secret(void *tls_ctx,
763189251Ssam					   struct tls_connection *conn,
764189251Ssam					   const u8 *key, size_t key_len)
765189251Ssam{
766189251Ssam	return -1;
767189251Ssam}
768