1 /** 2 * TLS Server 3 * 4 * Copyright: 5 * (C) 2004-2011,2015 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.tls.server; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS): 15 16 public import botan.tls.channel; 17 import botan.tls.credentials_manager; 18 import botan.tls.handshake_state; 19 import botan.tls.messages; 20 import botan.tls.alert; 21 import botan.rng.rng; 22 import memutils.dictionarylist; 23 import memutils.hashmap; 24 import botan.utils.types; 25 import std.datetime; 26 27 alias NextProtocolHandler = string delegate(in Vector!string); 28 alias SNIHandler = SNIContextSwitchInfo delegate(string); 29 30 struct SNIContextSwitchInfo 31 { 32 TLSSessionManager session_manager; 33 TLSCredentialsManager credentials; 34 TLSPolicy policy; 35 NextProtocolHandler next_proto; 36 void* user_data; 37 } 38 39 40 /** 41 * TLS Server 42 */ 43 final class TLSServer : TLSChannel 44 { 45 public: 46 47 /** 48 * TLSServer initialization 49 */ 50 this(DataWriter output_fn, 51 OnClearData data_cb, 52 OnAlert alert_cb, 53 OnHandshakeComplete handshake_cb, 54 TLSSessionManager session_manager, 55 TLSCredentialsManager creds, 56 TLSPolicy policy, 57 RandomNumberGenerator rng, 58 NextProtocolHandler next_proto = null, 59 SNIHandler sni_handler = null, 60 bool is_datagram = false, 61 size_t io_buf_sz = 16*1024) 62 { 63 super(output_fn, data_cb, alert_cb, handshake_cb, session_manager, rng, is_datagram, io_buf_sz); 64 m_policy = policy; 65 m_creds = creds; 66 m_choose_next_protocol = next_proto; 67 m_sni_handler = sni_handler; 68 } 69 70 void* getUserData() { return m_user_data; } 71 72 protected: 73 override Vector!X509Certificate getPeerCertChain(in HandshakeState state) const 74 { 75 if (state.clientCerts()) 76 return state.clientCerts().certChain().dup(); 77 return Vector!X509Certificate(); 78 } 79 80 /* 81 * Send a hello request to the client 82 */ 83 override void initiateHandshake(HandshakeState state, bool force_full_renegotiation) 84 { 85 (cast(ServerHandshakeState)state).allow_session_resumption = !force_full_renegotiation; 86 87 auto hello_req = scoped!HelloRequest(state.handshakeIo()); 88 } 89 90 /* 91 * Process a handshake message 92 */ 93 override void processHandshakeMsg(in HandshakeState active_state, 94 HandshakeState state_base, 95 HandshakeType type, 96 const ref Vector!ubyte contents) 97 { 98 ServerHandshakeState state = cast(ServerHandshakeState)(state_base); 99 100 state.confirmTransitionTo(type); 101 102 /* 103 * The change cipher spec message isn't technically a handshake 104 * message so it's not included in the hash. The finished and 105 * certificate verify messages are verified based on the current 106 * state of the hash *before* this message so we delay adding them 107 * to the hash computation until we've processed them below. 108 */ 109 if (type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY) 110 { 111 if (type == CLIENT_HELLO_SSLV2) 112 state.hash().update(contents); 113 else 114 state.hash().update(state.handshakeIo().format(contents, type)); 115 } 116 117 if (type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) 118 { 119 const bool initial_handshake = !active_state; 120 121 if (!m_policy.allowInsecureRenegotiation() && 122 !(initial_handshake || secureRenegotiationSupported())) 123 { 124 sendWarningAlert(TLSAlert.NO_RENEGOTIATION); 125 return; 126 } 127 state.clientHello(new ClientHello(contents, type)); 128 129 // choose a proper context depending on hostname and register the userdata 130 if (m_sni_handler) { 131 const string sni_hostname = state.clientHello().sniHostname(); 132 SNIContextSwitchInfo ctx = m_sni_handler(sni_hostname); 133 if (ctx !is SNIContextSwitchInfo.init) 134 switchContext(ctx); 135 } 136 137 const TLSProtocolVersion client_version = state.clientHello().Version(); 138 139 TLSProtocolVersion negotiated_version; 140 141 const TLSProtocolVersion latest_supported = m_policy.latestSupportedVersion(client_version.isDatagramProtocol()); 142 143 if ((initial_handshake && client_version.knownVersion()) || 144 (!initial_handshake && client_version == active_state.Version())) 145 { 146 /* 147 Common cases: new client hello with some known version, or a 148 renegotiation using the same version as previously 149 negotiated. 150 */ 151 152 negotiated_version = client_version; 153 } 154 else if (!initial_handshake && (client_version != active_state.Version())) 155 { 156 /* 157 * If this is a renegotiation, and the client has offered a 158 * later version than what it initially negotiated, negotiate 159 * the old version. This matches OpenSSL's behavior. If the 160 * client is offering a version earlier than what it initially 161 * negotiated, reject as a probable attack. 162 */ 163 if (active_state.Version() > client_version) 164 { 165 throw new TLSException(TLSAlert.PROTOCOL_VERSION, 166 "TLSClient negotiated " ~ 167 active_state.Version().toString() ~ 168 " then renegotiated with " ~ 169 client_version.toString()); 170 } 171 else 172 negotiated_version = active_state.Version(); 173 } 174 else 175 { 176 /* 177 New negotiation using a version we don't know. Offer 178 them the best we currently know and support. 179 */ 180 negotiated_version = latest_supported; 181 } 182 183 if (!m_policy.acceptableProtocolVersion(negotiated_version)) 184 { 185 throw new TLSException(TLSAlert.PROTOCOL_VERSION, "Client version " ~ negotiated_version.toString() ~ " is unacceptable by policy"); 186 } 187 188 if (state.clientHello().sentFallbackSCSV()) 189 { 190 if (latest_supported > client_version) 191 throw new TLSException(TLSAlert.INAPPROPRIATE_FALLBACK, "Client signalled fallback SCSV, possible attack"); 192 } 193 194 secureRenegotiationCheck(state.clientHello()); 195 196 state.setVersion(negotiated_version); 197 198 TLSSession session_info; 199 scope(exit) destroy(session_info); 200 const bool resuming = state.allow_session_resumption && 201 checkForResume(session_info, 202 sessionManager(), 203 m_creds, 204 state.clientHello(), 205 m_policy.sessionTicketLifetime()); 206 207 bool have_session_ticket_key = false; 208 209 try 210 { 211 have_session_ticket_key = m_creds.psk("tls-server", "session-ticket", "").length > 0; 212 } 213 catch (Exception) {} 214 215 m_application_protocol = ""; 216 217 if (m_choose_next_protocol && state.clientHello().supportsAlpn()) 218 m_application_protocol = m_choose_next_protocol(state.clientHello().nextProtocols()); 219 220 if (resuming) 221 { 222 // resume session 223 224 const bool offer_new_session_ticket = (state.clientHello().supportsSessionTicket() && 225 state.clientHello().sessionTicket().empty && 226 have_session_ticket_key); 227 228 state.serverHello(new ServerHello(state.handshakeIo(), 229 state.hash(), 230 m_policy, 231 state.clientHello().sessionId().dup, 232 session_info.Version(), 233 session_info.ciphersuiteCode(), 234 session_info.compressionMethod(), 235 session_info.fragmentSize(), 236 state.clientHello().secureRenegotiation(), 237 secureRenegotiationDataForServerHello(), 238 offer_new_session_ticket, 239 state.clientHello().supportsAlpn(), 240 m_application_protocol, 241 state.clientHello().supportsHeartbeats(), 242 rng())); 243 244 secureRenegotiationCheck(state.serverHello()); 245 246 state.computeSessionKeys(session_info.masterSecret().dup); 247 248 if (!saveSession(session_info)) 249 { 250 auto entry = &session_info.sessionId(); 251 sessionManager().removeEntry(*entry); 252 253 if (state.serverHello().supportsSessionTicket()) // send an empty ticket 254 { 255 state.newSessionTicket(new NewSessionTicket(state.handshakeIo(), state.hash())); 256 } 257 } 258 259 if (state.serverHello().supportsSessionTicket() && !state.newSessionTicket()) 260 { 261 try 262 { 263 const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); 264 265 state.newSessionTicket(new NewSessionTicket(state.handshakeIo(), 266 state.hash(), 267 session_info.encrypt(ticket_key, rng()), 268 m_policy.sessionTicketLifetime())); 269 } 270 catch (Exception) {} 271 272 if (!state.newSessionTicket()) 273 { 274 state.newSessionTicket(new NewSessionTicket(state.handshakeIo(), state.hash())); 275 } 276 } 277 278 state.handshakeIo().send(scoped!ChangeCipherSpec()); 279 280 changeCipherSpecWriter(SERVER); 281 282 state.serverFinished(new Finished(state.handshakeIo(), state, SERVER)); 283 284 state.setExpectedNext(HANDSHAKE_CCS); 285 } 286 else // new session 287 { 288 HashMapRef!(string, Array!X509Certificate) cert_chains; 289 290 const string sni_hostname = state.clientHello().sniHostname(); 291 292 cert_chains = getServerCerts(sni_hostname, m_creds); 293 294 if (sni_hostname != "" && cert_chains.length == 0) 295 { 296 cert_chains = getServerCerts("", m_creds); 297 298 /* 299 * Only send the unrecognized_name alert if we couldn't 300 * find any certs for the requested name but did find at 301 * least one cert to use in general. That avoids sending an 302 * unrecognized_name when a server is configured for purely 303 * anonymous operation. 304 */ 305 if (cert_chains.length != 0) 306 sendAlert(TLSAlert(TLSAlert.UNRECOGNIZED_NAME)); 307 } 308 state.serverHello( 309 new ServerHello( state.handshakeIo(), 310 state.hash(), 311 m_policy, 312 makeHelloRandom(rng(), m_policy), // new session ID 313 state.Version(), 314 chooseCiphersuite(m_policy, state.Version(), m_creds, cert_chains, state.clientHello()), 315 chooseCompression(m_policy, state.clientHello().compressionMethods()), 316 state.clientHello().fragmentSize(), 317 state.clientHello().secureRenegotiation(), 318 secureRenegotiationDataForServerHello(), 319 state.clientHello().supportsSessionTicket() && have_session_ticket_key, 320 state.clientHello().supportsAlpn(), 321 m_application_protocol, 322 state.clientHello().supportsHeartbeats(), 323 rng() 324 ) 325 ); 326 327 secureRenegotiationCheck(state.serverHello()); 328 329 const string sig_algo = state.ciphersuite().sigAlgo(); 330 const string kex_algo = state.ciphersuite().kexAlgo(); 331 332 if (sig_algo != "") 333 { 334 assert(!cert_chains[sig_algo].empty, 335 "Attempting to send empty certificate chain"); 336 337 state.serverCerts(new Certificate(state.handshakeIo(), state.hash(), cert_chains[sig_algo]) 338 ); 339 } 340 341 PrivateKey priv_key = null; 342 343 if (kex_algo == "RSA" || sig_algo != "") 344 { 345 priv_key = m_creds.privateKeyFor(state.serverCerts().certChain()[0], 346 "tls-server", 347 sni_hostname ); 348 349 if (!priv_key) 350 throw new InternalError("No private key located for associated server cert"); 351 } 352 353 if (kex_algo == "RSA") 354 { 355 state.server_rsa_kex_key = priv_key; 356 } 357 else 358 { 359 state.serverKex( 360 new ServerKeyExchange(state.handshakeIo(), 361 state, 362 m_policy, 363 m_creds, 364 rng(), 365 priv_key) 366 ); 367 } 368 369 auto trusted_CAs = m_creds.trustedCertificateAuthorities("tls-server", sni_hostname); 370 371 Vector!X509DN client_auth_CAs; 372 373 foreach (store; trusted_CAs[]) 374 { 375 auto subjects = store.allSubjects(); 376 client_auth_CAs ~= subjects[]; 377 } 378 379 if (!client_auth_CAs.empty && state.ciphersuite().sigAlgo() != "") 380 { 381 state.certReq(new CertificateReq(state.handshakeIo(), state.hash(), m_policy, 382 client_auth_CAs.move(), state.Version())); 383 384 state.setExpectedNext(CERTIFICATE); 385 } 386 387 /* 388 * If the client doesn't have a cert they want to use they are 389 * allowed to send either an empty cert message or proceed 390 * directly to the client key exchange, so allow either case. 391 */ 392 state.setExpectedNext(CLIENT_KEX); 393 394 state.serverHelloDone(new ServerHelloDone(state.handshakeIo(), state.hash())); 395 } 396 } 397 else if (type == CERTIFICATE) 398 { 399 state.clientCerts(new Certificate(contents)); 400 401 state.setExpectedNext(CLIENT_KEX); 402 } 403 else if (type == CLIENT_KEX) 404 { 405 if (state.receivedHandshakeMsg(CERTIFICATE) && !state.clientCerts().empty) 406 state.setExpectedNext(CERTIFICATE_VERIFY); 407 else 408 state.setExpectedNext(HANDSHAKE_CCS); 409 410 state.clientKex( 411 new ClientKeyExchange(contents, state, state.server_rsa_kex_key, m_creds, m_policy, rng()) 412 ); 413 414 state.computeSessionKeys(); 415 } 416 else if (type == CERTIFICATE_VERIFY) 417 { 418 state.clientVerify(new CertificateVerify(contents, state.Version())); 419 420 const(Vector!X509Certificate)* client_certs = &state.clientCerts().certChain(); 421 422 const bool sig_valid = state.clientVerify().verify((*client_certs)[0], state); 423 424 state.hash().update(state.handshakeIo().format(contents, type)); 425 426 /* 427 * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for 428 * "A handshake cryptographic operation failed, including being 429 * unable to correctly verify a signature, ..." 430 */ 431 if (!sig_valid) 432 throw new TLSException(TLSAlert.DECRYPT_ERROR, "TLSClient cert verify failed"); 433 434 try 435 { 436 m_creds.verifyCertificateChain("tls-server", "", *client_certs); 437 } 438 catch(Exception e) 439 { 440 throw new TLSException(TLSAlert.BAD_CERTIFICATE, e.msg); 441 } 442 443 state.setExpectedNext(HANDSHAKE_CCS); 444 } 445 else if (type == HANDSHAKE_CCS) 446 { 447 state.setExpectedNext(FINISHED); 448 changeCipherSpecReader(SERVER); 449 450 } 451 else if (type == FINISHED) 452 { 453 state.setExpectedNext(HANDSHAKE_NONE); 454 455 state.clientFinished(new Finished(contents.dup)); 456 457 if (!state.clientFinished().verify(state, CLIENT)) 458 throw new TLSException(TLSAlert.DECRYPT_ERROR, "Finished message didn't verify"); 459 460 if (!state.serverFinished()) 461 { 462 // already sent finished if resuming, so this is a new session 463 464 state.hash().update(state.handshakeIo().format(contents, type)); 465 466 auto session_info = new TLSSession(state.serverHello().sessionId().dup, 467 state.sessionKeys().masterSecret().dup, 468 state.serverHello().Version(), 469 state.serverHello().ciphersuite(), 470 state.serverHello().compressionMethod(), 471 SERVER, 472 state.serverHello().fragmentSize(), 473 getPeerCertChain(state), 474 Vector!ubyte(), 475 TLSServerInformation(state.clientHello().sniHostname()), 476 state.srpIdentifier() 477 ); 478 479 if (saveSession(session_info)) 480 { 481 if (state.serverHello().supportsSessionTicket()) 482 { 483 try 484 { 485 const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", ""); 486 487 state.newSessionTicket( 488 new NewSessionTicket(state.handshakeIo(), 489 state.hash(), 490 session_info.encrypt(ticket_key, rng()), 491 m_policy.sessionTicketLifetime()) 492 ); 493 } 494 catch (Exception) {} 495 } 496 else 497 sessionManager().save(session_info); 498 } 499 500 if (!state.newSessionTicket() && state.serverHello().supportsSessionTicket()) 501 { 502 state.newSessionTicket(new NewSessionTicket(state.handshakeIo(), state.hash())); 503 } 504 505 state.handshakeIo().send(scoped!ChangeCipherSpec()); 506 507 changeCipherSpecWriter(SERVER); 508 509 state.serverFinished(new Finished(state.handshakeIo(), state, SERVER)); 510 } 511 activateSession(); 512 } 513 else 514 throw new TLSUnexpectedMessage("Unknown handshake message received"); 515 } 516 517 override HandshakeState newHandshakeState(HandshakeIO io) 518 { 519 HandshakeState state = new ServerHandshakeState(io); 520 state.setExpectedNext(CLIENT_HELLO); 521 return state; 522 } 523 524 void switchContext(SNIContextSwitchInfo info) 525 { 526 m_creds = info.credentials; 527 m_session_manager = info.session_manager; 528 m_policy = info.policy; 529 m_choose_next_protocol = info.next_proto; 530 m_user_data = info.user_data; 531 } 532 533 private: 534 TLSPolicy m_policy; 535 TLSCredentialsManager m_creds; 536 537 NextProtocolHandler m_choose_next_protocol; 538 SNIHandler m_sni_handler; 539 void* m_user_data; 540 } 541 542 private: 543 544 bool checkForResume(ref TLSSession session_info, 545 TLSSessionManager session_manager, 546 TLSCredentialsManager credentials, 547 in ClientHello clientHello, 548 Duration session_ticket_lifetime) 549 { 550 const(Vector!ubyte)* client_session_id = &clientHello.sessionId(); 551 const Vector!ubyte session_ticket = clientHello.sessionTicket(); 552 553 if (session_ticket.empty) 554 { 555 if (client_session_id.empty) // not resuming 556 return false; 557 558 // not found 559 if (!session_manager.loadFromSessionId(*client_session_id, session_info)) 560 return false; 561 } 562 else 563 { 564 // If a session ticket was sent, ignore client session ID 565 try 566 { 567 session_info = TLSSession.decrypt(session_ticket, 568 credentials.psk("tls-server", "session-ticket", "")); 569 570 if (session_ticket_lifetime != Duration.init && 571 session_info.sessionAge() > session_ticket_lifetime) 572 return false; // ticket has expired 573 } 574 catch (Exception) 575 { 576 return false; 577 } 578 } 579 580 if (!session_info) 581 return false; 582 583 // wrong version 584 if (clientHello.Version() != session_info.Version()) 585 return false; 586 587 // client didn't send original ciphersuite 588 if (!valueExists(clientHello.ciphersuites(), 589 session_info.ciphersuiteCode())) 590 return false; 591 592 // client didn't send original compression method 593 if (!valueExists(clientHello.compressionMethods(), 594 session_info.compressionMethod())) 595 return false; 596 597 // client sent a different SRP identity 598 if (clientHello.srpIdentifier() != "") 599 { 600 if (clientHello.srpIdentifier() != session_info.srpIdentifier()) 601 return false; 602 } 603 604 // client sent a different SNI hostname 605 if (clientHello.sniHostname() != "") 606 { 607 if (clientHello.sniHostname() != session_info.serverInfo().hostname()) 608 return false; 609 } 610 611 return true; 612 } 613 614 /* 615 * Choose which ciphersuite to use 616 */ 617 ushort chooseCiphersuite(in TLSPolicy policy, 618 TLSProtocolVersion _version, 619 TLSCredentialsManager creds, 620 in HashMapRef!(string, Array!X509Certificate) cert_chains, 621 in ClientHello client_hello) 622 { 623 const bool our_choice = policy.serverUsesOwnCiphersuitePreferences(); 624 625 const bool have_srp = creds.attemptSrp("tls-server", client_hello.sniHostname()); 626 627 const(Vector!ushort)* client_suites = &client_hello.ciphersuites(); 628 629 const Vector!ushort server_suites = policy.ciphersuiteList(_version, have_srp); 630 631 if (server_suites.empty) 632 throw new TLSException(TLSAlert.HANDSHAKE_FAILURE, "TLSPolicy forbids us from negotiating any ciphersuite"); 633 634 const bool have_shared_ecc_curve = (policy.chooseCurve(client_hello.supportedEccCurves()) != ""); 635 636 Vector!ushort pref_list = server_suites.dup; 637 638 if (!our_choice) 639 pref_list[] = *client_suites; 640 debug { 641 string dbg_msg; 642 string dbg_sig; 643 } 644 foreach (suite_id; pref_list[]) 645 { 646 if (!valueExists(*client_suites, suite_id)) 647 continue; 648 649 TLSCiphersuite suite = TLSCiphersuite.byId(suite_id); 650 651 if (!have_shared_ecc_curve && suite.eccCiphersuite()) 652 continue; 653 654 if (suite.sigAlgo() != "" && cert_chains.get(suite.sigAlgo(), Array!X509Certificate(0)) == Array!X509Certificate(0)) 655 { 656 debug { 657 dbg_msg = "Server Certificate type did not match a type that was accepted from policy: "; 658 dbg_sig = suite.sigAlgo; 659 } 660 continue; 661 } 662 /* 663 The client may offer SRP cipher suites in the hello message but 664 omit the SRP extension. If the server would like to select an 665 SRP cipher suite in this case, the server SHOULD return a fatal 666 "unknown_psk_identity" alert immediately after processing the 667 client hello message. 668 - RFC 5054 section 2.5.1.2 669 */ 670 if (suite.kexAlgo() == "SRP_SHA" && client_hello.srpIdentifier() == "") 671 throw new TLSException(TLSAlert.UNKNOWN_PSK_IDENTITY, 672 "TLSClient wanted SRP but did not send username"); 673 674 return suite_id; 675 } 676 debug logDebug(dbg_msg, dbg_sig); 677 throw new TLSException(TLSAlert.HANDSHAKE_FAILURE, "Can't agree on a ciphersuite with client"); 678 } 679 680 /* 681 * Choose which compression algorithm to use 682 */ 683 ubyte chooseCompression(in TLSPolicy policy, const ref Vector!ubyte c_comp) 684 { 685 Vector!ubyte s_comp = policy.compression(); 686 687 for (size_t i = 0; i != s_comp.length; ++i) 688 for (size_t j = 0; j != c_comp.length; ++j) 689 if (s_comp[i] == c_comp[j]) 690 return s_comp[i]; 691 692 return NO_COMPRESSION; 693 } 694 695 HashMapRef!(string, Array!X509Certificate) 696 getServerCerts(in string hostname, TLSCredentialsManager creds) 697 { 698 string[] cert_types = [ "RSA", "DSA", "ECDSA", null ]; 699 700 HashMapRef!(string, Array!X509Certificate) cert_chains; 701 702 for (size_t i = 0; cert_types[i]; ++i) 703 { 704 Vector!X509Certificate certs = creds.certChainSingleType(cert_types[i], "tls-server", hostname); 705 706 if (!certs.empty) 707 cert_chains[cert_types[i]] = certs.dupr; 708 } 709 710 return cert_chains; 711 } 712 713 private final class ServerHandshakeState : HandshakeState 714 { 715 public: 716 this(HandshakeIO io) 717 { 718 super(io); 719 } 720 721 // Used by the server only, in case of RSA key exchange. Not owned 722 PrivateKey server_rsa_kex_key = null; 723 724 /* 725 * Used by the server to know if resumption should be allowed on 726 * a server-initiated renegotiation 727 */ 728 bool allow_session_resumption = true; 729 }