2 * SSL/TLS interface functions for Microsoft Schannel
3 * Copyright (c) 2005-2009, 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 struct wpabuf
* tls_conn_hs_clienthello(struct tls_global
*global
,
219 struct tls_connection
*conn
)
221 DWORD sspi_flags
, sspi_flags_out
;
222 SecBufferDesc outbuf
;
223 SecBuffer outbufs
[1];
224 SECURITY_STATUS status
;
227 sspi_flags
= ISC_REQ_REPLAY_DETECT
|
228 ISC_REQ_CONFIDENTIALITY
|
229 ISC_RET_EXTENDED_ERROR
|
230 ISC_REQ_ALLOCATE_MEMORY
|
231 ISC_REQ_MANUAL_CRED_VALIDATION
;
233 wpa_printf(MSG_DEBUG
, "%s: Generating ClientHello", __func__
);
235 outbufs
[0].pvBuffer
= NULL
;
236 outbufs
[0].BufferType
= SECBUFFER_TOKEN
;
237 outbufs
[0].cbBuffer
= 0;
240 outbuf
.pBuffers
= outbufs
;
241 outbuf
.ulVersion
= SECBUFFER_VERSION
;
244 status
= global
->sspi
->InitializeSecurityContextW(
245 &conn
->creds
, NULL
, NULL
/* server name */, sspi_flags
, 0,
246 SECURITY_NATIVE_DREP
, NULL
, 0, &conn
->context
,
247 &outbuf
, &sspi_flags_out
, &ts_expiry
);
249 status
= global
->sspi
->InitializeSecurityContextA(
250 &conn
->creds
, NULL
, NULL
/* server name */, sspi_flags
, 0,
251 SECURITY_NATIVE_DREP
, NULL
, 0, &conn
->context
,
252 &outbuf
, &sspi_flags_out
, &ts_expiry
);
254 if (status
!= SEC_I_CONTINUE_NEEDED
) {
255 wpa_printf(MSG_ERROR
, "%s: InitializeSecurityContextA "
257 __func__
, (unsigned int) status
);
261 if (outbufs
[0].cbBuffer
!= 0 && outbufs
[0].pvBuffer
) {
263 wpa_hexdump(MSG_MSGDUMP
, "SChannel - ClientHello",
264 outbufs
[0].pvBuffer
, outbufs
[0].cbBuffer
);
266 buf
= wpabuf_alloc_copy(outbufs
[0].pvBuffer
,
267 outbufs
[0].cbBuffer
);
270 global
->sspi
->FreeContextBuffer(outbufs
[0].pvBuffer
);
274 wpa_printf(MSG_ERROR
, "SChannel: Failed to generate ClientHello");
280 #ifndef SECPKG_ATTR_EAP_KEY_BLOCK
281 #define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
283 typedef struct _SecPkgContext_EapKeyBlock
{
286 } SecPkgContext_EapKeyBlock
, *PSecPkgContext_EapKeyBlock
;
287 #endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
289 static int tls_get_eap(struct tls_global
*global
, struct tls_connection
*conn
)
291 SECURITY_STATUS status
;
292 SecPkgContext_EapKeyBlock kb
;
294 /* Note: Windows NT and Windows Me/98/95 do not support getting
297 status
= global
->sspi
->QueryContextAttributes(
298 &conn
->context
, SECPKG_ATTR_EAP_KEY_BLOCK
, &kb
);
299 if (status
!= SEC_E_OK
) {
300 wpa_printf(MSG_DEBUG
, "%s: QueryContextAttributes("
301 "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
302 __func__
, (int) status
);
306 wpa_hexdump_key(MSG_MSGDUMP
, "Schannel - EapKeyBlock - rgbKeys",
307 kb
.rgbKeys
, sizeof(kb
.rgbKeys
));
308 wpa_hexdump_key(MSG_MSGDUMP
, "Schannel - EapKeyBlock - rgbIVs",
309 kb
.rgbIVs
, sizeof(kb
.rgbIVs
));
311 os_memcpy(conn
->eap_tls_prf
, kb
.rgbKeys
, sizeof(kb
.rgbKeys
));
312 conn
->eap_tls_prf_set
= 1;
317 struct wpabuf
* tls_connection_handshake(void *tls_ctx
,
318 struct tls_connection
*conn
,
319 const struct wpabuf
*in_data
,
320 struct wpabuf
**appl_data
)
322 struct tls_global
*global
= tls_ctx
;
323 DWORD sspi_flags
, sspi_flags_out
;
324 SecBufferDesc inbuf
, outbuf
;
325 SecBuffer inbufs
[2], outbufs
[1];
326 SECURITY_STATUS status
;
328 struct wpabuf
*out_buf
= NULL
;
334 return tls_conn_hs_clienthello(global
, conn
);
336 wpa_printf(MSG_DEBUG
, "SChannel: %d bytes handshake data to process",
337 (int) wpabuf_len(in_data
));
339 sspi_flags
= ISC_REQ_REPLAY_DETECT
|
340 ISC_REQ_CONFIDENTIALITY
|
341 ISC_RET_EXTENDED_ERROR
|
342 ISC_REQ_ALLOCATE_MEMORY
|
343 ISC_REQ_MANUAL_CRED_VALIDATION
;
345 /* Input buffer for Schannel */
346 inbufs
[0].pvBuffer
= (u8
*) wpabuf_head(in_data
);
347 inbufs
[0].cbBuffer
= wpabuf_len(in_data
);
348 inbufs
[0].BufferType
= SECBUFFER_TOKEN
;
350 /* Place for leftover data from Schannel */
351 inbufs
[1].pvBuffer
= NULL
;
352 inbufs
[1].cbBuffer
= 0;
353 inbufs
[1].BufferType
= SECBUFFER_EMPTY
;
356 inbuf
.pBuffers
= inbufs
;
357 inbuf
.ulVersion
= SECBUFFER_VERSION
;
359 /* Output buffer for Schannel */
360 outbufs
[0].pvBuffer
= NULL
;
361 outbufs
[0].cbBuffer
= 0;
362 outbufs
[0].BufferType
= SECBUFFER_TOKEN
;
365 outbuf
.pBuffers
= outbufs
;
366 outbuf
.ulVersion
= SECBUFFER_VERSION
;
369 status
= global
->sspi
->InitializeSecurityContextW(
370 &conn
->creds
, &conn
->context
, NULL
, sspi_flags
, 0,
371 SECURITY_NATIVE_DREP
, &inbuf
, 0, NULL
,
372 &outbuf
, &sspi_flags_out
, &ts_expiry
);
374 status
= global
->sspi
->InitializeSecurityContextA(
375 &conn
->creds
, &conn
->context
, NULL
, sspi_flags
, 0,
376 SECURITY_NATIVE_DREP
, &inbuf
, 0, NULL
,
377 &outbuf
, &sspi_flags_out
, &ts_expiry
);
380 wpa_printf(MSG_MSGDUMP
, "Schannel: InitializeSecurityContext -> "
381 "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
382 "intype[1]=%d outlen[0]=%d",
383 (int) status
, (int) inbufs
[0].cbBuffer
,
384 (int) inbufs
[0].BufferType
, (int) inbufs
[1].cbBuffer
,
385 (int) inbufs
[1].BufferType
,
386 (int) outbufs
[0].cbBuffer
);
387 if (status
== SEC_E_OK
|| status
== SEC_I_CONTINUE_NEEDED
||
388 (FAILED(status
) && (sspi_flags_out
& ISC_RET_EXTENDED_ERROR
))) {
389 if (outbufs
[0].cbBuffer
!= 0 && outbufs
[0].pvBuffer
) {
390 wpa_hexdump(MSG_MSGDUMP
, "SChannel - output",
391 outbufs
[0].pvBuffer
, outbufs
[0].cbBuffer
);
392 out_buf
= wpabuf_alloc_copy(outbufs
[0].pvBuffer
,
393 outbufs
[0].cbBuffer
);
394 global
->sspi
->FreeContextBuffer(outbufs
[0].pvBuffer
);
395 outbufs
[0].pvBuffer
= NULL
;
402 case SEC_E_INCOMPLETE_MESSAGE
:
403 wpa_printf(MSG_DEBUG
, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
405 case SEC_I_CONTINUE_NEEDED
:
406 wpa_printf(MSG_DEBUG
, "Schannel: SEC_I_CONTINUE_NEEDED");
409 /* TODO: verify server certificate chain */
410 wpa_printf(MSG_DEBUG
, "Schannel: SEC_E_OK - Handshake "
411 "completed successfully");
412 conn
->established
= 1;
413 tls_get_eap(global
, conn
);
415 /* Need to return something to get final TLS ACK. */
417 out_buf
= wpabuf_alloc(0);
419 if (inbufs
[1].BufferType
== SECBUFFER_EXTRA
) {
420 wpa_hexdump(MSG_MSGDUMP
, "SChannel - Encrypted "
422 inbufs
[1].pvBuffer
, inbufs
[1].cbBuffer
);
424 *appl_data
= wpabuf_alloc_copy(
426 outbufs
[1].cbBuffer
);
428 global
->sspi
->FreeContextBuffer(inbufs
[1].pvBuffer
);
429 inbufs
[1].pvBuffer
= NULL
;
432 case SEC_I_INCOMPLETE_CREDENTIALS
:
433 wpa_printf(MSG_DEBUG
,
434 "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
436 case SEC_E_WRONG_PRINCIPAL
:
437 wpa_printf(MSG_DEBUG
, "Schannel: SEC_E_WRONG_PRINCIPAL");
439 case SEC_E_INTERNAL_ERROR
:
440 wpa_printf(MSG_DEBUG
, "Schannel: SEC_E_INTERNAL_ERROR");
444 if (FAILED(status
)) {
445 wpa_printf(MSG_DEBUG
, "Schannel: Handshake failed "
446 "(out_buf=%p)", out_buf
);
448 global
->sspi
->DeleteSecurityContext(&conn
->context
);
452 if (inbufs
[1].BufferType
== SECBUFFER_EXTRA
) {
453 /* TODO: Can this happen? What to do with this data? */
454 wpa_hexdump(MSG_MSGDUMP
, "SChannel - Leftover data",
455 inbufs
[1].pvBuffer
, inbufs
[1].cbBuffer
);
456 global
->sspi
->FreeContextBuffer(inbufs
[1].pvBuffer
);
457 inbufs
[1].pvBuffer
= NULL
;
464 struct wpabuf
* tls_connection_server_handshake(void *tls_ctx
,
465 struct tls_connection
*conn
,
466 const struct wpabuf
*in_data
,
467 struct wpabuf
**appl_data
)
473 struct wpabuf
* tls_connection_encrypt(void *tls_ctx
,
474 struct tls_connection
*conn
,
475 const struct wpabuf
*in_data
)
477 struct tls_global
*global
= tls_ctx
;
478 SECURITY_STATUS status
;
481 SecPkgContext_StreamSizes sizes
;
485 status
= global
->sspi
->QueryContextAttributes(&conn
->context
,
486 SECPKG_ATTR_STREAM_SIZES
,
488 if (status
!= SEC_E_OK
) {
489 wpa_printf(MSG_DEBUG
, "%s: QueryContextAttributes failed",
493 wpa_printf(MSG_DEBUG
, "%s: Stream sizes: header=%u trailer=%u",
495 (unsigned int) sizes
.cbHeader
,
496 (unsigned int) sizes
.cbTrailer
);
498 out
= wpabuf_alloc(sizes
.cbHeader
+ wpabuf_len(in_data
) +
501 os_memset(&bufs
, 0, sizeof(bufs
));
502 bufs
[0].pvBuffer
= wpabuf_put(out
, sizes
.cbHeader
);
503 bufs
[0].cbBuffer
= sizes
.cbHeader
;
504 bufs
[0].BufferType
= SECBUFFER_STREAM_HEADER
;
506 bufs
[1].pvBuffer
= wpabuf_put(out
, 0);
507 wpabuf_put_buf(out
, in_data
);
508 bufs
[1].cbBuffer
= wpabuf_len(in_data
);
509 bufs
[1].BufferType
= SECBUFFER_DATA
;
511 bufs
[2].pvBuffer
= wpabuf_put(out
, sizes
.cbTrailer
);
512 bufs
[2].cbBuffer
= sizes
.cbTrailer
;
513 bufs
[2].BufferType
= SECBUFFER_STREAM_TRAILER
;
515 buf
.ulVersion
= SECBUFFER_VERSION
;
519 status
= global
->sspi
->EncryptMessage(&conn
->context
, 0, &buf
, 0);
521 wpa_printf(MSG_MSGDUMP
, "Schannel: EncryptMessage -> "
522 "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
523 "len[2]=%d type[2]=%d",
525 (int) bufs
[0].cbBuffer
, (int) bufs
[0].BufferType
,
526 (int) bufs
[1].cbBuffer
, (int) bufs
[1].BufferType
,
527 (int) bufs
[2].cbBuffer
, (int) bufs
[2].BufferType
);
528 wpa_printf(MSG_MSGDUMP
, "Schannel: EncryptMessage pointers: "
529 "out_data=%p bufs %p %p %p",
530 wpabuf_head(out
), bufs
[0].pvBuffer
, bufs
[1].pvBuffer
,
533 for (i
= 0; i
< 3; i
++) {
534 if (bufs
[i
].pvBuffer
&& bufs
[i
].BufferType
!= SECBUFFER_EMPTY
)
536 wpa_hexdump(MSG_MSGDUMP
, "SChannel: bufs",
537 bufs
[i
].pvBuffer
, bufs
[i
].cbBuffer
);
541 if (status
== SEC_E_OK
) {
542 wpa_printf(MSG_DEBUG
, "%s: SEC_E_OK", __func__
);
543 wpa_hexdump_buf_key(MSG_MSGDUMP
, "Schannel: Encrypted data "
544 "from EncryptMessage", out
);
548 wpa_printf(MSG_DEBUG
, "%s: Failed - status=%d",
549 __func__
, (int) status
);
555 struct wpabuf
* tls_connection_decrypt(void *tls_ctx
,
556 struct tls_connection
*conn
,
557 const struct wpabuf
*in_data
)
559 struct tls_global
*global
= tls_ctx
;
560 SECURITY_STATUS status
;
564 struct wpabuf
*out
, *tmp
;
566 wpa_hexdump_buf(MSG_MSGDUMP
,
567 "Schannel: Encrypted data to DecryptMessage", in_data
);
568 os_memset(&bufs
, 0, sizeof(bufs
));
569 tmp
= wpabuf_dup(in_data
);
572 bufs
[0].pvBuffer
= wpabuf_mhead(tmp
);
573 bufs
[0].cbBuffer
= wpabuf_len(in_data
);
574 bufs
[0].BufferType
= SECBUFFER_DATA
;
576 bufs
[1].BufferType
= SECBUFFER_EMPTY
;
577 bufs
[2].BufferType
= SECBUFFER_EMPTY
;
578 bufs
[3].BufferType
= SECBUFFER_EMPTY
;
580 buf
.ulVersion
= SECBUFFER_VERSION
;
584 status
= global
->sspi
->DecryptMessage(&conn
->context
, &buf
, 0,
586 wpa_printf(MSG_MSGDUMP
, "Schannel: DecryptMessage -> "
587 "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
588 "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
590 (int) bufs
[0].cbBuffer
, (int) bufs
[0].BufferType
,
591 (int) bufs
[1].cbBuffer
, (int) bufs
[1].BufferType
,
592 (int) bufs
[2].cbBuffer
, (int) bufs
[2].BufferType
,
593 (int) bufs
[3].cbBuffer
, (int) bufs
[3].BufferType
);
594 wpa_printf(MSG_MSGDUMP
, "Schannel: DecryptMessage pointers: "
595 "out_data=%p bufs %p %p %p %p",
596 wpabuf_head(tmp
), bufs
[0].pvBuffer
, bufs
[1].pvBuffer
,
597 bufs
[2].pvBuffer
, bufs
[3].pvBuffer
);
600 case SEC_E_INCOMPLETE_MESSAGE
:
601 wpa_printf(MSG_DEBUG
, "%s: SEC_E_INCOMPLETE_MESSAGE",
605 wpa_printf(MSG_DEBUG
, "%s: SEC_E_OK", __func__
);
606 for (i
= 0; i
< 4; i
++) {
607 if (bufs
[i
].BufferType
== SECBUFFER_DATA
)
611 wpa_printf(MSG_DEBUG
, "%s: No output data from "
612 "DecryptMessage", __func__
);
616 wpa_hexdump_key(MSG_MSGDUMP
, "Schannel: Decrypted data from "
618 bufs
[i
].pvBuffer
, bufs
[i
].cbBuffer
);
619 out
= wpabuf_alloc_copy(bufs
[i
].pvBuffer
, bufs
[i
].cbBuffer
);
624 wpa_printf(MSG_DEBUG
, "%s: Failed - status=%d",
625 __func__
, (int) status
);
631 int tls_connection_resumed(void *ssl_ctx
, struct tls_connection
*conn
)
637 int tls_connection_set_cipher_list(void *tls_ctx
, struct tls_connection
*conn
,
644 int tls_get_cipher(void *ssl_ctx
, struct tls_connection
*conn
,
645 char *buf
, size_t buflen
)
651 int tls_connection_enable_workaround(void *ssl_ctx
,
652 struct tls_connection
*conn
)
658 int tls_connection_client_hello_ext(void *ssl_ctx
, struct tls_connection
*conn
,
659 int ext_type
, const u8
*data
,
666 int tls_connection_get_failed(void *ssl_ctx
, struct tls_connection
*conn
)
674 int tls_connection_get_read_alerts(void *ssl_ctx
, struct tls_connection
*conn
)
678 return conn
->read_alerts
;
682 int tls_connection_get_write_alerts(void *ssl_ctx
, struct tls_connection
*conn
)
686 return conn
->write_alerts
;
690 int tls_connection_set_params(void *tls_ctx
, struct tls_connection
*conn
,
691 const struct tls_connection_params
*params
)
693 struct tls_global
*global
= tls_ctx
;
695 SECURITY_STATUS status
;
701 if (global
->my_cert_store
== NULL
&&
702 (global
->my_cert_store
= CertOpenSystemStore(0, TEXT("MY"))) ==
704 wpa_printf(MSG_ERROR
, "%s: CertOpenSystemStore failed - 0x%x",
705 __func__
, (unsigned int) GetLastError());
709 os_memset(&conn
->schannel_cred
, 0, sizeof(conn
->schannel_cred
));
710 conn
->schannel_cred
.dwVersion
= SCHANNEL_CRED_VERSION
;
711 conn
->schannel_cred
.grbitEnabledProtocols
= SP_PROT_TLS1
;
712 algs
[0] = CALG_RSA_KEYX
;
713 conn
->schannel_cred
.cSupportedAlgs
= 1;
714 conn
->schannel_cred
.palgSupportedAlgs
= algs
;
715 conn
->schannel_cred
.dwFlags
|= SCH_CRED_NO_DEFAULT_CREDS
;
717 status
= global
->sspi
->AcquireCredentialsHandleW(
718 NULL
, UNISP_NAME_W
, SECPKG_CRED_OUTBOUND
, NULL
,
719 &conn
->schannel_cred
, NULL
, NULL
, &conn
->creds
, &ts_expiry
);
721 status
= global
->sspi
->AcquireCredentialsHandleA(
722 NULL
, UNISP_NAME_A
, SECPKG_CRED_OUTBOUND
, NULL
,
723 &conn
->schannel_cred
, NULL
, NULL
, &conn
->creds
, &ts_expiry
);
725 if (status
!= SEC_E_OK
) {
726 wpa_printf(MSG_DEBUG
, "%s: AcquireCredentialsHandleA failed - "
727 "0x%x", __func__
, (unsigned int) status
);
735 unsigned int tls_capabilities(void *tls_ctx
)
741 int tls_connection_set_ia(void *tls_ctx
, struct tls_connection
*conn
,
748 struct wpabuf
* tls_connection_ia_send_phase_finished(
749 void *tls_ctx
, struct tls_connection
*conn
, int final
);
755 int tls_connection_ia_final_phase_finished(void *tls_ctx
,
756 struct tls_connection
*conn
)
762 int tls_connection_ia_permute_inner_secret(void *tls_ctx
,
763 struct tls_connection
*conn
,
764 const u8
*key
, size_t key_len
)