Botan 3.4.0
Crypto and TLS for C&
tls_handshake_transitions.cpp
Go to the documentation of this file.
1/*
2* TLS Handshake State Transitions
3* (C) 2004-2006,2011,2012 Jack Lloyd
4* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/tls_handshake_transitions.h>
10
11#include <botan/tls_exceptn.h>
12
13#include <sstream>
14
15namespace Botan::TLS {
16
17namespace {
18
19uint32_t bitmask_for_handshake_type(Handshake_Type type) {
20 switch(type) {
22 return (1 << 0);
23
25 return (1 << 1);
26
28 return (1 << 2);
29
31 return (1 << 3);
32
34 return (1 << 4);
35
37 return (1 << 5);
38
40 return (1 << 6);
41
43 return (1 << 7);
44
46 return (1 << 8);
47
49 return (1 << 9);
50
52 return (1 << 10);
53
55 return (1 << 11);
56
58 return (1 << 12);
59
61 return (1 << 13);
62
64 return (1 << 14);
65
66 case Handshake_Type::EndOfEarlyData: // RFC 8446
67 return (1 << 15);
68
70 return (1 << 16);
71
72 case Handshake_Type::KeyUpdate: // RFC 8446
73 return (1 << 17);
74
75 case Handshake_Type::HelloRetryRequest: // RFC 8446
76 return (1 << 18);
77
78 // allow explicitly disabling new handshakes
80 return 0;
81 }
82
83 throw TLS_Exception(Alert::UnexpectedMessage,
84 "Unknown TLS handshake message type " + std::to_string(static_cast<size_t>(type)));
85}
86
87std::string handshake_mask_to_string(uint32_t mask, char combiner) {
106
107 std::ostringstream o;
108 bool empty = true;
109
110 for(auto&& t : types) {
111 if(mask & bitmask_for_handshake_type(t)) {
112 if(!empty) {
113 o << combiner;
114 }
116 empty = false;
117 }
118 }
119
120 return o.str();
121}
122
123} // namespace
124
126 const uint32_t mask = bitmask_for_handshake_type(msg_type);
127
128 return (m_hand_received_mask & mask) != 0;
129}
130
132 const uint32_t mask = bitmask_for_handshake_type(msg_type);
133
134 m_hand_received_mask |= mask;
135
136 const bool ok = (m_hand_expecting_mask & mask) != 0; // overlap?
137
138 if(!ok) {
139 const uint32_t seen_so_far = m_hand_received_mask & ~mask;
140
141 std::ostringstream msg;
142
143 msg << "Unexpected state transition in handshake got a " << handshake_type_to_string(msg_type);
144
145 if(m_hand_expecting_mask == 0) {
146 msg << " not expecting messages";
147 } else {
148 msg << " expected " << handshake_mask_to_string(m_hand_expecting_mask, '|');
149 }
150
151 if(seen_so_far != 0) {
152 msg << " seen " << handshake_mask_to_string(seen_so_far, '+');
153 }
154
155 throw Unexpected_Message(msg.str());
156 }
157
158 /* We don't know what to expect next, so force a call to
159 set_expected_next; if it doesn't happen, the next transition
160 check will always fail which is what we want.
161 */
162 m_hand_expecting_mask = 0;
163}
164
166 m_hand_expecting_mask |= bitmask_for_handshake_type(msg_type);
167}
168
169void Handshake_Transitions::set_expected_next(const std::vector<Handshake_Type>& msg_types) {
170 for(const auto type : msg_types) {
171 set_expected_next(type);
172 }
173}
174
176 return (bitmask_for_handshake_type(Handshake_Type::HandshakeCCS) & m_hand_expecting_mask) != 0;
177}
178
179} // namespace Botan::TLS
void confirm_transition_to(Handshake_Type msg_type)
bool received_handshake_msg(Handshake_Type msg_type) const
void set_expected_next(Handshake_Type msg_type)
const char * handshake_type_to_string(Handshake_Type type)