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