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 WINE_DEFAULT_DEBUG_CHANNEL(schannel); 40 41 #if defined(SONAME_LIBMBEDTLS) && !defined(HAVE_SECURITY_SECURITY_H) && !defined(SONAME_LIBGNUTLS) 42 43 #include <mbedtls/ssl.h> 44 #include <mbedtls/net_sockets.h> 45 46 #include <mbedtls/entropy.h> 47 #include <mbedtls/ctr_drbg.h> 48 #include <mbedtls/md_internal.h> 49 #include <mbedtls/ssl_internal.h> 50 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) 54 55 #ifndef __REACTOS__ 56 /* WINE defines the back-end glue in here */ 57 #include "secur32_priv.h" 58 59 /* in ReactOS we use schannel instead of secur32 */ 60 WINE_DEFAULT_DEBUG_CHANNEL(secur32); 61 62 /* WINE prefers to keep it optional, disable this to link explicitly */ 63 #include "schannel_mbedtls_lazyload.h" 64 65 /* WINE does not define this standard win32 macro for some reason */ 66 #ifndef _countof 67 #define _countof(a) (sizeof(a)/sizeof(*(a))) 68 #endif 69 #endif 70 71 typedef struct 72 { 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; 79 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) 83 { 84 MBEDTLS_SESSION *s = session; 85 size_t requested = buff_len; 86 int status; 87 88 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u)\n", s, s->transport, buff, buff_len); 89 90 status = schan_pull(s->transport, buff, &buff_len); 91 92 TRACE("MBEDTLS schan_pull_adapter: (%p/%p, %p, %u) status: %#x\n", s, s->transport, buff, buff_len, status); 93 94 if (status == NO_ERROR) 95 { 96 /* great, no more data left */ 97 if (buff_len == 0) 98 { 99 TRACE("Connection closed\n"); 100 return 0; 101 } 102 /* there's still some bytes that need pulling */ 103 else if (buff_len < requested) 104 { 105 TRACE("Pulled %u bytes before would block\n", buff_len); 106 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len); 107 } 108 else 109 { 110 TRACE("Pulled %u bytes\n", buff_len); 111 return buff_len; 112 } 113 } 114 else if (status == EAGAIN) 115 { 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); 118 } 119 else 120 { 121 ERR("Unknown status code from schan_pull: %d\n", status); 122 return MBEDTLS_ERR_NET_RECV_FAILED; 123 } 124 125 /* this should be unreachable */ 126 return MBEDTLS_ERR_NET_CONNECT_FAILED; 127 } 128 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) 132 { 133 MBEDTLS_SESSION *s = session; 134 int status; 135 136 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u)\n", s, s->transport, buff, buff_len); 137 138 status = schan_push(s->transport, buff, &buff_len); 139 140 TRACE("MBEDTLS schan_push_adapter: (%p/%p, %p, %u) status: %#x\n", s, s->transport, buff, buff_len, status); 141 142 if (status == NO_ERROR) 143 { 144 TRACE("Pushed %u bytes\n", buff_len); 145 return buff_len; 146 } 147 else if (status == EAGAIN) 148 { 149 TRACE("Would block before being able to push anything. passing %u\n", buff_len); 150 return ROS_SCHAN_IS_BLOCKING_MARSHALL(buff_len); 151 } 152 else 153 { 154 ERR("Unknown status code from schan_push: %d\n", status); 155 return MBEDTLS_ERR_NET_SEND_FAILED; 156 } 157 158 /* this should be unreachable */ 159 return MBEDTLS_ERR_NET_CONNECT_FAILED; 160 } 161 162 DWORD schan_imp_enabled_protocols(void) 163 { 164 /* NOTE: No support for SSL 2.0 */ 165 TRACE("MBEDTLS schan_imp_enabled_protocols()\n"); 166 167 return 0 168 #ifdef MBEDTLS_SSL_PROTO_SSL3 169 | SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER 170 #endif 171 #ifdef MBEDTLS_SSL_PROTO_TLS1 172 | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER 173 #endif 174 #ifdef MBEDTLS_SSL_PROTO_TLS1_1 175 | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER 176 #endif 177 #ifdef MBEDTLS_SSL_PROTO_TLS1_2 178 | SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER 179 #endif 180 ; 181 } 182 183 static void schan_imp_debug(void *ctx, int level, const char *file, int line, const char *str) 184 { 185 WARN("MBEDTLS schan_imp_debug: %s:%04d: %s\n", file, line, str); 186 } 187 188 BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) 189 { 190 MBEDTLS_SESSION *s = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MBEDTLS_SESSION)); 191 192 WARN("MBEDTLS schan_imp_create_session: %p %p %p\n", session, *session, cred); 193 194 if (!(*session = (schan_imp_session)s)) 195 { 196 ERR("Not enough memory to create session\n"); 197 return FALSE; 198 } 199 200 TRACE("MBEDTLS init entropy\n"); 201 mbedtls_entropy_init(&s->entropy); 202 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); 206 207 WARN("MBEDTLS init ssl\n"); 208 mbedtls_ssl_init(&s->ssl); 209 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); 214 215 TRACE("MBEDTLS set BIO callbacks\n"); 216 mbedtls_ssl_set_bio(&s->ssl, s, schan_push_adapter, schan_pull_adapter, NULL); 217 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); 221 222 TRACE("MBEDTLS set authmode\n"); 223 mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_NONE); 224 225 TRACE("MBEDTLS set rng\n"); 226 mbedtls_ssl_conf_rng(&s->conf, mbedtls_ctr_drbg_random, &s->ctr_drbg); 227 228 TRACE("MBEDTLS set dbg\n"); 229 mbedtls_ssl_conf_dbg(&s->conf, schan_imp_debug, stdout); 230 231 TRACE("MBEDTLS setup\n"); 232 mbedtls_ssl_setup(&s->ssl, &s->conf); 233 234 TRACE("MBEDTLS schan_imp_create_session END!\n"); 235 return TRUE; 236 } 237 238 void schan_imp_dispose_session(schan_imp_session session) 239 { 240 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 241 WARN("MBEDTLS schan_imp_dispose_session: %p\n", session); 242 243 /* tell the other peer (a server) that we are going away */ 244 //ssl_close_notify(&s->ssl); 245 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); 250 251 /* safely overwrite the freed context with zeroes */ 252 HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, s); 253 } 254 255 void schan_imp_set_session_transport(schan_imp_session session, 256 struct schan_transport *t) 257 { 258 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 259 260 TRACE("MBEDTLS schan_imp_set_session_transport: %p %p\n", session, t); 261 262 s->transport = t; 263 } 264 265 void schan_imp_set_session_target(schan_imp_session session, const char *target) 266 { 267 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 268 269 TRACE("MBEDTLS schan_imp_set_session_target: sess: %p hostname: %s\n", session, target); 270 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. */ 274 275 mbedtls_ssl_set_hostname(&s->ssl, target); 276 } 277 278 SECURITY_STATUS schan_imp_handshake(schan_imp_session session) 279 { 280 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 281 282 int err = mbedtls_ssl_handshake(&s->ssl); 283 284 TRACE("MBEDTLS schan_imp_handshake: %p err: %#x \n", session, err); 285 286 if (ROS_SCHAN_IS_BLOCKING(err)) 287 { 288 TRACE("Received ERR_NET_WANT_READ/WRITE... let's try again!\n"); 289 return SEC_I_CONTINUE_NEEDED; 290 } 291 else if (err == MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) 292 { 293 ERR("schan_imp_handshake: SSL Feature unavailable...\n"); 294 return SEC_E_UNSUPPORTED_FUNCTION; 295 } 296 else if (err != 0) 297 { 298 ERR("schan_imp_handshake: Oops! mbedtls_ssl_handshake returned the following error code: -%#x...\n", -err); 299 return SEC_E_INTERNAL_ERROR; 300 } 301 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)); 305 return SEC_E_OK; 306 } 307 308 static unsigned int schannel_get_cipher_key_size(int ciphersuite_id) 309 { 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); 312 313 unsigned int key_bitlen = cipher_info->key_bitlen; 314 315 TRACE("MBEDTLS schannel_get_cipher_key_size: Unknown cipher %#x, returning %u\n", ciphersuite_id, key_bitlen); 316 317 return key_bitlen; 318 } 319 320 static unsigned int schannel_get_mac_key_size(int ciphersuite_id) 321 { 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); 324 325 int md_size = md_info->size * CHAR_BIT; /* return the size in bits, as the secur32:schannel winetest shows */ 326 327 TRACE("MBEDTLS schannel_get_mac_key_size: returning %i\n", md_size); 328 329 return md_size; 330 } 331 332 static unsigned int schannel_get_kx_key_size(const mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf, int ciphersuite_id) 333 { 334 const mbedtls_ssl_ciphersuite_t *ssl_ciphersuite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id); 335 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); 338 339 if (ssl_ciphersuite->key_exchange != MBEDTLS_KEY_EXCHANGE_NONE) 340 return mbedtls_pk_get_len(&(server_cert->pk)); 341 342 TRACE("MBEDTLS schannel_get_kx_key_size: Unknown kx %#x, returning 0\n", ssl_ciphersuite->key_exchange); 343 344 return 0; 345 } 346 347 static DWORD schannel_get_protocol(const mbedtls_ssl_context *ssl, const mbedtls_ssl_config *conf) 348 { 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. */ 352 353 switch (ssl->minor_ver) 354 { 355 case MBEDTLS_SSL_MINOR_VERSION_0: 356 return (conf->endpoint == MBEDTLS_SSL_IS_CLIENT) ? SP_PROT_SSL3_CLIENT : 357 SP_PROT_SSL3_SERVER; 358 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; 362 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; 366 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; 370 371 default: 372 { 373 FIXME("MBEDTLS schannel_get_protocol: unknown protocol %d\n", ssl->minor_ver); 374 return 0; 375 } 376 } 377 } 378 379 static ALG_ID schannel_get_cipher_algid(int ciphersuite_id) 380 { 381 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id); 382 383 switch (cipher_suite->cipher) 384 { 385 case MBEDTLS_CIPHER_NONE: 386 case MBEDTLS_CIPHER_NULL: 387 return 0; 388 389 #ifdef MBEDTLS_ARC4_C 390 /* ARC4 */ 391 case MBEDTLS_CIPHER_ARC4_128: 392 return CALG_RC4; 393 #endif 394 395 #ifdef MBEDTLS_DES_C 396 /* DES */ 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: 401 return CALG_DES; 402 403 case MBEDTLS_CIPHER_DES_EDE3_ECB: 404 case MBEDTLS_CIPHER_DES_EDE3_CBC: 405 return CALG_3DES; 406 #endif 407 408 #ifdef MBEDTLS_BLOWFISH_C 409 /* BLOWFISH */ 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; 416 #endif 417 418 #ifdef MBEDTLS_CAMELLIA_C 419 /* CAMELLIA */ 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; 437 #endif 438 439 #ifdef MBEDTLS_AES_C 440 /* AES 128 */ 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: 446 #ifdef MBEDTLS_CCM_C 447 case MBEDTLS_CIPHER_AES_128_CCM: 448 #endif 449 return CALG_AES_128; 450 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: 456 #ifdef MBEDTLS_CCM_C 457 case MBEDTLS_CIPHER_AES_192_CCM: 458 #endif 459 return CALG_AES_192; 460 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: 466 #ifdef MBEDTLS_CCM_C 467 case MBEDTLS_CIPHER_AES_256_CCM: 468 #endif 469 return CALG_AES_256; 470 #endif 471 472 /* nothing to show? fall through */ 473 default: 474 { 475 FIXME("MBEDTLS schannel_get_cipher_algid: unknown algorithm %d\n", ciphersuite_id); 476 return 0; 477 } 478 } 479 } 480 481 static ALG_ID schannel_get_mac_algid(int ciphersuite_id) 482 { 483 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id); 484 485 switch (cipher_suite->mac) 486 { 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 */ 497 498 default: 499 { 500 FIXME("MBEDTLS schannel_get_mac_algid: unknown algorithm %d\n", cipher_suite->mac); 501 return 0; 502 } 503 } 504 } 505 506 static ALG_ID schannel_get_kx_algid(int ciphersuite_id) 507 { 508 const mbedtls_ssl_ciphersuite_t *cipher_suite = mbedtls_ssl_ciphersuite_from_id(ciphersuite_id); 509 510 switch (cipher_suite->key_exchange) 511 { 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` :) */ 515 516 case MBEDTLS_KEY_EXCHANGE_RSA: 517 case MBEDTLS_KEY_EXCHANGE_RSA_PSK: 518 return CALG_RSA_KEYX; 519 520 case MBEDTLS_KEY_EXCHANGE_DHE_RSA: 521 case MBEDTLS_KEY_EXCHANGE_DHE_PSK: 522 return CALG_DH_EPHEM; 523 524 case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: 525 case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: 526 return CALG_ECDH; 527 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; 532 533 default: 534 { 535 FIXME("MBEDTLS schannel_get_kx_algid: unknown algorithm %d\n", cipher_suite->key_exchange); 536 return 0; 537 } 538 } 539 } 540 541 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) 542 { 543 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 544 545 unsigned int cipher_block_size = mbedtls_cipher_get_block_size(&s->ssl.transform->cipher_ctx_enc); 546 547 TRACE("MBEDTLS schan_imp_get_session_cipher_block_size %p returning %u.\n", session, cipher_block_size); 548 549 return cipher_block_size; 550 } 551 552 unsigned int schan_imp_get_max_message_size(schan_imp_session session) 553 { 554 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 555 556 unsigned int max_frag_len = mbedtls_ssl_get_max_frag_len(&s->ssl); 557 558 TRACE("MBEDTLS schan_imp_get_max_message_size %p returning %u.\n", session, max_frag_len); 559 560 return max_frag_len; 561 } 562 563 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, 564 SecPkgContext_ConnectionInfo *info) 565 { 566 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 567 568 int ciphersuite_id = mbedtls_ssl_get_ciphersuite_id(mbedtls_ssl_get_ciphersuite(&s->ssl)); 569 570 TRACE("MBEDTLS schan_imp_get_connection_info %p %p.\n", session, info); 571 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); 579 580 return SEC_E_OK; 581 } 582 583 SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store, 584 PCCERT_CONTEXT *ret) 585 { 586 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 587 PCCERT_CONTEXT cert_context = NULL; 588 589 const mbedtls_x509_crt *next_cert; 590 const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&s->ssl); 591 592 TRACE("MBEDTLS schan_imp_get_session_peer_certificate %p %p %p %p.\n", session, store, ret, ret != NULL ? *ret : NULL); 593 594 if (!peer_cert) 595 return SEC_E_INTERNAL_ERROR; 596 597 for (next_cert = peer_cert; next_cert != NULL; next_cert = next_cert->next) 598 { 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)) 601 { 602 if (next_cert != peer_cert) 603 CertFreeCertificateContext(cert_context); 604 return GetLastError(); 605 } 606 } 607 608 *ret = cert_context; 609 return SEC_E_OK; 610 } 611 612 SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, 613 SIZE_T *length) 614 { 615 MBEDTLS_SESSION *s = (MBEDTLS_SESSION *)session; 616 int ret; 617 618 ret = mbedtls_ssl_write(&s->ssl, (unsigned char *)buffer, *length); 619 620 TRACE("MBEDTLS schan_imp_send: (%p, %p, %p/%lu)\n", s, buffer, length, *length); 621 622 if (ret >= 0) 623 { 624 TRACE("MBEDTLS schan_imp_send: ret=%i.\n", ret); 625 626 *length = ret; 627 } 628 else if (ROS_SCHAN_IS_BLOCKING(ret)) 629 { 630 *length = ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret); 631 632 if (!*length) 633 { 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; 636 } 637 else 638 { 639 TRACE("MBEDTLS schan_imp_send: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length); 640 return SEC_E_OK; 641 } 642 } 643 else 644 { 645 ERR("MBEDTLS schan_imp_send: mbedtls_ssl_write failed with -%x\n", -ret); 646 return SEC_E_INTERNAL_ERROR; 647 } 648 649 return SEC_E_OK; 650 } 651 652 SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, 653 SIZE_T *length) 654 { 655 PMBEDTLS_SESSION s = (PMBEDTLS_SESSION)session; 656 int ret; 657 658 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu)\n", s, buffer, length, *length); 659 660 ret = mbedtls_ssl_read(&s->ssl, (unsigned char *)buffer, *length); 661 662 TRACE("MBEDTLS schan_imp_recv: (%p, %p, %p/%lu) ret= %#x\n", s, buffer, length, *length, ret); 663 664 if (ret >= 0) 665 { 666 TRACE("MBEDTLS schan_imp_recv: ret == %i.\n", ret); 667 668 *length = ret; 669 } 670 else if (ROS_SCHAN_IS_BLOCKING(ret)) 671 { 672 *length = ROS_SCHAN_IS_BLOCKING_RETRIEVE(ret); 673 674 if (!*length) 675 { 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; 678 } 679 else 680 { 681 TRACE("MBEDTLS schan_imp_recv: ret=MBEDTLS_ERR_NET_WANT_WRITE -> SEC_E_OK; len=%lu", *length); 682 return SEC_E_OK; 683 } 684 } 685 else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) 686 { 687 *length = 0; 688 TRACE("MBEDTLS schan_imp_recv: ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -> SEC_E_OK\n"); 689 return SEC_E_OK; 690 } 691 else 692 { 693 ERR("MBEDTLS schan_imp_recv: mbedtls_ssl_read failed with -%x\n", -ret); 694 return SEC_E_INTERNAL_ERROR; 695 } 696 697 return SEC_E_OK; 698 } 699 700 BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c) 701 { 702 TRACE("MBEDTLS schan_imp_allocate_certificate_credentials %p %p %d\n", c, c->credentials, c->credential_use); 703 704 /* in our case credentials aren't really used for anything, so just stub them */ 705 c->credentials = NULL; 706 return TRUE; 707 } 708 709 void schan_imp_free_certificate_credentials(schan_credentials *c) 710 { 711 TRACE("MBEDTLS schan_imp_free_certificate_credentials %p %p %d\n", c, c->credentials, c->credential_use); 712 } 713 714 BOOL schan_imp_init(void) 715 { 716 TRACE("Schannel MBEDTLS schan_imp_init\n"); 717 return TRUE; 718 } 719 720 void schan_imp_deinit(void) 721 { 722 WARN("Schannel MBEDTLS schan_imp_deinit\n"); 723 } 724 725 #endif /* SONAME_LIBMBEDTLS && !HAVE_SECURITY_SECURITY_H && !SONAME_LIBGNUTLS */