/* * TLS handshake state (machine) implementation for TLS 1.3 * (C) 2022 Jack Lloyd * 2022 Hannes Rantzsch, René Meusel - neXenio GmbH * * Botan is released under the Simplified BSD License (see license.txt) */ #include #include #include #include #include #include namespace Botan::TLS { void Handshake_Layer::copy_data(std::span data_from_peer) { m_read_buffer.insert(m_read_buffer.end(), data_from_peer.begin(), data_from_peer.end()); } namespace { constexpr size_t HEADER_LENGTH = 4; template Handshake_Type handshake_type_from_byte(uint8_t byte_value) { const auto type = static_cast(byte_value); if constexpr(std::is_same_v) { switch(type) { case Handshake_Type::ClientHello: case Handshake_Type::ServerHello: // case Handshake_Type::EndOfEarlyData: // NYI: needs PSK/resumption support -- won't be offered in Client Hello for now case Handshake_Type::EncryptedExtensions: case Handshake_Type::Certificate: case Handshake_Type::CertificateRequest: case Handshake_Type::CertificateVerify: case Handshake_Type::Finished: return type; default: throw TLS_Exception(AlertType::UnexpectedMessage, "Unknown handshake message received"); } } else { switch(type) { case Handshake_Type::NewSessionTicket: case Handshake_Type::KeyUpdate: // case Handshake_Type::CertificateRequest: // NYI: post-handshake client auth (RFC 8446 4.6.2) -- won't be offered in Client Hello for now return type; default: throw TLS_Exception(AlertType::UnexpectedMessage, "Unknown post-handshake message received"); } } } template std::optional parse_message(TLS::TLS_Data_Reader& reader, const Policy& policy, const Connection_Side peer_side, const Certificate_Type cert_type) { // read the message header if(reader.remaining_bytes() < HEADER_LENGTH) { return std::nullopt; } Handshake_Type type = handshake_type_from_byte(reader.get_byte()); // make sure we have received the full message const size_t msg_len = reader.get_uint24_t(); if(reader.remaining_bytes() < msg_len) { return std::nullopt; } // create the message const auto msg = reader.get_fixed(msg_len); if constexpr(std::is_same_v) { switch(type) { // Client Hello and Server Hello messages are ambiguous. Both may come // from non-TLS 1.3 peers. Hence, their parsing is somewhat different. case Handshake_Type::ClientHello: // ... might be TLS 1.2 Client Hello or TLS 1.3 Client Hello return generalize_to(Client_Hello_13::parse(msg)); case Handshake_Type::ServerHello: // ... might be TLS 1.2 Server Hello or TLS 1.3 Server Hello or // a TLS 1.3 Hello Retry Request disguising as a Server Hello return generalize_to(Server_Hello_13::parse(msg)); // case Handshake_Type::EndOfEarlyData: // return End_Of_Early_Data(msg); case Handshake_Type::EncryptedExtensions: return Encrypted_Extensions(msg); case Handshake_Type::Certificate: return Certificate_13(msg, policy, peer_side, cert_type); case Handshake_Type::CertificateRequest: return Certificate_Request_13(msg, peer_side); case Handshake_Type::CertificateVerify: return Certificate_Verify_13(msg, peer_side); case Handshake_Type::Finished: return Finished_13(msg); default: BOTAN_ASSERT(false, "cannot be reached"); // make sure to update handshake_type_from_byte } } else { BOTAN_UNUSED(peer_side); switch(type) { case Handshake_Type::NewSessionTicket: return New_Session_Ticket_13(msg, peer_side); case Handshake_Type::KeyUpdate: return Key_Update(msg); default: BOTAN_ASSERT(false, "cannot be reached"); // make sure to update handshake_type_from_byte } } } } // namespace std::optional Handshake_Layer::next_message(const Policy& policy, Transcript_Hash_State& transcript_hash) { TLS::TLS_Data_Reader reader("handshake message", m_read_buffer); auto msg = parse_message(reader, policy, m_peer, m_certificate_type); if(msg.has_value()) { BOTAN_ASSERT_NOMSG(m_read_buffer.size() >= reader.read_so_far()); transcript_hash.update(std::span{m_read_buffer.data(), reader.read_so_far()}); m_read_buffer.erase(m_read_buffer.cbegin(), m_read_buffer.cbegin() + reader.read_so_far()); } return msg; } std::optional Handshake_Layer::next_post_handshake_message(const Policy& policy) { TLS::TLS_Data_Reader reader("post handshake message", m_read_buffer); auto msg = parse_message(reader, policy, m_peer, m_certificate_type); if(msg.has_value()) { m_read_buffer.erase(m_read_buffer.cbegin(), m_read_buffer.cbegin() + reader.read_so_far()); } return msg; } namespace { template const T& get(const std::reference_wrapper& v) { return v.get(); } template const T& get(const T& v) { // NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter) return v; } template std::vector marshall_message(const T& message) { auto [type, serialized] = std::visit([](const auto& msg) { return std::pair(get(msg).wire_type(), get(msg).serialize()); }, message); BOTAN_ASSERT_NOMSG(serialized.size() <= 0xFFFFFF); const uint32_t msg_size = static_cast(serialized.size()); std::vector header{ static_cast(type), get_byte<1>(msg_size), get_byte<2>(msg_size), get_byte<3>(msg_size)}; return concat(header, serialized); } } //namespace std::vector Handshake_Layer::prepare_message(const Handshake_Message_13_Ref message, Transcript_Hash_State& transcript_hash) { auto msg = marshall_message(message); transcript_hash.update(msg); return msg; } std::vector Handshake_Layer::prepare_post_handshake_message(const Post_Handshake_Message_13& message) { return marshall_message(message); } } // namespace Botan::TLS