2
* WPA Supplicant / SSL/TLS interface functions for Microsoft Schannel
3
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License version 2 as
7
* published by the Free Software Foundation.
9
* Alternatively, this software may be distributed under the terms of BSD
12
* See README and COPYING for more details.
16
* FIX: Go through all SSPI functions and verify what needs to be freed
17
* FIX: session resumption
18
* TODO: add support for server cert chain validation
19
* TODO: add support for CA cert validation
20
* TODO: add support for EAP-TLS (client cert/key conf)
27
#define SECURITY_WIN32
37
PSecurityFunctionTable sspi;
38
HCERTSTORE my_cert_store;
41
struct tls_connection {
42
int established, start;
43
int failed, read_alerts, write_alerts;
45
SCHANNEL_CRED schannel_cred;
54
static int schannel_load_lib(struct tls_global *global)
56
INIT_SECURITY_INTERFACE pInitSecurityInterface;
58
global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
59
if (global->hsecurity == NULL) {
60
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
61
__func__, (unsigned int) GetLastError());
65
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
66
global->hsecurity, "InitSecurityInterfaceA");
67
if (pInitSecurityInterface == NULL) {
68
wpa_printf(MSG_ERROR, "%s: Could not find "
69
"InitSecurityInterfaceA from Secur32.dll",
71
FreeLibrary(global->hsecurity);
72
global->hsecurity = NULL;
76
global->sspi = pInitSecurityInterface();
77
if (global->sspi == NULL) {
78
wpa_printf(MSG_ERROR, "%s: Could not read security "
80
__func__, (unsigned int) GetLastError());
81
FreeLibrary(global->hsecurity);
82
global->hsecurity = NULL;
90
void * tls_init(const struct tls_config *conf)
92
struct tls_global *global;
94
global = os_zalloc(sizeof(*global));
97
if (schannel_load_lib(global)) {
105
void tls_deinit(void *ssl_ctx)
107
struct tls_global *global = ssl_ctx;
109
if (global->my_cert_store)
110
CertCloseStore(global->my_cert_store, 0);
111
FreeLibrary(global->hsecurity);
116
int tls_get_errors(void *ssl_ctx)
122
struct tls_connection * tls_connection_init(void *ssl_ctx)
124
struct tls_connection *conn;
126
conn = os_zalloc(sizeof(*conn));
135
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
144
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
146
return conn ? conn->established : 0;
150
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
152
struct tls_global *global = ssl_ctx;
156
conn->eap_tls_prf_set = 0;
157
conn->established = conn->failed = 0;
158
conn->read_alerts = conn->write_alerts = 0;
159
global->sspi->DeleteSecurityContext(&conn->context);
160
/* FIX: what else needs to be reseted? */
166
int tls_global_set_params(void *tls_ctx,
167
const struct tls_connection_params *params)
173
int tls_global_set_verify(void *ssl_ctx, int check_crl)
179
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
186
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
187
struct tls_keys *keys)
189
/* Schannel does not export master secret or client/server random. */
194
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
195
const char *label, int server_random_first,
196
u8 *out, size_t out_len)
199
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
200
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
201
* EAP-TTLS cannot use this, though, since they are using different
202
* labels. The only option could be to implement TLSv1 completely here
203
* and just use Schannel or CryptoAPI for low-level crypto
207
if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
208
os_strcmp(label, "client EAP encryption") != 0 ||
209
out_len > sizeof(conn->eap_tls_prf))
212
os_memcpy(out, conn->eap_tls_prf, out_len);
218
static u8 * tls_conn_hs_clienthello(struct tls_global *global,
219
struct tls_connection *conn,
222
DWORD sspi_flags, sspi_flags_out;
223
SecBufferDesc outbuf;
224
SecBuffer outbufs[1];
225
SECURITY_STATUS status;
228
sspi_flags = ISC_REQ_REPLAY_DETECT |
229
ISC_REQ_CONFIDENTIALITY |
230
ISC_RET_EXTENDED_ERROR |
231
ISC_REQ_ALLOCATE_MEMORY |
232
ISC_REQ_MANUAL_CRED_VALIDATION;
234
wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
236
outbufs[0].pvBuffer = NULL;
237
outbufs[0].BufferType = SECBUFFER_TOKEN;
238
outbufs[0].cbBuffer = 0;
241
outbuf.pBuffers = outbufs;
242
outbuf.ulVersion = SECBUFFER_VERSION;
245
status = global->sspi->InitializeSecurityContextW(
246
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
247
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
248
&outbuf, &sspi_flags_out, &ts_expiry);
250
status = global->sspi->InitializeSecurityContextA(
251
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
252
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
253
&outbuf, &sspi_flags_out, &ts_expiry);
255
if (status != SEC_I_CONTINUE_NEEDED) {
256
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
258
__func__, (unsigned int) status);
262
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
264
wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
265
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
267
*out_len = outbufs[0].cbBuffer;
268
buf = os_malloc(*out_len);
271
os_memcpy(buf, outbufs[0].pvBuffer, *out_len);
272
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
276
wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
282
#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
283
#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
285
typedef struct _SecPkgContext_EapKeyBlock {
288
} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
289
#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
291
static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
293
SECURITY_STATUS status;
294
SecPkgContext_EapKeyBlock kb;
296
/* Note: Windows NT and Windows Me/98/95 do not support getting
299
status = global->sspi->QueryContextAttributes(
300
&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
301
if (status != SEC_E_OK) {
302
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
303
"SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
304
__func__, (int) status);
308
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
309
kb.rgbKeys, sizeof(kb.rgbKeys));
310
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
311
kb.rgbIVs, sizeof(kb.rgbIVs));
313
os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
314
conn->eap_tls_prf_set = 1;
319
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
320
const u8 *in_data, size_t in_len,
321
size_t *out_len, u8 **appl_data,
322
size_t *appl_data_len)
324
struct tls_global *global = ssl_ctx;
325
DWORD sspi_flags, sspi_flags_out;
326
SecBufferDesc inbuf, outbuf;
327
SecBuffer inbufs[2], outbufs[1];
328
SECURITY_STATUS status;
336
return tls_conn_hs_clienthello(global, conn, out_len);
339
wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
342
sspi_flags = ISC_REQ_REPLAY_DETECT |
343
ISC_REQ_CONFIDENTIALITY |
344
ISC_RET_EXTENDED_ERROR |
345
ISC_REQ_ALLOCATE_MEMORY |
346
ISC_REQ_MANUAL_CRED_VALIDATION;
348
/* Input buffer for Schannel */
349
inbufs[0].pvBuffer = (u8 *) in_data;
350
inbufs[0].cbBuffer = in_len;
351
inbufs[0].BufferType = SECBUFFER_TOKEN;
353
/* Place for leftover data from Schannel */
354
inbufs[1].pvBuffer = NULL;
355
inbufs[1].cbBuffer = 0;
356
inbufs[1].BufferType = SECBUFFER_EMPTY;
359
inbuf.pBuffers = inbufs;
360
inbuf.ulVersion = SECBUFFER_VERSION;
362
/* Output buffer for Schannel */
363
outbufs[0].pvBuffer = NULL;
364
outbufs[0].cbBuffer = 0;
365
outbufs[0].BufferType = SECBUFFER_TOKEN;
368
outbuf.pBuffers = outbufs;
369
outbuf.ulVersion = SECBUFFER_VERSION;
372
status = global->sspi->InitializeSecurityContextW(
373
&conn->creds, &conn->context, NULL, sspi_flags, 0,
374
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
375
&outbuf, &sspi_flags_out, &ts_expiry);
377
status = global->sspi->InitializeSecurityContextA(
378
&conn->creds, &conn->context, NULL, sspi_flags, 0,
379
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
380
&outbuf, &sspi_flags_out, &ts_expiry);
383
wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
384
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
385
"intype[1]=%d outlen[0]=%d",
386
(int) status, (int) inbufs[0].cbBuffer,
387
(int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
388
(int) inbufs[1].BufferType,
389
(int) outbufs[0].cbBuffer);
390
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
391
(FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
392
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
393
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
394
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
395
*out_len = outbufs[0].cbBuffer;
396
out_buf = os_malloc(*out_len);
398
os_memcpy(out_buf, outbufs[0].pvBuffer,
400
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
401
outbufs[0].pvBuffer = NULL;
408
case SEC_E_INCOMPLETE_MESSAGE:
409
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
411
case SEC_I_CONTINUE_NEEDED:
412
wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
415
/* TODO: verify server certificate chain */
416
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
417
"completed successfully");
418
conn->established = 1;
419
tls_get_eap(global, conn);
421
/* Need to return something to get final TLS ACK. */
423
out_buf = os_malloc(1);
425
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
426
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
428
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
430
*appl_data_len = outbufs[1].cbBuffer;
431
appl_data = os_malloc(*appl_data_len);
437
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
438
inbufs[1].pvBuffer = NULL;
441
case SEC_I_INCOMPLETE_CREDENTIALS:
442
wpa_printf(MSG_DEBUG,
443
"Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
445
case SEC_E_WRONG_PRINCIPAL:
446
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
448
case SEC_E_INTERNAL_ERROR:
449
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
453
if (FAILED(status)) {
454
wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
455
"(out_buf=%p)", out_buf);
457
global->sspi->DeleteSecurityContext(&conn->context);
461
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
462
/* TODO: Can this happen? What to do with this data? */
463
wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
464
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
465
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
466
inbufs[1].pvBuffer = NULL;
473
u8 * tls_connection_server_handshake(void *ssl_ctx,
474
struct tls_connection *conn,
475
const u8 *in_data, size_t in_len,
482
int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
483
const u8 *in_data, size_t in_len,
484
u8 *out_data, size_t out_len)
486
struct tls_global *global = ssl_ctx;
487
SECURITY_STATUS status;
490
SecPkgContext_StreamSizes sizes;
494
status = global->sspi->QueryContextAttributes(&conn->context,
495
SECPKG_ATTR_STREAM_SIZES,
497
if (status != SEC_E_OK) {
498
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
502
wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
504
(unsigned int) sizes.cbHeader,
505
(unsigned int) sizes.cbTrailer);
507
total_len = sizes.cbHeader + in_len + sizes.cbTrailer;
509
if (out_len < total_len) {
510
wpa_printf(MSG_DEBUG, "%s: too short out_data (out_len=%lu "
511
"in_len=%lu total_len=%lu)", __func__,
512
(unsigned long) out_len, (unsigned long) in_len,
513
(unsigned long) total_len);
517
os_memset(&bufs, 0, sizeof(bufs));
518
bufs[0].pvBuffer = out_data;
519
bufs[0].cbBuffer = sizes.cbHeader;
520
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
522
os_memcpy(out_data + sizes.cbHeader, in_data, in_len);
523
bufs[1].pvBuffer = out_data + sizes.cbHeader;
524
bufs[1].cbBuffer = in_len;
525
bufs[1].BufferType = SECBUFFER_DATA;
527
bufs[2].pvBuffer = out_data + sizes.cbHeader + in_len;
528
bufs[2].cbBuffer = sizes.cbTrailer;
529
bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
531
buf.ulVersion = SECBUFFER_VERSION;
535
status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
537
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
538
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
539
"len[2]=%d type[2]=%d",
541
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
542
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
543
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
544
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
545
"out_data=%p bufs %p %p %p",
546
out_data, bufs[0].pvBuffer, bufs[1].pvBuffer,
549
for (i = 0; i < 3; i++) {
550
if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
552
wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
553
bufs[i].pvBuffer, bufs[i].cbBuffer);
557
if (status == SEC_E_OK) {
558
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
559
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Encrypted data from "
560
"EncryptMessage", out_data, total_len);
564
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
565
__func__, (int) status);
570
int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
571
const u8 *in_data, size_t in_len,
572
u8 *out_data, size_t out_len)
574
struct tls_global *global = ssl_ctx;
575
SECURITY_STATUS status;
580
if (out_len < in_len) {
581
wpa_printf(MSG_DEBUG, "%s: out_len=%lu < in_len=%lu", __func__,
582
(unsigned long) out_len, (unsigned long) in_len);
586
wpa_hexdump(MSG_MSGDUMP, "Schannel: Encrypted data to DecryptMessage",
588
os_memset(&bufs, 0, sizeof(bufs));
589
os_memcpy(out_data, in_data, in_len);
590
bufs[0].pvBuffer = out_data;
591
bufs[0].cbBuffer = in_len;
592
bufs[0].BufferType = SECBUFFER_DATA;
594
bufs[1].BufferType = SECBUFFER_EMPTY;
595
bufs[2].BufferType = SECBUFFER_EMPTY;
596
bufs[3].BufferType = SECBUFFER_EMPTY;
598
buf.ulVersion = SECBUFFER_VERSION;
602
status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
604
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
605
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
606
"len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
608
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
609
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
610
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
611
(int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
612
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
613
"out_data=%p bufs %p %p %p %p",
614
out_data, bufs[0].pvBuffer, bufs[1].pvBuffer,
615
bufs[2].pvBuffer, bufs[3].pvBuffer);
618
case SEC_E_INCOMPLETE_MESSAGE:
619
wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
623
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
624
for (i = 0; i < 4; i++) {
625
if (bufs[i].BufferType == SECBUFFER_DATA)
629
wpa_printf(MSG_DEBUG, "%s: No output data from "
630
"DecryptMessage", __func__);
633
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
635
bufs[i].pvBuffer, bufs[i].cbBuffer);
636
if (bufs[i].cbBuffer > out_len) {
637
wpa_printf(MSG_DEBUG, "%s: Too long output data",
641
os_memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer);
642
return bufs[i].cbBuffer;
645
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
646
__func__, (int) status);
651
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
657
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
664
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
665
char *buf, size_t buflen)
671
int tls_connection_enable_workaround(void *ssl_ctx,
672
struct tls_connection *conn)
678
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
679
int ext_type, const u8 *data,
686
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
694
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
698
return conn->read_alerts;
702
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
706
return conn->write_alerts;
710
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
711
const struct tls_connection_params *params)
713
struct tls_global *global = tls_ctx;
715
SECURITY_STATUS status;
721
if (global->my_cert_store == NULL &&
722
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
724
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
725
__func__, (unsigned int) GetLastError());
729
os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
730
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
731
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
732
algs[0] = CALG_RSA_KEYX;
733
conn->schannel_cred.cSupportedAlgs = 1;
734
conn->schannel_cred.palgSupportedAlgs = algs;
735
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
737
status = global->sspi->AcquireCredentialsHandleW(
738
NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
739
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
741
status = global->sspi->AcquireCredentialsHandleA(
742
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
743
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
745
if (status != SEC_E_OK) {
746
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
747
"0x%x", __func__, (unsigned int) status);
755
unsigned int tls_capabilities(void *tls_ctx)
761
int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
768
int tls_connection_ia_send_phase_finished(void *tls_ctx,
769
struct tls_connection *conn,
771
u8 *out_data, size_t out_len)
777
int tls_connection_ia_final_phase_finished(void *tls_ctx,
778
struct tls_connection *conn)
784
int tls_connection_ia_permute_inner_secret(void *tls_ctx,
785
struct tls_connection *conn,
786
const u8 *key, size_t key_len)