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