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