1/*
2 * SSL/TLS interface functions for Microsoft Schannel
3 * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9/*
10 * FIX: Go through all SSPI functions and verify what needs to be freed
11 * FIX: session resumption
12 * TODO: add support for server cert chain validation
13 * TODO: add support for CA cert validation
14 * TODO: add support for EAP-TLS (client cert/key conf)
15 */
16
17#include "includes.h"
18#include <windows.h>
19#include <wincrypt.h>
20#include <schannel.h>
21#define SECURITY_WIN32
22#include <security.h>
23#include <sspi.h>
24
25#include "common.h"
26#include "tls.h"
27
28
29struct tls_global {
30	HMODULE hsecurity;
31	PSecurityFunctionTable sspi;
32	HCERTSTORE my_cert_store;
33};
34
35struct tls_connection {
36	int established, start;
37	int failed, read_alerts, write_alerts;
38
39	SCHANNEL_CRED schannel_cred;
40	CredHandle creds;
41	CtxtHandle context;
42
43	u8 eap_tls_prf[128];
44	int eap_tls_prf_set;
45};
46
47
48static int schannel_load_lib(struct tls_global *global)
49{
50	INIT_SECURITY_INTERFACE pInitSecurityInterface;
51
52	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
53	if (global->hsecurity == NULL) {
54		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
55			   __func__, (unsigned int) GetLastError());
56		return -1;
57	}
58
59	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
60		global->hsecurity, "InitSecurityInterfaceA");
61	if (pInitSecurityInterface == NULL) {
62		wpa_printf(MSG_ERROR, "%s: Could not find "
63			   "InitSecurityInterfaceA from Secur32.dll",
64			   __func__);
65		FreeLibrary(global->hsecurity);
66		global->hsecurity = NULL;
67		return -1;
68	}
69
70	global->sspi = pInitSecurityInterface();
71	if (global->sspi == NULL) {
72		wpa_printf(MSG_ERROR, "%s: Could not read security "
73			   "interface - 0x%x",
74			   __func__, (unsigned int) GetLastError());
75		FreeLibrary(global->hsecurity);
76		global->hsecurity = NULL;
77		return -1;
78	}
79
80	return 0;
81}
82
83
84void * tls_init(const struct tls_config *conf)
85{
86	struct tls_global *global;
87
88	global = os_zalloc(sizeof(*global));
89	if (global == NULL)
90		return NULL;
91	if (schannel_load_lib(global)) {
92		os_free(global);
93		return NULL;
94	}
95	return global;
96}
97
98
99void tls_deinit(void *ssl_ctx)
100{
101	struct tls_global *global = ssl_ctx;
102
103	if (global->my_cert_store)
104		CertCloseStore(global->my_cert_store, 0);
105	FreeLibrary(global->hsecurity);
106	os_free(global);
107}
108
109
110int tls_get_errors(void *ssl_ctx)
111{
112	return 0;
113}
114
115
116struct tls_connection * tls_connection_init(void *ssl_ctx)
117{
118	struct tls_connection *conn;
119
120	conn = os_zalloc(sizeof(*conn));
121	if (conn == NULL)
122		return NULL;
123	conn->start = 1;
124
125	return conn;
126}
127
128
129void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
130{
131	if (conn == NULL)
132		return;
133
134	os_free(conn);
135}
136
137
138int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
139{
140	return conn ? conn->established : 0;
141}
142
143
144int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
145{
146	struct tls_global *global = ssl_ctx;
147	if (conn == NULL)
148		return -1;
149
150	conn->eap_tls_prf_set = 0;
151	conn->established = conn->failed = 0;
152	conn->read_alerts = conn->write_alerts = 0;
153	global->sspi->DeleteSecurityContext(&conn->context);
154	/* FIX: what else needs to be reseted? */
155
156	return 0;
157}
158
159
160int tls_global_set_params(void *tls_ctx,
161			  const struct tls_connection_params *params)
162{
163	return -1;
164}
165
166
167int tls_global_set_verify(void *ssl_ctx, int check_crl)
168{
169	return -1;
170}
171
172
173int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
174			      int verify_peer)
175{
176	return -1;
177}
178
179
180int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
181			    struct tls_keys *keys)
182{
183	/* Schannel does not export master secret or client/server random. */
184	return -1;
185}
186
187
188int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
189		       const char *label, int server_random_first,
190		       u8 *out, size_t out_len)
191{
192	/*
193	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
194	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
195	 * EAP-TTLS cannot use this, though, since they are using different
196	 * labels. The only option could be to implement TLSv1 completely here
197	 * and just use Schannel or CryptoAPI for low-level crypto
198	 * functionality..
199	 */
200
201	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
202	    os_strcmp(label, "client EAP encryption") != 0 ||
203	    out_len > sizeof(conn->eap_tls_prf))
204		return -1;
205
206	os_memcpy(out, conn->eap_tls_prf, out_len);
207
208	return 0;
209}
210
211
212static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
213					       struct tls_connection *conn)
214{
215	DWORD sspi_flags, sspi_flags_out;
216	SecBufferDesc outbuf;
217	SecBuffer outbufs[1];
218	SECURITY_STATUS status;
219	TimeStamp ts_expiry;
220
221	sspi_flags = ISC_REQ_REPLAY_DETECT |
222		ISC_REQ_CONFIDENTIALITY |
223		ISC_RET_EXTENDED_ERROR |
224		ISC_REQ_ALLOCATE_MEMORY |
225		ISC_REQ_MANUAL_CRED_VALIDATION;
226
227	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
228
229	outbufs[0].pvBuffer = NULL;
230	outbufs[0].BufferType = SECBUFFER_TOKEN;
231	outbufs[0].cbBuffer = 0;
232
233	outbuf.cBuffers = 1;
234	outbuf.pBuffers = outbufs;
235	outbuf.ulVersion = SECBUFFER_VERSION;
236
237#ifdef UNICODE
238	status = global->sspi->InitializeSecurityContextW(
239		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
240		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
241		&outbuf, &sspi_flags_out, &ts_expiry);
242#else /* UNICODE */
243	status = global->sspi->InitializeSecurityContextA(
244		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
245		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
246		&outbuf, &sspi_flags_out, &ts_expiry);
247#endif /* UNICODE */
248	if (status != SEC_I_CONTINUE_NEEDED) {
249		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
250			   "failed - 0x%x",
251			   __func__, (unsigned int) status);
252		return NULL;
253	}
254
255	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
256		struct wpabuf *buf;
257		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
258			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
259		conn->start = 0;
260		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
261					outbufs[0].cbBuffer);
262		if (buf == NULL)
263			return NULL;
264		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
265		return buf;
266	}
267
268	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
269
270	return NULL;
271}
272
273
274#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
275#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
276
277typedef struct _SecPkgContext_EapKeyBlock {
278	BYTE rgbKeys[128];
279	BYTE rgbIVs[64];
280} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
281#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
282
283static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
284{
285	SECURITY_STATUS status;
286	SecPkgContext_EapKeyBlock kb;
287
288	/* Note: Windows NT and Windows Me/98/95 do not support getting
289	 * EapKeyBlock */
290
291	status = global->sspi->QueryContextAttributes(
292		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
293	if (status != SEC_E_OK) {
294		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
295			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
296			   __func__, (int) status);
297		return -1;
298	}
299
300	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
301			kb.rgbKeys, sizeof(kb.rgbKeys));
302	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
303			kb.rgbIVs, sizeof(kb.rgbIVs));
304
305	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
306	conn->eap_tls_prf_set = 1;
307	return 0;
308}
309
310
311struct wpabuf * tls_connection_handshake(void *tls_ctx,
312					 struct tls_connection *conn,
313					 const struct wpabuf *in_data,
314					 struct wpabuf **appl_data)
315{
316	struct tls_global *global = tls_ctx;
317	DWORD sspi_flags, sspi_flags_out;
318	SecBufferDesc inbuf, outbuf;
319	SecBuffer inbufs[2], outbufs[1];
320	SECURITY_STATUS status;
321	TimeStamp ts_expiry;
322	struct wpabuf *out_buf = NULL;
323
324	if (appl_data)
325		*appl_data = NULL;
326
327	if (conn->start)
328		return tls_conn_hs_clienthello(global, conn);
329
330	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
331		   (int) wpabuf_len(in_data));
332
333	sspi_flags = ISC_REQ_REPLAY_DETECT |
334		ISC_REQ_CONFIDENTIALITY |
335		ISC_RET_EXTENDED_ERROR |
336		ISC_REQ_ALLOCATE_MEMORY |
337		ISC_REQ_MANUAL_CRED_VALIDATION;
338
339	/* Input buffer for Schannel */
340	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
341	inbufs[0].cbBuffer = wpabuf_len(in_data);
342	inbufs[0].BufferType = SECBUFFER_TOKEN;
343
344	/* Place for leftover data from Schannel */
345	inbufs[1].pvBuffer = NULL;
346	inbufs[1].cbBuffer = 0;
347	inbufs[1].BufferType = SECBUFFER_EMPTY;
348
349	inbuf.cBuffers = 2;
350	inbuf.pBuffers = inbufs;
351	inbuf.ulVersion = SECBUFFER_VERSION;
352
353	/* Output buffer for Schannel */
354	outbufs[0].pvBuffer = NULL;
355	outbufs[0].cbBuffer = 0;
356	outbufs[0].BufferType = SECBUFFER_TOKEN;
357
358	outbuf.cBuffers = 1;
359	outbuf.pBuffers = outbufs;
360	outbuf.ulVersion = SECBUFFER_VERSION;
361
362#ifdef UNICODE
363	status = global->sspi->InitializeSecurityContextW(
364		&conn->creds, &conn->context, NULL, sspi_flags, 0,
365		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
366		&outbuf, &sspi_flags_out, &ts_expiry);
367#else /* UNICODE */
368	status = global->sspi->InitializeSecurityContextA(
369		&conn->creds, &conn->context, NULL, sspi_flags, 0,
370		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
371		&outbuf, &sspi_flags_out, &ts_expiry);
372#endif /* UNICODE */
373
374	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
375		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
376		   "intype[1]=%d outlen[0]=%d",
377		   (int) status, (int) inbufs[0].cbBuffer,
378		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
379		   (int) inbufs[1].BufferType,
380		   (int) outbufs[0].cbBuffer);
381	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
382	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
383		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
384			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
385				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
386			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
387						    outbufs[0].cbBuffer);
388			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
389			outbufs[0].pvBuffer = NULL;
390			if (out_buf == NULL)
391				return NULL;
392		}
393	}
394
395	switch (status) {
396	case SEC_E_INCOMPLETE_MESSAGE:
397		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
398		break;
399	case SEC_I_CONTINUE_NEEDED:
400		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
401		break;
402	case SEC_E_OK:
403		/* TODO: verify server certificate chain */
404		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
405			   "completed successfully");
406		conn->established = 1;
407		tls_get_eap(global, conn);
408
409		/* Need to return something to get final TLS ACK. */
410		if (out_buf == NULL)
411			out_buf = wpabuf_alloc(0);
412
413		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
414			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
415				    "application data",
416				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
417			if (appl_data) {
418				*appl_data = wpabuf_alloc_copy(
419					outbufs[1].pvBuffer,
420					outbufs[1].cbBuffer);
421			}
422			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
423			inbufs[1].pvBuffer = NULL;
424		}
425		break;
426	case SEC_I_INCOMPLETE_CREDENTIALS:
427		wpa_printf(MSG_DEBUG,
428			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
429		break;
430	case SEC_E_WRONG_PRINCIPAL:
431		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
432		break;
433	case SEC_E_INTERNAL_ERROR:
434		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
435		break;
436	}
437
438	if (FAILED(status)) {
439		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
440			   "(out_buf=%p)", out_buf);
441		conn->failed++;
442		global->sspi->DeleteSecurityContext(&conn->context);
443		return out_buf;
444	}
445
446	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
447		/* TODO: Can this happen? What to do with this data? */
448		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
449			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
450		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
451		inbufs[1].pvBuffer = NULL;
452	}
453
454	return out_buf;
455}
456
457
458struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
459						struct tls_connection *conn,
460						const struct wpabuf *in_data,
461						struct wpabuf **appl_data)
462{
463	return NULL;
464}
465
466
467struct wpabuf * tls_connection_encrypt(void *tls_ctx,
468				       struct tls_connection *conn,
469				       const struct wpabuf *in_data)
470{
471	struct tls_global *global = tls_ctx;
472	SECURITY_STATUS status;
473	SecBufferDesc buf;
474	SecBuffer bufs[4];
475	SecPkgContext_StreamSizes sizes;
476	int i;
477	struct wpabuf *out;
478
479	status = global->sspi->QueryContextAttributes(&conn->context,
480						      SECPKG_ATTR_STREAM_SIZES,
481						      &sizes);
482	if (status != SEC_E_OK) {
483		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
484			   __func__);
485		return NULL;
486	}
487	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
488		   __func__,
489		   (unsigned int) sizes.cbHeader,
490		   (unsigned int) sizes.cbTrailer);
491
492	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
493			   sizes.cbTrailer);
494
495	os_memset(&bufs, 0, sizeof(bufs));
496	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
497	bufs[0].cbBuffer = sizes.cbHeader;
498	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
499
500	bufs[1].pvBuffer = wpabuf_put(out, 0);
501	wpabuf_put_buf(out, in_data);
502	bufs[1].cbBuffer = wpabuf_len(in_data);
503	bufs[1].BufferType = SECBUFFER_DATA;
504
505	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
506	bufs[2].cbBuffer = sizes.cbTrailer;
507	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
508
509	buf.ulVersion = SECBUFFER_VERSION;
510	buf.cBuffers = 3;
511	buf.pBuffers = bufs;
512
513	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
514
515	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
516		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
517		   "len[2]=%d type[2]=%d",
518		   (int) status,
519		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
520		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
521		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
522	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
523		   "out_data=%p bufs %p %p %p",
524		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
525		   bufs[2].pvBuffer);
526
527	for (i = 0; i < 3; i++) {
528		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
529		{
530			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
531				    bufs[i].pvBuffer, bufs[i].cbBuffer);
532		}
533	}
534
535	if (status == SEC_E_OK) {
536		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
537		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
538				    "from EncryptMessage", out);
539		return out;
540	}
541
542	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
543		   __func__, (int) status);
544	wpabuf_free(out);
545	return NULL;
546}
547
548
549struct wpabuf * tls_connection_decrypt(void *tls_ctx,
550				       struct tls_connection *conn,
551				       const struct wpabuf *in_data)
552{
553	struct tls_global *global = tls_ctx;
554	SECURITY_STATUS status;
555	SecBufferDesc buf;
556	SecBuffer bufs[4];
557	int i;
558	struct wpabuf *out, *tmp;
559
560	wpa_hexdump_buf(MSG_MSGDUMP,
561			"Schannel: Encrypted data to DecryptMessage", in_data);
562	os_memset(&bufs, 0, sizeof(bufs));
563	tmp = wpabuf_dup(in_data);
564	if (tmp == NULL)
565		return NULL;
566	bufs[0].pvBuffer = wpabuf_mhead(tmp);
567	bufs[0].cbBuffer = wpabuf_len(in_data);
568	bufs[0].BufferType = SECBUFFER_DATA;
569
570	bufs[1].BufferType = SECBUFFER_EMPTY;
571	bufs[2].BufferType = SECBUFFER_EMPTY;
572	bufs[3].BufferType = SECBUFFER_EMPTY;
573
574	buf.ulVersion = SECBUFFER_VERSION;
575	buf.cBuffers = 4;
576	buf.pBuffers = bufs;
577
578	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
579						    NULL);
580	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
581		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
582		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
583		   (int) status,
584		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
585		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
586		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
587		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
588	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
589		   "out_data=%p bufs %p %p %p %p",
590		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
591		   bufs[2].pvBuffer, bufs[3].pvBuffer);
592
593	switch (status) {
594	case SEC_E_INCOMPLETE_MESSAGE:
595		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
596			   __func__);
597		break;
598	case SEC_E_OK:
599		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
600		for (i = 0; i < 4; i++) {
601			if (bufs[i].BufferType == SECBUFFER_DATA)
602				break;
603		}
604		if (i == 4) {
605			wpa_printf(MSG_DEBUG, "%s: No output data from "
606				   "DecryptMessage", __func__);
607			wpabuf_free(tmp);
608			return NULL;
609		}
610		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
611				"DecryptMessage",
612				bufs[i].pvBuffer, bufs[i].cbBuffer);
613		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
614		wpabuf_free(tmp);
615		return out;
616	}
617
618	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
619		   __func__, (int) status);
620	wpabuf_free(tmp);
621	return NULL;
622}
623
624
625int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
626{
627	return 0;
628}
629
630
631int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
632				   u8 *ciphers)
633{
634	return -1;
635}
636
637
638int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
639		   char *buf, size_t buflen)
640{
641	return -1;
642}
643
644
645int tls_connection_enable_workaround(void *ssl_ctx,
646				     struct tls_connection *conn)
647{
648	return 0;
649}
650
651
652int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
653				    int ext_type, const u8 *data,
654				    size_t data_len)
655{
656	return -1;
657}
658
659
660int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
661{
662	if (conn == NULL)
663		return -1;
664	return conn->failed;
665}
666
667
668int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
669{
670	if (conn == NULL)
671		return -1;
672	return conn->read_alerts;
673}
674
675
676int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
677{
678	if (conn == NULL)
679		return -1;
680	return conn->write_alerts;
681}
682
683
684int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
685			      const struct tls_connection_params *params)
686{
687	struct tls_global *global = tls_ctx;
688	ALG_ID algs[1];
689	SECURITY_STATUS status;
690	TimeStamp ts_expiry;
691
692	if (conn == NULL)
693		return -1;
694
695	if (global->my_cert_store == NULL &&
696	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
697	    NULL) {
698		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
699			   __func__, (unsigned int) GetLastError());
700		return -1;
701	}
702
703	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
704	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
705	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
706	algs[0] = CALG_RSA_KEYX;
707	conn->schannel_cred.cSupportedAlgs = 1;
708	conn->schannel_cred.palgSupportedAlgs = algs;
709	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
710#ifdef UNICODE
711	status = global->sspi->AcquireCredentialsHandleW(
712		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
713		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
714#else /* UNICODE */
715	status = global->sspi->AcquireCredentialsHandleA(
716		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
717		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
718#endif /* UNICODE */
719	if (status != SEC_E_OK) {
720		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
721			   "0x%x", __func__, (unsigned int) status);
722		return -1;
723	}
724
725	return 0;
726}
727
728
729unsigned int tls_capabilities(void *tls_ctx)
730{
731	return 0;
732}
733