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