2 * Lightweight mbedTLS-based implementation of the schannel (SSL/TLS) provider.
4 * Copyright 2015 Peter Hater
5 * Copyright 2015 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
35 #include "wine/debug.h"
36 #include "wine/library.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(schannel
);
41 #if defined(SONAME_LIBMBEDTLS) && !defined(HAVE_SECURITY_SECURITY_H) && !defined(SONAME_LIBGNUTLS)
43 #include <mbedtls/ssl.h>
44 #include <mbedtls/net_sockets.h>
46 #include <mbedtls/entropy.h>
47 #include <mbedtls/ctr_drbg.h>
48 #include <mbedtls/md_internal.h>
49 #include <mbedtls/ssl_internal.h>
51 #define ROS_SCHAN_IS_BLOCKING(read_len) ((read_len & 0xFFF00000) == 0xCCC00000)
52 #define ROS_SCHAN_IS_BLOCKING_MARSHALL(read_len) ((read_len & 0x000FFFFF) | 0xCCC00000)
53 #define ROS_SCHAN_IS_BLOCKING_RETRIEVE(read_len) (read_len & 0x000FFFFF)
56 /* WINE defines the back-end glue in here */
57 #include "secur32_priv.h"
59 /* in ReactOS we use schannel instead of secur32 */
60 WINE_DEFAULT_DEBUG_CHANNEL(secur32
);
62 /* WINE prefers to keep it optional, disable this to link explicitly */
63 #include "schannel_mbedtls_lazyload.h"
65 /* WINE does not define this standard win32 macro for some reason */
67 #define _countof(a) (sizeof(a)/sizeof(*(a)))
73 mbedtls_ssl_context ssl
;
74 mbedtls_ssl_config conf
;
75 mbedtls_entropy_context entropy
;
76 mbedtls_ctr_drbg_context ctr_drbg
;
77 struct schan_transport
*transport
;
78 } MBEDTLS_SESSION
, *PMBEDTLS_SESSION
;
80 /* custom `net_recv` callback adapter, mbedTLS uses it in mbedtls_ssl_read for
81 pulling data from the underlying win32 net stack */
82 static int schan_pull_adapter(void *session
, unsigned char *buff
, size_t buff_len
)
84 MBEDTLS_SESSION
*s
= session
;
85 size_t requested
= buff_len
;
88 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u)\n", s
, s
->transport
, buff
, buff_len
);
90 status
= schan_pull(s
->transport
, buff
, &buff_len
);
92 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u) status: %#x\n", s
, s
->transport
, buff
, buff_len
, status
);
94 if (status
== NO_ERROR
)
96 /* great, no more data left */
99 TRACE("Connection closed\n");
102 /* there's still some bytes that need pulling */
103 else if (buff_len
< requested
)
105 TRACE("Pulled %u bytes before would block\n", buff_len
);
106 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len
);
110 TRACE("Pulled %u bytes\n", buff_len
);
114 else if (status
== EAGAIN
)
116 TRACE("Would block before being able to pull anything, passing buff_len=%u\n", buff_len
);
117 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len
);
121 ERR("Unknown status code from schan_pull: %d\n", status
);
122 return MBEDTLS_ERR_NET_RECV_FAILED
;
125 /* this should be unreachable */
126 return MBEDTLS_ERR_NET_CONNECT_FAILED
;
129 /* custom `net_send` callback adapter, mbedTLS uses it in mbedtls_ssl_write for
130 pushing data to the underlying win32 net stack */
131 static int schan_push_adapter(void *session
, const unsigned char *buff
, size_t buff_len
)
133 MBEDTLS_SESSION
*s
= session
;
136 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u)\n", s
, s
->transport
, buff
, buff_len
);
138 status
= schan_push(s
->transport
, buff
, &buff_len
);
140 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u) status: %#x\n", s
, s
->transport
, buff
, buff_len
, status
);
142 if (status
== NO_ERROR
)
144 TRACE("Pushed %u bytes\n", buff_len
);
147 else if (status
== EAGAIN
)
149 TRACE("Would block before being able to push anything. passing %u\n", buff_len
);
150 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len
);
154 ERR("Unknown status code from schan_push: %d\n", status
);
155 return MBEDTLS_ERR_NET_SEND_FAILED
;
158 /* this should be unreachable */
159 return MBEDTLS_ERR_NET_CONNECT_FAILED
;
162 DWORD
schan_imp_enabled_protocols(void)
164 /* NOTE: No support for SSL 2.0 */
165 TRACE("MBEDTLS schan_imp_enabled_protocols()\n");
168 #ifdef MBEDTLS_SSL_PROTO_SSL3
169 | SP_PROT_SSL3_CLIENT
| SP_PROT_SSL3_SERVER
171 #ifdef MBEDTLS_SSL_PROTO_TLS1
172 | SP_PROT_TLS1_0_CLIENT
| SP_PROT_TLS1_0_SERVER
174 #ifdef MBEDTLS_SSL_PROTO_TLS1_1
175 | SP_PROT_TLS1_1_CLIENT
| SP_PROT_TLS1_1_SERVER
177 #ifdef MBEDTLS_SSL_PROTO_TLS1_2
178 | SP_PROT_TLS1_2_CLIENT
| SP_PROT_TLS1_2_SERVER
183 static void schan_imp_debug(void *ctx
, int level
, const char *file
, int line
, const char *str
)
185 WARN("MBEDTLS schan_imp_debug: %s:%04d: %s\n", file
, line
, str
);
188 BOOL
schan_imp_create_session(schan_imp_session
*session
, schan_credentials
*cred
)
190 MBEDTLS_SESSION
*s
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MBEDTLS_SESSION
));
192 WARN("MBEDTLS schan_imp_create_session: %p %p %p\n", session
, *session
, cred
);
194 if (!(*session
= (schan_imp_session
)s
))
196 ERR("Not enough memory to create session\n");
200 TRACE("MBEDTLS init entropy\n");
201 mbedtls_entropy_init(&s
->entropy
);
203 TRACE("MBEDTLS init random - change static entropy private data\n");
204 mbedtls_ctr_drbg_init(&s
->ctr_drbg
);
205 mbedtls_ctr_drbg_seed(&s
->ctr_drbg
, mbedtls_entropy_func
, &s
->entropy
, NULL
, 0);
207 WARN("MBEDTLS init ssl\n");
208 mbedtls_ssl_init(&s
->ssl
);
210 WARN("MBEDTLS init conf\n");
211 mbedtls_ssl_config_init(&s
->conf
);
212 mbedtls_ssl_config_defaults(&s
->conf
, MBEDTLS_SSL_IS_CLIENT
,
213 MBEDTLS_SSL_TRANSPORT_STREAM
, MBEDTLS_SSL_PRESET_DEFAULT
);
215 TRACE("MBEDTLS set BIO callbacks\n");
216 mbedtls_ssl_set_bio(&s
->ssl
, s
, schan_push_adapter
, schan_pull_adapter
, NULL
);
218 TRACE("MBEDTLS set endpoint to %s\n", (cred
->credential_use
& SECPKG_CRED_INBOUND
) ? "server" : "client");
219 mbedtls_ssl_conf_endpoint(&s
->conf
, (cred
->credential_use
& SECPKG_CRED_INBOUND
) ? MBEDTLS_SSL_IS_SERVER
:
220 MBEDTLS_SSL_IS_CLIENT
);
222 TRACE("MBEDTLS set authmode\n");
223 mbedtls_ssl_conf_authmode(&s
->conf
, MBEDTLS_SSL_VERIFY_NONE
);
225 TRACE("MBEDTLS set rng\n");
226 mbedtls_ssl_conf_rng(&s
->conf
, mbedtls_ctr_drbg_random
, &s
->ctr_drbg
);
228 TRACE("MBEDTLS set dbg\n");
229 mbedtls_ssl_conf_dbg(&s
->conf
, schan_imp_debug
, stdout
);
231 TRACE("MBEDTLS setup\n");
232 mbedtls_ssl_setup(&s
->ssl
, &s
->conf
);
234 TRACE("MBEDTLS schan_imp_create_session END!\n");
238 void schan_imp_dispose_session(schan_imp_session session
)
240 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
241 WARN("MBEDTLS schan_imp_dispose_session: %p\n", session
);
243 /* tell the other peer (a server) that we are going away */
244 //ssl_close_notify(&s->ssl);
246 mbedtls_ssl_free(&s
->ssl
);
247 mbedtls_ctr_drbg_free(&s
->ctr_drbg
);
248 mbedtls_entropy_free(&s
->entropy
);
249 mbedtls_ssl_config_free(&s
->conf
);
251 /* safely overwrite the freed context with zeroes */
252 HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY
, s
);
255 void schan_imp_set_session_transport(schan_imp_session session
,
256 struct schan_transport
*t
)
258 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
260 TRACE("MBEDTLS schan_imp_set_session_transport: %p %p\n", session
, t
);
265 void schan_imp_set_session_target(schan_imp_session session
, const char *target
)
267 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
269 TRACE("MBEDTLS schan_imp_set_session_target: sess: %p hostname: %s\n", session
, target
);
271 /* FIXME: WINE tests do not pass when we set the hostname because in the test cases
272 * contacting 'www.winehq.org' the hostname is defined as 'localhost' so the server
273 * sends a non-fatal alert which preemptively forces mbedTLS to close connection. */
275 mbedtls_ssl_set_hostname(&s
->ssl
, target
);
278 SECURITY_STATUS
schan_imp_handshake(schan_imp_session session
)
280 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
282 int err
= mbedtls_ssl_handshake(&s
->ssl
);
284 TRACE("MBEDTLS schan_imp_handshake: %p err: %#x \n", session
, err
);
286 if (ROS_SCHAN_IS_BLOCKING(err
))
288 TRACE("Received ERR_NET_WANT_READ/WRITE... let's try again!\n");
289 return SEC_I_CONTINUE_NEEDED
;
291 else if (err
== MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE
)
293 ERR("schan_imp_handshake: SSL Feature unavailable...\n");
294 return SEC_E_UNSUPPORTED_FUNCTION
;
298 ERR("schan_imp_handshake: Oops! mbedtls_ssl_handshake returned the following error code: -%#x...\n", -err
);
299 return SEC_E_INTERNAL_ERROR
;
302 WARN("schan_imp_handshake: Handshake completed!\n");
303 WARN("schan_imp_handshake: Protocol is %s, Cipher suite is %s\n", mbedtls_ssl_get_version(&s
->ssl
),
304 mbedtls_ssl_get_ciphersuite(&s
->ssl
));
308 static unsigned int schannel_get_cipher_key_size(int ciphersuite_id
)
310 const mbedtls_ssl_ciphersuite_t
*ssl_cipher_suite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
311 const mbedtls_cipher_info_t
*cipher_info
= mbedtls_cipher_info_from_type(ssl_cipher_suite
->cipher
);
313 unsigned int key_bitlen
= cipher_info
->key_bitlen
;
315 TRACE("MBEDTLS schannel_get_cipher_key_size: Unknown cipher %#x, returning %u\n", ciphersuite_id
, key_bitlen
);
320 static unsigned int schannel_get_mac_key_size(int ciphersuite_id
)
322 const mbedtls_ssl_ciphersuite_t
*ssl_cipher_suite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
323 const mbedtls_md_info_t
*md_info
= mbedtls_md_info_from_type(ssl_cipher_suite
->mac
);
325 int md_size
= md_info
->size
* CHAR_BIT
; /* return the size in bits, as the secur32:schannel winetest shows */
327 TRACE("MBEDTLS schannel_get_mac_key_size: returning %i\n", md_size
);
332 static unsigned int schannel_get_kx_key_size(const mbedtls_ssl_context
*ssl
, const mbedtls_ssl_config
*conf
, int ciphersuite_id
)
334 const mbedtls_ssl_ciphersuite_t
*ssl_ciphersuite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
336 /* if we are the server take ca_chain, if we are the client take the proper x509 peer certificate */
337 const mbedtls_x509_crt
*server_cert
= (conf
->endpoint
== MBEDTLS_SSL_IS_SERVER
) ? conf
->ca_chain
: mbedtls_ssl_get_peer_cert(ssl
);
339 if (ssl_ciphersuite
->key_exchange
!= MBEDTLS_KEY_EXCHANGE_NONE
)
340 return mbedtls_pk_get_len(&(server_cert
->pk
));
342 TRACE("MBEDTLS schannel_get_kx_key_size: Unknown kx %#x, returning 0\n", ssl_ciphersuite
->key_exchange
);
347 static DWORD
schannel_get_protocol(const mbedtls_ssl_context
*ssl
, const mbedtls_ssl_config
*conf
)
349 /* FIXME: currently schannel only implements client connections, but
350 * there's no reason it couldn't be used for servers as well. The
351 * context doesn't tell us which it is, so decide based on ssl endpoint value. */
353 switch (ssl
->minor_ver
)
355 case MBEDTLS_SSL_MINOR_VERSION_0
:
356 return (conf
->endpoint
== MBEDTLS_SSL_IS_CLIENT
) ? SP_PROT_SSL3_CLIENT
:
359 case MBEDTLS_SSL_MINOR_VERSION_1
:
360 return (conf
->endpoint
== MBEDTLS_SSL_IS_CLIENT
) ? SP_PROT_TLS1_0_CLIENT
:
361 SP_PROT_TLS1_0_SERVER
;
363 case MBEDTLS_SSL_MINOR_VERSION_2
:
364 return (conf
->endpoint
== MBEDTLS_SSL_IS_CLIENT
) ? SP_PROT_TLS1_1_CLIENT
:
365 SP_PROT_TLS1_1_SERVER
;
367 case MBEDTLS_SSL_MINOR_VERSION_3
:
368 return (conf
->endpoint
== MBEDTLS_SSL_IS_CLIENT
) ? SP_PROT_TLS1_2_CLIENT
:
369 SP_PROT_TLS1_2_SERVER
;
373 FIXME("MBEDTLS schannel_get_protocol: unknown protocol %d\n", ssl
->minor_ver
);
379 static ALG_ID
schannel_get_cipher_algid(int ciphersuite_id
)
381 const mbedtls_ssl_ciphersuite_t
*cipher_suite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
383 switch (cipher_suite
->cipher
)
385 case MBEDTLS_CIPHER_NONE
:
386 case MBEDTLS_CIPHER_NULL
:
389 #ifdef MBEDTLS_ARC4_C
391 case MBEDTLS_CIPHER_ARC4_128
:
397 case MBEDTLS_CIPHER_DES_ECB
:
398 case MBEDTLS_CIPHER_DES_CBC
:
399 case MBEDTLS_CIPHER_DES_EDE_ECB
:
400 case MBEDTLS_CIPHER_DES_EDE_CBC
:
403 case MBEDTLS_CIPHER_DES_EDE3_ECB
:
404 case MBEDTLS_CIPHER_DES_EDE3_CBC
:
408 #ifdef MBEDTLS_BLOWFISH_C
410 case MBEDTLS_CIPHER_BLOWFISH_ECB
:
411 case MBEDTLS_CIPHER_BLOWFISH_CBC
:
412 case MBEDTLS_CIPHER_BLOWFISH_CFB64
:
413 case MBEDTLS_CIPHER_BLOWFISH_CTR
:
414 return CALG_RC4
; // (as schannel does not support it fake it as RC4, which has a
415 // similar profile of low footprint and medium-high security) CALG_BLOWFISH;
418 #ifdef MBEDTLS_CAMELLIA_C
420 case MBEDTLS_CIPHER_CAMELLIA_128_ECB
:
421 case MBEDTLS_CIPHER_CAMELLIA_192_ECB
:
422 case MBEDTLS_CIPHER_CAMELLIA_256_ECB
:
423 case MBEDTLS_CIPHER_CAMELLIA_128_CBC
:
424 case MBEDTLS_CIPHER_CAMELLIA_192_CBC
:
425 case MBEDTLS_CIPHER_CAMELLIA_256_CBC
:
426 case MBEDTLS_CIPHER_CAMELLIA_128_CFB128
:
427 case MBEDTLS_CIPHER_CAMELLIA_192_CFB128
:
428 case MBEDTLS_CIPHER_CAMELLIA_256_CFB128
:
429 case MBEDTLS_CIPHER_CAMELLIA_128_CTR
:
430 case MBEDTLS_CIPHER_CAMELLIA_192_CTR
:
431 case MBEDTLS_CIPHER_CAMELLIA_256_CTR
:
432 case MBEDTLS_CIPHER_CAMELLIA_128_GCM
:
433 case MBEDTLS_CIPHER_CAMELLIA_192_GCM
:
434 case MBEDTLS_CIPHER_CAMELLIA_256_GCM
:
435 return CALG_AES_256
; // (as schannel does not support it fake it as AES, which has a
436 // similar profile, offering modern high security) CALG_CAMELLIA;
441 case MBEDTLS_CIPHER_AES_128_ECB
:
442 case MBEDTLS_CIPHER_AES_128_CBC
:
443 case MBEDTLS_CIPHER_AES_128_CFB128
:
444 case MBEDTLS_CIPHER_AES_128_CTR
:
445 case MBEDTLS_CIPHER_AES_128_GCM
:
447 case MBEDTLS_CIPHER_AES_128_CCM
:
451 case MBEDTLS_CIPHER_AES_192_ECB
:
452 case MBEDTLS_CIPHER_AES_192_CBC
:
453 case MBEDTLS_CIPHER_AES_192_CFB128
:
454 case MBEDTLS_CIPHER_AES_192_CTR
:
455 case MBEDTLS_CIPHER_AES_192_GCM
:
457 case MBEDTLS_CIPHER_AES_192_CCM
:
461 case MBEDTLS_CIPHER_AES_256_ECB
:
462 case MBEDTLS_CIPHER_AES_256_CBC
:
463 case MBEDTLS_CIPHER_AES_256_CFB128
:
464 case MBEDTLS_CIPHER_AES_256_CTR
:
465 case MBEDTLS_CIPHER_AES_256_GCM
:
467 case MBEDTLS_CIPHER_AES_256_CCM
:
472 /* nothing to show? fall through */
475 FIXME("MBEDTLS schannel_get_cipher_algid: unknown algorithm %d\n", ciphersuite_id
);
481 static ALG_ID
schannel_get_mac_algid(int ciphersuite_id
)
483 const mbedtls_ssl_ciphersuite_t
*cipher_suite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
485 switch (cipher_suite
->mac
)
487 case MBEDTLS_MD_NONE
: return 0;
488 case MBEDTLS_MD_MD2
: return CALG_MD2
;
489 case MBEDTLS_MD_MD4
: return CALG_MD4
;
490 case MBEDTLS_MD_MD5
: return CALG_MD5
;
491 case MBEDTLS_MD_SHA1
: return CALG_SHA1
;
492 case MBEDTLS_MD_SHA224
: return CALG_SHA
;
493 case MBEDTLS_MD_SHA256
: return CALG_SHA_256
;
494 case MBEDTLS_MD_SHA384
: return CALG_SHA_384
;
495 case MBEDTLS_MD_SHA512
: return CALG_SHA_512
;
496 case MBEDTLS_MD_RIPEMD160
: return (ALG_CLASS_HASH
| ALG_TYPE_ANY
| ALG_SID_RIPEMD160
); /* there's no CALG_RIPEMD or CALG_RIPEMD160 defined in <wincrypt.h> yet */
500 FIXME("MBEDTLS schannel_get_mac_algid: unknown algorithm %d\n", cipher_suite
->mac
);
506 static ALG_ID
schannel_get_kx_algid(int ciphersuite_id
)
508 const mbedtls_ssl_ciphersuite_t
*cipher_suite
= mbedtls_ssl_ciphersuite_from_id(ciphersuite_id
);
510 switch (cipher_suite
->key_exchange
)
512 case MBEDTLS_KEY_EXCHANGE_NONE
:
513 case MBEDTLS_KEY_EXCHANGE_PSK
: /* the original implementation does not support */
514 return 0; /* any PSK, and does not define any `CALG_PSK` :) */
516 case MBEDTLS_KEY_EXCHANGE_RSA
:
517 case MBEDTLS_KEY_EXCHANGE_RSA_PSK
:
518 return CALG_RSA_KEYX
;
520 case MBEDTLS_KEY_EXCHANGE_DHE_RSA
:
521 case MBEDTLS_KEY_EXCHANGE_DHE_PSK
:
522 return CALG_DH_EPHEM
;
524 case MBEDTLS_KEY_EXCHANGE_ECDH_RSA
:
525 case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA
:
528 case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA
:
529 case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
:
530 case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
:
531 return CALG_ECDH_EPHEM
;
535 FIXME("MBEDTLS schannel_get_kx_algid: unknown algorithm %d\n", cipher_suite
->key_exchange
);
541 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session
)
543 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
545 unsigned int cipher_block_size
= mbedtls_cipher_get_block_size(&s
->ssl
.transform
->cipher_ctx_enc
);
547 TRACE("MBEDTLS schan_imp_get_session_cipher_block_size %p returning %u.\n", session
, cipher_block_size
);
549 return cipher_block_size
;
552 unsigned int schan_imp_get_max_message_size(schan_imp_session session
)
554 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
556 unsigned int max_frag_len
= mbedtls_ssl_get_max_frag_len(&s
->ssl
);
558 TRACE("MBEDTLS schan_imp_get_max_message_size %p returning %u.\n", session
, max_frag_len
);
563 SECURITY_STATUS
schan_imp_get_connection_info(schan_imp_session session
,
564 SecPkgContext_ConnectionInfo
*info
)
566 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
568 int ciphersuite_id
= mbedtls_ssl_get_ciphersuite_id(mbedtls_ssl_get_ciphersuite(&s
->ssl
));
570 TRACE("MBEDTLS schan_imp_get_connection_info %p %p.\n", session
, info
);
572 info
->dwProtocol
= schannel_get_protocol(&s
->ssl
, &s
->conf
);
573 info
->aiCipher
= schannel_get_cipher_algid(ciphersuite_id
);
574 info
->dwCipherStrength
= schannel_get_cipher_key_size(ciphersuite_id
);
575 info
->aiHash
= schannel_get_mac_algid(ciphersuite_id
);
576 info
->dwHashStrength
= schannel_get_mac_key_size(ciphersuite_id
);
577 info
->aiExch
= schannel_get_kx_algid(ciphersuite_id
);
578 info
->dwExchStrength
= schannel_get_kx_key_size(&s
->ssl
, &s
->conf
, ciphersuite_id
);
583 SECURITY_STATUS
schan_imp_get_session_peer_certificate(schan_imp_session session
, HCERTSTORE store
,
586 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
587 PCCERT_CONTEXT cert_context
= NULL
;
589 const mbedtls_x509_crt
*next_cert
;
590 const mbedtls_x509_crt
*peer_cert
= mbedtls_ssl_get_peer_cert(&s
->ssl
);
592 TRACE("MBEDTLS schan_imp_get_session_peer_certificate %p %p %p %p.\n", session
, store
, ret
, ret
!= NULL
? *ret
: NULL
);
595 return SEC_E_INTERNAL_ERROR
;
597 for (next_cert
= peer_cert
; next_cert
!= NULL
; next_cert
= next_cert
->next
)
599 if (!CertAddEncodedCertificateToStore(store
, X509_ASN_ENCODING
, next_cert
->raw
.p
, next_cert
->raw
.len
,
600 CERT_STORE_ADD_REPLACE_EXISTING
, (next_cert
!= peer_cert
) ? NULL
: &cert_context
))
602 if (next_cert
!= peer_cert
)
603 CertFreeCertificateContext(cert_context
);
604 return GetLastError();
612 SECURITY_STATUS
schan_imp_send(schan_imp_session session
, const void *buffer
,
615 MBEDTLS_SESSION
*s
= (MBEDTLS_SESSION
*)session
;
618 ret
= mbedtls_ssl_write(&s
->ssl
, (unsigned char *)buffer
, *length
);
620 TRACE("MBEDTLS schan_imp_send: (%p, %p, %p/%lu)\n", s
, buffer
, length
, *length
);
624 TRACE("MBEDTLS schan_imp_send: ret=%i.\n", ret
);
628 else if (ROS_SCHAN_IS_BLOCKING(ret
))
630 *length
= ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret
);
634 TRACE("MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu", *length
);
635 return SEC_I_CONTINUE_NEEDED
;
639 TRACE("MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length
);
645 ERR("MBEDTLS schan_imp_send: mbedtls_ssl_write failed with -%x\n", -ret
);
646 return SEC_E_INTERNAL_ERROR
;
652 SECURITY_STATUS
schan_imp_recv(schan_imp_session session
, void *buffer
,
655 PMBEDTLS_SESSION s
= (PMBEDTLS_SESSION
)session
;
658 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu)\n", s
, buffer
, length
, *length
);
660 ret
= mbedtls_ssl_read(&s
->ssl
, (unsigned char *)buffer
, *length
);
662 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu) ret= %#x\n", s
, buffer
, length
, *length
, ret
);
666 TRACE("MBEDTLS schan_imp_recv: ret == %i.\n", ret
);
670 else if (ROS_SCHAN_IS_BLOCKING(ret
))
672 *length
= ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret
);
676 TRACE("MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu", *length
);
677 return SEC_I_CONTINUE_NEEDED
;
681 TRACE("MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length
);
685 else if (ret
== MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY
)
688 TRACE("MBEDTLS schan_imp_recv: ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -> SEC_E_OK\n");
693 ERR("MBEDTLS schan_imp_recv: mbedtls_ssl_read failed with -%x\n", -ret
);
694 return SEC_E_INTERNAL_ERROR
;
700 BOOL
schan_imp_allocate_certificate_credentials(schan_credentials
*c
)
702 TRACE("MBEDTLS schan_imp_allocate_certificate_credentials %p %p %d\n", c
, c
->credentials
, c
->credential_use
);
704 /* in our case credentials aren't really used for anything, so just stub them */
705 c
->credentials
= NULL
;
709 void schan_imp_free_certificate_credentials(schan_credentials
*c
)
711 TRACE("MBEDTLS schan_imp_free_certificate_credentials %p %p %d\n", c
, c
->credentials
, c
->credential_use
);
714 BOOL
schan_imp_init(void)
716 TRACE("Schannel MBEDTLS schan_imp_init\n");
720 void schan_imp_deinit(void)
722 WARN("Schannel MBEDTLS schan_imp_deinit\n");
725 #endif /* SONAME_LIBMBEDTLS && !HAVE_SECURITY_SECURITY_H && !SONAME_LIBGNUTLS */