/src/botan/src/lib/tls/tls_handshake_transitions.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
15 | | namespace Botan::TLS { |
16 | | |
17 | | namespace { |
18 | | |
19 | | uint32_t bitmask_for_handshake_type(Handshake_Type type) |
20 | 194k | { |
21 | 194k | switch(type) |
22 | 194k | { |
23 | 206 | case HELLO_VERIFY_REQUEST: |
24 | 206 | return (1 << 0); |
25 | | |
26 | 265 | case HELLO_REQUEST: |
27 | 265 | return (1 << 1); |
28 | | |
29 | 45.2k | case CLIENT_HELLO: |
30 | 45.2k | return (1 << 2); |
31 | | |
32 | 2.51k | case SERVER_HELLO: |
33 | 2.51k | return (1 << 3); |
34 | | |
35 | 14.3k | case CERTIFICATE: |
36 | 14.3k | return (1 << 4); |
37 | | |
38 | 201 | case CERTIFICATE_URL: |
39 | 201 | return (1 << 5); |
40 | | |
41 | 200 | case CERTIFICATE_STATUS: |
42 | 200 | return (1 << 6); |
43 | | |
44 | 206 | case SERVER_KEX: |
45 | 206 | return (1 << 7); |
46 | | |
47 | 203 | case CERTIFICATE_REQUEST: |
48 | 203 | return (1 << 8); |
49 | | |
50 | 204 | case SERVER_HELLO_DONE: |
51 | 204 | return (1 << 9); |
52 | | |
53 | 202 | case CERTIFICATE_VERIFY: |
54 | 202 | return (1 << 10); |
55 | | |
56 | 34.0k | case CLIENT_KEX: |
57 | 34.0k | return (1 << 11); |
58 | | |
59 | 202 | case NEW_SESSION_TICKET: |
60 | 202 | return (1 << 12); |
61 | | |
62 | 94.7k | case HANDSHAKE_CCS: |
63 | 94.7k | return (1 << 13); |
64 | | |
65 | 1.06k | case FINISHED: |
66 | 1.06k | return (1 << 14); |
67 | | |
68 | | // allow explicitly disabling new handshakes |
69 | 313 | case HANDSHAKE_NONE: |
70 | 313 | return 0; |
71 | 194k | } |
72 | | |
73 | 59 | throw TLS_Exception(Alert::UNEXPECTED_MESSAGE, |
74 | 59 | "Unknown TLS handshake message type " + std::to_string(type)); |
75 | 194k | } |
76 | | |
77 | | std::string handshake_mask_to_string(uint32_t mask, char combiner) |
78 | 197 | { |
79 | 197 | const Handshake_Type types[] = |
80 | 197 | { |
81 | 197 | HELLO_VERIFY_REQUEST, |
82 | 197 | HELLO_REQUEST, |
83 | 197 | CLIENT_HELLO, |
84 | 197 | SERVER_HELLO, |
85 | 197 | CERTIFICATE, |
86 | 197 | CERTIFICATE_URL, |
87 | 197 | CERTIFICATE_STATUS, |
88 | 197 | SERVER_KEX, |
89 | 197 | CERTIFICATE_REQUEST, |
90 | 197 | SERVER_HELLO_DONE, |
91 | 197 | CERTIFICATE_VERIFY, |
92 | 197 | CLIENT_KEX, |
93 | 197 | NEW_SESSION_TICKET, |
94 | 197 | HANDSHAKE_CCS, |
95 | 197 | FINISHED |
96 | 197 | }; |
97 | | |
98 | 197 | std::ostringstream o; |
99 | 197 | bool empty = true; |
100 | | |
101 | 197 | for(auto&& t : types) |
102 | 2.95k | { |
103 | 2.95k | if(mask & bitmask_for_handshake_type(t)) |
104 | 226 | { |
105 | 226 | if(!empty) |
106 | 29 | { o << combiner; } |
107 | 226 | o << handshake_type_to_string(t); |
108 | 226 | empty = false; |
109 | 226 | } |
110 | 2.95k | } |
111 | | |
112 | 197 | return o.str(); |
113 | 197 | } |
114 | | |
115 | | } |
116 | | |
117 | | bool Handshake_Transitions::received_handshake_msg(Handshake_Type msg_type) const |
118 | 14.1k | { |
119 | 14.1k | const uint32_t mask = bitmask_for_handshake_type(msg_type); |
120 | | |
121 | 14.1k | return (m_hand_received_mask & mask) != 0; |
122 | 14.1k | } |
123 | | |
124 | | void Handshake_Transitions::confirm_transition_to(Handshake_Type msg_type) |
125 | 37.7k | { |
126 | 37.7k | const uint32_t mask = bitmask_for_handshake_type(msg_type); |
127 | | |
128 | 37.7k | m_hand_received_mask |= mask; |
129 | | |
130 | 37.7k | const bool ok = (m_hand_expecting_mask & mask) != 0; // overlap? |
131 | | |
132 | 37.7k | if(!ok) |
133 | 150 | { |
134 | 150 | const uint32_t seen_so_far = m_hand_received_mask & ~mask; |
135 | | |
136 | 150 | std::ostringstream msg; |
137 | | |
138 | 150 | msg << "Unexpected state transition in handshake got a " << handshake_type_to_string(msg_type); |
139 | | |
140 | 150 | if(m_hand_expecting_mask == 0) |
141 | 1 | { msg << " not expecting messages"; } |
142 | 149 | else |
143 | 149 | { msg << " expected " << handshake_mask_to_string(m_hand_expecting_mask, '|'); } |
144 | | |
145 | 150 | if(seen_so_far != 0) |
146 | 48 | { msg << " seen " << handshake_mask_to_string(seen_so_far, '+'); } |
147 | | |
148 | 150 | throw Unexpected_Message(msg.str()); |
149 | 150 | } |
150 | | |
151 | | /* We don't know what to expect next, so force a call to |
152 | | set_expected_next; if it doesn't happen, the next transition |
153 | | check will always fail which is what we want. |
154 | | */ |
155 | 37.6k | m_hand_expecting_mask = 0; |
156 | 37.6k | } |
157 | | |
158 | | void Handshake_Transitions::set_expected_next(Handshake_Type msg_type) |
159 | 59.5k | { |
160 | 59.5k | m_hand_expecting_mask |= bitmask_for_handshake_type(msg_type); |
161 | 59.5k | } |
162 | | |
163 | | void Handshake_Transitions::set_expected_next(const std::vector<Handshake_Type>& msg_types) |
164 | 0 | { |
165 | 0 | for (const auto type : msg_types) |
166 | 0 | { |
167 | 0 | set_expected_next(type); |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | | bool Handshake_Transitions::change_cipher_spec_expected() const |
172 | 79.8k | { |
173 | 79.8k | return (bitmask_for_handshake_type(HANDSHAKE_CCS) & m_hand_expecting_mask) != 0; |
174 | 79.8k | } |
175 | | |
176 | | } |