[SCHANNEL]
[reactos.git] / reactos / dll / win32 / schannel / schannel_mbedtls.c
1 /*
2 * Lightweight mbedTLS-based implementation of the schannel (SSL/TLS) provider.
3 *
4 * Copyright 2015 Peter Hater
5 * Copyright 2015 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com>
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #ifdef __REACTOS__
26 #include "precomp.h"
27 #else
28 #include <stdarg.h>
29 #include <errno.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "sspi.h"
34 #include "schannel.h"
35 #include "wine/debug.h"
36 #include "wine/library.h"
37 #endif
38
39 #if defined(SONAME_LIBMBEDTLS) && !defined(HAVE_SECURITY_SECURITY_H) && !defined(SONAME_LIBGNUTLS)
40
41 #include <mbedtls/ssl.h>
42 #include <mbedtls/net.h>
43
44 #include <mbedtls/entropy.h>
45 #include <mbedtls/ctr_drbg.h>
46 #include <mbedtls/md_internal.h>
47 #include <mbedtls/ssl_internal.h>
48
49 #define ROS_SCHAN_IS_BLOCKING(read_len) ((read_len & 0xFFF00000) == 0xCCC00000)
50 #define ROS_SCHAN_IS_BLOCKING_MARSHALL(read_len) ((read_len & 0x000FFFFF) | 0xCCC00000)
51 #define ROS_SCHAN_IS_BLOCKING_RETRIEVE(read_len) (read_len & 0x000FFFFF)
52
53 #ifndef __REACTOS__
54 /* WINE defines the back-end glue in here */
55 #include "secur32_priv.h"
56
57 /* in ReactOS we use schannel instead of secur32 */
58 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
59
60 /* WINE prefers to keep it optional, disable this to link explicitly */
61 #include "schannel_mbedtls_lazyload.h"
62
63 /* WINE does not define this standard win32 macro for some reason */
64 #ifndef _countof
65 #define _countof(a) (sizeof(a)/sizeof(*(a)))
66 #endif
67 #endif
68
69 typedef struct
70 {
71 mbedtls_ssl_context ssl;
72 mbedtls_ssl_config conf;
73 mbedtls_entropy_context entropy;
74 mbedtls_ctr_drbg_context ctr_drbg;
75 struct schan_transport *transport;
76 } MBEDTLS_SESSION, *PMBEDTLS_SESSION;
77
78 /* custom `net_recv` callback adapter, mbedTLS uses it in mbedtls_ssl_read for
79 pulling data from the underlying win32 net stack */
80 static int schan_pull_adapter(void *session, unsigned char *buff, size_t buff_len)
81 {
82 MBEDTLS_SESSION *s = session;
83 size_t requested = buff_len;
84 int status;
85
86 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u)\n", s, s->transport, buff, buff_len);
87
88 status = schan_pull(s->transport, buff, &buff_len);
89
90 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u) status: %#x\n", s, s->transport, buff, buff_len, status);
91
92 if (status == NO_ERROR)
93 {
94 /* great, no more data left */
95 if (buff_len == 0)
96 {
97 TRACE("Connection closed\n");
98 return 0;
99 }
100 /* there's still some bytes that need pulling */
101 else if (buff_len < requested)
102 {
103 TRACE("Pulled %u bytes before would block\n", buff_len);
104 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len);
105 }
106 else
107 {
108 TRACE("Pulled %u bytes\n", buff_len);
109 return buff_len;
110 }
111 }
112 else if (status == EAGAIN)
113 {
114 TRACE("Would block before being able to pull anything, passing buff_len=%u\n", buff_len);
115 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len);
116 }
117 else
118 {
119 ERR("Unknown status code from schan_pull: %d\n", status);
120 return MBEDTLS_ERR_NET_RECV_FAILED;
121 }
122
123 /* this should be unreachable */
124 return MBEDTLS_ERR_NET_CONNECT_FAILED;
125 }
126
127 /* custom `net_send` callback adapter, mbedTLS uses it in mbedtls_ssl_write for
128 pushing data to the underlying win32 net stack */
129 static int schan_push_adapter(void *session, const unsigned char *buff, size_t buff_len)
130 {
131 MBEDTLS_SESSION *s = session;
132 int status;
133
134 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u)\n", s, s->transport, buff, buff_len);
135
136 status = schan_push(s->transport, buff, &buff_len);
137
138 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u) status: %#x\n", s, s->transport, buff, buff_len, status);
139
140 if (status == NO_ERROR)
141 {
142 TRACE("Pushed %u bytes\n", buff_len);
143 return buff_len;
144 }
145 else if (status == EAGAIN)
146 {
147 TRACE("Would block before being able to push anything. passing %u\n", buff_len);
148 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len);
149 }
150 else
151 {
152 ERR("Unknown status code from schan_push: %d\n", status);
153 return MBEDTLS_ERR_NET_SEND_FAILED;
154 }
155
156 /* this should be unreachable */
157 return MBEDTLS_ERR_NET_CONNECT_FAILED;
158 }
159
160 DWORD schan_imp_enabled_protocols(void)
161 {
162 /* NOTE: No support for SSL 2.0 */
163 TRACE("MBEDTLS schan_imp_enabled_protocols()\n");
164
165 return 0
166 #ifdef MBEDTLS_SSL_PROTO_SSL3
167 | SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER
168 #endif
169 #ifdef MBEDTLS_SSL_PROTO_TLS1
170 | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER
171 #endif
172 #ifdef MBEDTLS_SSL_PROTO_TLS1_1
173 | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER
174 #endif
175 #ifdef MBEDTLS_SSL_PROTO_TLS1_2
176 | SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER
177 #endif
178 ;
179 }
180
181 static void schan_imp_debug(void *ctx, int level, const char *file, int line, const char *str)
182 {
183 WARN("MBEDTLS schan_imp_debug: %s:%04d: %s\n", file, line, str);
184 }
185
186 BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred)
187 {
188 MBEDTLS_SESSION *s = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MBEDTLS_SESSION));
189
190 WARN("MBEDTLS schan_imp_create_session: %p %p %p\n", session, *session, cred);
191
192 if (!(*session = (schan_imp_session)s))
193 {
194 ERR("Not enough memory to create session\n");
195 return FALSE;
196 }
197
198 TRACE("MBEDTLS init entropy\n");
199 mbedtls_entropy_init(&s->entropy);
200
201 TRACE("MBEDTLS init random - change static entropy private data\n");
202 mbedtls_ctr_drbg_init(&s->ctr_drbg);
203 mbedtls_ctr_drbg_seed(&s->ctr_drbg, mbedtls_entropy_func, &s->entropy, NULL, 0);
204
205 WARN("MBEDTLS init ssl\n");
206 mbedtls_ssl_init(&s->ssl);
207
208 WARN("MBEDTLS init conf\n");
209 mbedtls_ssl_config_init(&s->conf);
210 mbedtls_ssl_config_defaults(&s->conf, MBEDTLS_SSL_IS_CLIENT,
211 MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
212
213 TRACE("MBEDTLS set BIO callbacks\n");
214 mbedtls_ssl_set_bio(&s->ssl, s, schan_push_adapter, schan_pull_adapter, NULL);
215
216 TRACE("MBEDTLS set endpoint to %s\n", (cred->credential_use & SECPKG_CRED_INBOUND) ? "server" : "client");
217 mbedtls_ssl_conf_endpoint(&s->conf, (cred->credential_use & SECPKG_CRED_INBOUND) ? MBEDTLS_SSL_IS_SERVER :
218 MBEDTLS_SSL_IS_CLIENT);
219
220 TRACE("MBEDTLS set authmode\n");
221 mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_NONE);
222
223 TRACE("MBEDTLS set rng\n");
224 mbedtls_ssl_conf_rng(&s->conf, mbedtls_ctr_drbg_random, &s->ctr_drbg);
225
226 TRACE("MBEDTLS set dbg\n");
227 mbedtls_ssl_conf_dbg(&s->conf, schan_imp_debug, stdout);
228
229 TRACE("MBEDTLS setup\n");
230 mbedtls_ssl_setup(&s->ssl, &s->conf);
231
232 TRACE("MBEDTLS schan_imp_create_session END!\n");
233 return TRUE;
234 }
235
236 void schan_imp_dispose_session(schan_imp_session session)
237 {
238 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
239 WARN("MBEDTLS schan_imp_dispose_session: %p\n", session);
240
241 /* tell the other peer (a server) that we are going away */
242 //ssl_close_notify(&s->ssl);
243
244 mbedtls_ssl_free(&s->ssl);
245 mbedtls_ctr_drbg_free(&s->ctr_drbg);
246 mbedtls_entropy_free(&s->entropy);
247 mbedtls_ssl_config_free(&s->conf);
248
249 /* safely overwrite the freed context with zeroes */
250 HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, s);
251 }
252
253 void schan_imp_set_session_transport(schan_imp_session session,
254 struct schan_transport *t)
255 {
256 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
257
258 TRACE("MBEDTLS schan_imp_set_session_transport: %p %p\n", session, t);
259
260 s->transport = t;
261 }
262
263 void schan_imp_set_session_target(schan_imp_session session, const char *target)
264 {
265 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
266
267 TRACE("MBEDTLS schan_imp_set_session_target: sess: %p hostname: %s\n", session, target);
268
269 /* FIXME: WINE tests do not pass when we set the hostname because in the test cases
270 * contacting 'www.winehq.org' the hostname is defined as 'localhost' so the server
271 * sends a non-fatal alert which preemptively forces mbedTLS to close connection. */
272
273 mbedtls_ssl_set_hostname(&s->ssl, target);
274 }
275
276 SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
277 {
278 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
279
280 int err = mbedtls_ssl_handshake(&s->ssl);
281
282 TRACE("MBEDTLS schan_imp_handshake: %p err: %#x \n", session, err);
283
284 if (ROS_SCHAN_IS_BLOCKING(err))
285 {
286 TRACE("Received ERR_NET_WANT_READ/WRITE... let's try again!\n");
287 return SEC_I_CONTINUE_NEEDED;
288 }
289 else if (err == MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE)
290 {
291 ERR("schan_imp_handshake: SSL Feature unavailable...\n");
292 return SEC_E_UNSUPPORTED_FUNCTION;
293 }
294 else if (err != 0)
295 {
296 ERR("schan_imp_handshake: Oops! mbedtls_ssl_handshake returned the following error code: -%#x...\n", -err);
297 return SEC_E_INTERNAL_ERROR;
298 }
299
300 WARN("schan_imp_handshake: Handshake completed!\n");
301 WARN("schan_imp_handshake: Protocol is %s, Cipher suite is %s\n", mbedtls_ssl_get_version(&s->ssl),
302 mbedtls_ssl_get_ciphersuite(&s->ssl));
303 return SEC_E_OK;
304 }
305
306 static unsigned int schannel_get_cipher_key_size(int ciphersuite_id)
307 {
308 const mbedtls_ssl_ciphersuite_t *ssl_cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
309 const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type(ssl_cipher_suite->cipher);
310
311 unsigned int key_bitlen = cipher_info->key_bitlen;
312
313 TRACE("MBEDTLS schannel_get_cipher_key_size: Unknown cipher %#x, returning %u\n", ciphersuite_id, key_bitlen);
314
315 return key_bitlen;
316 }
317
318 static unsigned int schannel_get_mac_key_size(int ciphersuite_id)
319 {
320 const mbedtls_ssl_ciphersuite_t *ssl_cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
321 const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(ssl_cipher_suite->mac);
322
323 int md_size = md_info->size * CHAR_BIT; /* return the size in bits, as the secur32:schannel winetest shows */
324
325 TRACE("MBEDTLS schannel_get_mac_key_size: returning %i\n", md_size);
326
327 return md_size;
328 }
329
330 static unsigned int schannel_get_kx_key_size(const mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf, int ciphersuite_id)
331 {
332 const mbedtls_ssl_ciphersuite_t *ssl_ciphersuite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
333
334 /* if we are the server take ca_chain, if we are the client take the proper x509 peer certificate */
335 const mbedtls_x509_crt *server_cert = (conf->endpoint == MBEDTLS_SSL_IS_SERVER) ? conf->ca_chain : mbedtls_ssl_get_peer_cert(ssl);
336
337 if (ssl_ciphersuite->key_exchange != MBEDTLS_KEY_EXCHANGE_NONE)
338 return mbedtls_pk_get_len(&(server_cert->pk));
339
340 TRACE("MBEDTLS schannel_get_kx_key_size: Unknown kx %#x, returning 0\n", ssl_ciphersuite->key_exchange);
341
342 return 0;
343 }
344
345 static DWORD schannel_get_protocol(const mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf)
346 {
347 /* FIXME: currently schannel only implements client connections, but
348 * there's no reason it couldn't be used for servers as well. The
349 * context doesn't tell us which it is, so decide based on ssl endpoint value. */
350
351 switch (ssl->minor_ver)
352 {
353 case MBEDTLS_SSL_MINOR_VERSION_0:
354 return (conf->endpoint == MBEDTLS_SSL_IS_CLIENT) ? SP_PROT_SSL3_CLIENT :
355 SP_PROT_SSL3_SERVER;
356
357 case MBEDTLS_SSL_MINOR_VERSION_1:
358 return (conf->endpoint == MBEDTLS_SSL_IS_CLIENT) ? SP_PROT_TLS1_0_CLIENT :
359 SP_PROT_TLS1_0_SERVER;
360
361 case MBEDTLS_SSL_MINOR_VERSION_2:
362 return (conf->endpoint == MBEDTLS_SSL_IS_CLIENT) ? SP_PROT_TLS1_1_CLIENT :
363 SP_PROT_TLS1_1_SERVER;
364
365 case MBEDTLS_SSL_MINOR_VERSION_3:
366 return (conf->endpoint == MBEDTLS_SSL_IS_CLIENT) ? SP_PROT_TLS1_2_CLIENT :
367 SP_PROT_TLS1_2_SERVER;
368
369 default:
370 {
371 FIXME("MBEDTLS schannel_get_protocol: unknown protocol %d\n", ssl->minor_ver);
372 return 0;
373 }
374 }
375 }
376
377 static ALG_ID schannel_get_cipher_algid(int ciphersuite_id)
378 {
379 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
380
381 switch (cipher_suite->cipher)
382 {
383 case MBEDTLS_CIPHER_NONE:
384 case MBEDTLS_CIPHER_NULL:
385 return 0;
386
387 #ifdef MBEDTLS_ARC4_C
388 /* ARC4 */
389 case MBEDTLS_CIPHER_ARC4_128:
390 return CALG_RC4;
391 #endif
392
393 #ifdef MBEDTLS_DES_C
394 /* DES */
395 case MBEDTLS_CIPHER_DES_ECB:
396 case MBEDTLS_CIPHER_DES_CBC:
397 case MBEDTLS_CIPHER_DES_EDE_ECB:
398 case MBEDTLS_CIPHER_DES_EDE_CBC:
399 return CALG_DES;
400
401 case MBEDTLS_CIPHER_DES_EDE3_ECB:
402 case MBEDTLS_CIPHER_DES_EDE3_CBC:
403 return CALG_3DES;
404 #endif
405
406 #ifdef MBEDTLS_BLOWFISH_C
407 /* BLOWFISH */
408 case MBEDTLS_CIPHER_BLOWFISH_ECB:
409 case MBEDTLS_CIPHER_BLOWFISH_CBC:
410 case MBEDTLS_CIPHER_BLOWFISH_CFB64:
411 case MBEDTLS_CIPHER_BLOWFISH_CTR:
412 return CALG_RC4; // (as schannel does not support it fake it as RC4, which has a
413 // similar profile of low footprint and medium-high security) CALG_BLOWFISH;
414 #endif
415
416 #ifdef MBEDTLS_CAMELLIA_C
417 /* CAMELLIA */
418 case MBEDTLS_CIPHER_CAMELLIA_128_ECB:
419 case MBEDTLS_CIPHER_CAMELLIA_192_ECB:
420 case MBEDTLS_CIPHER_CAMELLIA_256_ECB:
421 case MBEDTLS_CIPHER_CAMELLIA_128_CBC:
422 case MBEDTLS_CIPHER_CAMELLIA_192_CBC:
423 case MBEDTLS_CIPHER_CAMELLIA_256_CBC:
424 case MBEDTLS_CIPHER_CAMELLIA_128_CFB128:
425 case MBEDTLS_CIPHER_CAMELLIA_192_CFB128:
426 case MBEDTLS_CIPHER_CAMELLIA_256_CFB128:
427 case MBEDTLS_CIPHER_CAMELLIA_128_CTR:
428 case MBEDTLS_CIPHER_CAMELLIA_192_CTR:
429 case MBEDTLS_CIPHER_CAMELLIA_256_CTR:
430 case MBEDTLS_CIPHER_CAMELLIA_128_GCM:
431 case MBEDTLS_CIPHER_CAMELLIA_192_GCM:
432 case MBEDTLS_CIPHER_CAMELLIA_256_GCM:
433 return CALG_AES_256; // (as schannel does not support it fake it as AES, which has a
434 // similar profile, offering modern high security) CALG_CAMELLIA;
435 #endif
436
437 #ifdef MBEDTLS_AES_C
438 /* AES 128 */
439 case MBEDTLS_CIPHER_AES_128_ECB:
440 case MBEDTLS_CIPHER_AES_128_CBC:
441 case MBEDTLS_CIPHER_AES_128_CFB128:
442 case MBEDTLS_CIPHER_AES_128_CTR:
443 case MBEDTLS_CIPHER_AES_128_GCM:
444 #ifdef MBEDTLS_CCM_C
445 case MBEDTLS_CIPHER_AES_128_CCM:
446 #endif
447 return CALG_AES_128;
448
449 case MBEDTLS_CIPHER_AES_192_ECB:
450 case MBEDTLS_CIPHER_AES_192_CBC:
451 case MBEDTLS_CIPHER_AES_192_CFB128:
452 case MBEDTLS_CIPHER_AES_192_CTR:
453 case MBEDTLS_CIPHER_AES_192_GCM:
454 #ifdef MBEDTLS_CCM_C
455 case MBEDTLS_CIPHER_AES_192_CCM:
456 #endif
457 return CALG_AES_192;
458
459 case MBEDTLS_CIPHER_AES_256_ECB:
460 case MBEDTLS_CIPHER_AES_256_CBC:
461 case MBEDTLS_CIPHER_AES_256_CFB128:
462 case MBEDTLS_CIPHER_AES_256_CTR:
463 case MBEDTLS_CIPHER_AES_256_GCM:
464 #ifdef MBEDTLS_CCM_C
465 case MBEDTLS_CIPHER_AES_256_CCM:
466 #endif
467 return CALG_AES_256;
468 #endif
469
470 /* nothing to show? fall through */
471 default:
472 {
473 FIXME("MBEDTLS schannel_get_cipher_algid: unknown algorithm %d\n", ciphersuite_id);
474 return 0;
475 }
476 }
477 }
478
479 static ALG_ID schannel_get_mac_algid(int ciphersuite_id)
480 {
481 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
482
483 switch (cipher_suite->mac)
484 {
485 case MBEDTLS_MD_NONE: return 0;
486 case MBEDTLS_MD_MD2: return CALG_MD2;
487 case MBEDTLS_MD_MD4: return CALG_MD4;
488 case MBEDTLS_MD_MD5: return CALG_MD5;
489 case MBEDTLS_MD_SHA1: return CALG_SHA1;
490 case MBEDTLS_MD_SHA224: return CALG_SHA;
491 case MBEDTLS_MD_SHA256: return CALG_SHA_256;
492 case MBEDTLS_MD_SHA384: return CALG_SHA_384;
493 case MBEDTLS_MD_SHA512: return CALG_SHA_512;
494 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 */
495
496 default:
497 {
498 FIXME("MBEDTLS schannel_get_mac_algid: unknown algorithm %d\n", cipher_suite->mac);
499 return 0;
500 }
501 }
502 }
503
504 static ALG_ID schannel_get_kx_algid(int ciphersuite_id)
505 {
506 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id);
507
508 switch (cipher_suite->key_exchange)
509 {
510 case MBEDTLS_KEY_EXCHANGE_NONE:
511 case MBEDTLS_KEY_EXCHANGE_PSK: /* the original implementation does not support */
512 return 0; /* any PSK, and does not define any `CALG_PSK` :) */
513
514 case MBEDTLS_KEY_EXCHANGE_RSA:
515 case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
516 return CALG_RSA_KEYX;
517
518 case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
519 case MBEDTLS_KEY_EXCHANGE_DHE_PSK:
520 return CALG_DH_EPHEM;
521
522 case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
523 case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
524 return CALG_ECDH;
525
526 case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
527 case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
528 case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK:
529 return CALG_ECDH_EPHEM;
530
531 default:
532 {
533 FIXME("MBEDTLS schannel_get_kx_algid: unknown algorithm %d\n", cipher_suite->key_exchange);
534 return 0;
535 }
536 }
537 }
538
539 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
540 {
541 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
542
543 unsigned int cipher_block_size = mbedtls_cipher_get_block_size(&s->ssl.transform->cipher_ctx_enc);
544
545 TRACE("MBEDTLS schan_imp_get_session_cipher_block_size %p returning %u.\n", session, cipher_block_size);
546
547 return cipher_block_size;
548 }
549
550 unsigned int schan_imp_get_max_message_size(schan_imp_session session)
551 {
552 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
553
554 unsigned int max_frag_len = mbedtls_ssl_get_max_frag_len(&s->ssl);
555
556 TRACE("MBEDTLS schan_imp_get_max_message_size %p returning %u.\n", session, max_frag_len);
557
558 return max_frag_len;
559 }
560
561 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
562 SecPkgContext_ConnectionInfo *info)
563 {
564 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
565
566 int ciphersuite_id = mbedtls_ssl_get_ciphersuite_id(mbedtls_ssl_get_ciphersuite(&s->ssl));
567
568 TRACE("MBEDTLS schan_imp_get_connection_info %p %p.\n", session, info);
569
570 info->dwProtocol = schannel_get_protocol(&s->ssl, &s->conf);
571 info->aiCipher = schannel_get_cipher_algid(ciphersuite_id);
572 info->dwCipherStrength = schannel_get_cipher_key_size(ciphersuite_id);
573 info->aiHash = schannel_get_mac_algid(ciphersuite_id);
574 info->dwHashStrength = schannel_get_mac_key_size(ciphersuite_id);
575 info->aiExch = schannel_get_kx_algid(ciphersuite_id);
576 info->dwExchStrength = schannel_get_kx_key_size(&s->ssl, &s->conf, ciphersuite_id);
577
578 return SEC_E_OK;
579 }
580
581 SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store,
582 PCCERT_CONTEXT *ret)
583 {
584 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
585 PCCERT_CONTEXT cert_context = NULL;
586
587 const mbedtls_x509_crt *next_cert;
588 const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&s->ssl);
589
590 TRACE("MBEDTLS schan_imp_get_session_peer_certificate %p %p %p %p.\n", session, store, ret, ret != NULL ? *ret : NULL);
591
592 if (!peer_cert)
593 return SEC_E_INTERNAL_ERROR;
594
595 for (next_cert = peer_cert; next_cert != NULL; next_cert = next_cert->next)
596 {
597 if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, next_cert->raw.p, next_cert->raw.len,
598 CERT_STORE_ADD_REPLACE_EXISTING, (next_cert != peer_cert) ? NULL : &cert_context))
599 {
600 if (next_cert != peer_cert)
601 CertFreeCertificateContext(cert_context);
602 return GetLastError();
603 }
604 }
605
606 *ret = cert_context;
607 return SEC_E_OK;
608 }
609
610 SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
611 SIZE_T *length)
612 {
613 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session;
614 int ret;
615
616 ret = mbedtls_ssl_write(&s->ssl, (unsigned char *)buffer, *length);
617
618 TRACE("MBEDTLS schan_imp_send: (%p, %p, %p/%lu)\n", s, buffer, length, *length);
619
620 if (ret >= 0)
621 {
622 TRACE("MBEDTLS schan_imp_send: ret=%i.\n", ret);
623
624 *length = ret;
625 }
626 else if (ROS_SCHAN_IS_BLOCKING(ret))
627 {
628 *length = ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret);
629
630 if (!*length)
631 {
632 TRACE("MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu", *length);
633 return SEC_I_CONTINUE_NEEDED;
634 }
635 else
636 {
637 TRACE("MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length);
638 return SEC_E_OK;
639 }
640 }
641 else
642 {
643 ERR("MBEDTLS schan_imp_send: mbedtls_ssl_write failed with -%x\n", -ret);
644 return SEC_E_INTERNAL_ERROR;
645 }
646
647 return SEC_E_OK;
648 }
649
650 SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
651 SIZE_T *length)
652 {
653 PMBEDTLS_SESSION s = (PMBEDTLS_SESSION)session;
654 int ret;
655
656 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu)\n", s, buffer, length, *length);
657
658 ret = mbedtls_ssl_read(&s->ssl, (unsigned char *)buffer, *length);
659
660 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu) ret= %#x\n", s, buffer, length, *length, ret);
661
662 if (ret >= 0)
663 {
664 TRACE("MBEDTLS schan_imp_recv: ret == %i.\n", ret);
665
666 *length = ret;
667 }
668 else if (ROS_SCHAN_IS_BLOCKING(ret))
669 {
670 *length = ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret);
671
672 if (!*length)
673 {
674 TRACE("MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_I_CONTINUE_NEEDED; len=%lu", *length);
675 return SEC_I_CONTINUE_NEEDED;
676 }
677 else
678 {
679 TRACE("MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length);
680 return SEC_E_OK;
681 }
682 }
683 else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
684 {
685 *length = 0;
686 TRACE("MBEDTLS schan_imp_recv: ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -> SEC_E_OK\n");
687 return SEC_E_OK;
688 }
689 else
690 {
691 ERR("MBEDTLS schan_imp_recv: mbedtls_ssl_read failed with -%x\n", -ret);
692 return SEC_E_INTERNAL_ERROR;
693 }
694
695 return SEC_E_OK;
696 }
697
698 BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c)
699 {
700 TRACE("MBEDTLS schan_imp_allocate_certificate_credentials %p %p %d\n", c, c->credentials, c->credential_use);
701
702 /* in our case credentials aren't really used for anything, so just stub them */
703 c->credentials = NULL;
704 return TRUE;
705 }
706
707 void schan_imp_free_certificate_credentials(schan_credentials *c)
708 {
709 TRACE("MBEDTLS schan_imp_free_certificate_credentials %p %p %d\n", c, c->credentials, c->credential_use);
710 }
711
712 BOOL schan_imp_init(void)
713 {
714 TRACE("Schannel MBEDTLS schan_imp_init\n");
715 return TRUE;
716 }
717
718 void schan_imp_deinit(void)
719 {
720 WARN("Schannel MBEDTLS schan_imp_deinit\n");
721 }
722
723 #endif /* SONAME_LIBMBEDTLS && !HAVE_SECURITY_SECURITY_H && !SONAME_LIBGNUTLS */