Home | History | Annotate | Download | only in crypto
      1 /*
      2  * SSL/TLS interface functions for Microsoft Schannel
      3  * Copyright (c) 2005-2009, Jouni Malinen <j (at) 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 
     29 struct tls_global {
     30 	HMODULE hsecurity;
     31 	PSecurityFunctionTable sspi;
     32 	HCERTSTORE my_cert_store;
     33 };
     34 
     35 struct 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 
     48 static 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 
     84 void * 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 
     99 void 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 
    110 int tls_get_errors(void *ssl_ctx)
    111 {
    112 	return 0;
    113 }
    114 
    115 
    116 struct 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 
    129 void 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 
    138 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
    139 {
    140 	return conn ? conn->established : 0;
    141 }
    142 
    143 
    144 int 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 
    160 int tls_global_set_params(void *tls_ctx,
    161 			  const struct tls_connection_params *params)
    162 {
    163 	return -1;
    164 }
    165 
    166 
    167 int tls_global_set_verify(void *ssl_ctx, int check_crl)
    168 {
    169 	return -1;
    170 }
    171 
    172 
    173 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
    174 			      int verify_peer)
    175 {
    176 	return -1;
    177 }
    178 
    179 
    180 int 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 
    188 int 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 
    212 static 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 
    277 typedef struct _SecPkgContext_EapKeyBlock {
    278 	BYTE rgbKeys[128];
    279 	BYTE rgbIVs[64];
    280 } SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
    281 #endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
    282 
    283 static 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 
    311 struct 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 
    458 struct 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 
    467 struct 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 
    549 struct 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 
    625 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
    626 {
    627 	return 0;
    628 }
    629 
    630 
    631 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
    632 				   u8 *ciphers)
    633 {
    634 	return -1;
    635 }
    636 
    637 
    638 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
    639 		   char *buf, size_t buflen)
    640 {
    641 	return -1;
    642 }
    643 
    644 
    645 int tls_connection_enable_workaround(void *ssl_ctx,
    646 				     struct tls_connection *conn)
    647 {
    648 	return 0;
    649 }
    650 
    651 
    652 int 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 
    660 int 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 
    668 int 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 
    676 int 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 
    684 int 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 
    729 unsigned int tls_capabilities(void *tls_ctx)
    730 {
    731 	return 0;
    732 }
    733