diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/tls/msg_server_hello.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/tls/msg_server_hello.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp b/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp new file mode 100644 index 0000000000..651fd14f89 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/msg_server_hello.cpp @@ -0,0 +1,251 @@ +/* +* TLS Server Hello and Server Hello Done +* (C) 2004-2011,2015,2016,2019 Jack Lloyd +* 2016 Matthias Gierlings +* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/tls_messages.h> +#include <botan/tls_extensions.h> +#include <botan/tls_callbacks.h> +#include <botan/internal/tls_reader.h> +#include <botan/internal/tls_session_key.h> +#include <botan/internal/tls_handshake_io.h> +#include <botan/internal/tls_handshake_hash.h> +#include <botan/internal/stl_util.h> + +namespace Botan { + +namespace TLS { + +namespace { + +const uint64_t DOWNGRADE_TLS11 = 0x444F574E47524400; +//const uint64_t DOWNGRADE_TLS12 = 0x444F574E47524401; + +std::vector<uint8_t> +make_server_hello_random(RandomNumberGenerator& rng, + Protocol_Version offered_version, + const Policy& policy) + { + auto random = make_hello_random(rng, policy); + + if((offered_version == Protocol_Version::TLS_V10 || + offered_version == Protocol_Version::TLS_V11) && + policy.allow_tls12()) + { + store_be(DOWNGRADE_TLS11, &random[24]); + } + + if(offered_version == Protocol_Version::DTLS_V10 && policy.allow_dtls12()) + { + store_be(DOWNGRADE_TLS11, &random[24]); + } + + return random; + } + +} + +// New session case +Server_Hello::Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector<uint8_t>& reneg_info, + const Client_Hello& client_hello, + const Server_Hello::Settings& server_settings, + const std::string next_protocol) : + m_version(server_settings.protocol_version()), + m_session_id(server_settings.session_id()), + m_random(make_server_hello_random(rng, m_version, policy)), + m_ciphersuite(server_settings.ciphersuite()), + m_comp_method(0) + { + if(client_hello.supports_extended_master_secret()) + m_extensions.add(new Extended_Master_Secret); + + // Sending the extension back does not commit us to sending a stapled response + if(client_hello.supports_cert_status_message() && policy.support_cert_status_message()) + m_extensions.add(new Certificate_Status_Request); + + Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); + + if(c.cbc_ciphersuite() && client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) + { + m_extensions.add(new Encrypt_then_MAC); + } + + if(c.ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + if(client_hello.secure_renegotiation()) + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + if(client_hello.supports_session_ticket() && server_settings.offer_session_ticket()) + m_extensions.add(new Session_Ticket()); + + if(!next_protocol.empty() && client_hello.supports_alpn()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); + + if(m_version.is_datagram_protocol()) + { + const std::vector<uint16_t> server_srtp = policy.srtp_profiles(); + const std::vector<uint16_t> client_srtp = client_hello.srtp_profiles(); + + if(!server_srtp.empty() && !client_srtp.empty()) + { + uint16_t shared = 0; + // always using server preferences for now + for(auto s_srtp : server_srtp) + for(auto c_srtp : client_srtp) + { + if(shared == 0 && s_srtp == c_srtp) + shared = s_srtp; + } + + if(shared) + m_extensions.add(new SRTP_Protection_Profiles(shared)); + } + } + + cb.tls_modify_extensions(m_extensions, SERVER); + + hash.update(io.send(*this)); + } + +// Resuming +Server_Hello::Server_Hello(Handshake_IO& io, + Handshake_Hash& hash, + const Policy& policy, + Callbacks& cb, + RandomNumberGenerator& rng, + const std::vector<uint8_t>& reneg_info, + const Client_Hello& client_hello, + Session& resumed_session, + bool offer_session_ticket, + const std::string& next_protocol) : + m_version(resumed_session.version()), + m_session_id(client_hello.session_id()), + m_random(make_hello_random(rng, policy)), + m_ciphersuite(resumed_session.ciphersuite_code()), + m_comp_method(0) + { + if(client_hello.supports_extended_master_secret()) + m_extensions.add(new Extended_Master_Secret); + + if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) + { + Ciphersuite c = resumed_session.ciphersuite(); + if(c.cbc_ciphersuite()) + m_extensions.add(new Encrypt_then_MAC); + } + + if(resumed_session.ciphersuite().ecc_ciphersuite() && client_hello.extension_types().count(TLSEXT_EC_POINT_FORMATS)) + { + m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); + } + + if(client_hello.secure_renegotiation()) + m_extensions.add(new Renegotiation_Extension(reneg_info)); + + if(client_hello.supports_session_ticket() && offer_session_ticket) + m_extensions.add(new Session_Ticket()); + + if(!next_protocol.empty() && client_hello.supports_alpn()) + m_extensions.add(new Application_Layer_Protocol_Notification(next_protocol)); + + cb.tls_modify_extensions(m_extensions, SERVER); + + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello message +*/ +Server_Hello::Server_Hello(const std::vector<uint8_t>& buf) + { + if(buf.size() < 38) + throw Decoding_Error("Server_Hello: Packet corrupted"); + + TLS_Data_Reader reader("ServerHello", buf); + + const uint8_t major_version = reader.get_byte(); + const uint8_t minor_version = reader.get_byte(); + + m_version = Protocol_Version(major_version, minor_version); + + m_random = reader.get_fixed<uint8_t>(32); + + m_session_id = reader.get_range<uint8_t>(1, 0, 32); + + m_ciphersuite = reader.get_uint16_t(); + + m_comp_method = reader.get_byte(); + + m_extensions.deserialize(reader, Connection_Side::SERVER); + } + +/* +* Serialize a Server Hello message +*/ +std::vector<uint8_t> Server_Hello::serialize() const + { + std::vector<uint8_t> buf; + + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; + + append_tls_length_value(buf, m_session_id, 1); + + buf.push_back(get_byte(0, m_ciphersuite)); + buf.push_back(get_byte(1, m_ciphersuite)); + + buf.push_back(m_comp_method); + + buf += m_extensions.serialize(Connection_Side::SERVER); + + return buf; + } + +bool Server_Hello::random_signals_downgrade() const + { + const uint64_t last8 = load_be<uint64_t>(m_random.data(), 3); + return (last8 == DOWNGRADE_TLS11); + } + +/* +* Create a new Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(Handshake_IO& io, + Handshake_Hash& hash) + { + hash.update(io.send(*this)); + } + +/* +* Deserialize a Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(const std::vector<uint8_t>& buf) + { + if(buf.size()) + throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); + } + +/* +* Serialize a Server Hello Done message +*/ +std::vector<uint8_t> Server_Hello_Done::serialize() const + { + return std::vector<uint8_t>(); + } + +} + +} |