Coverage Report

Created: 2022-06-23 06:44

/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
}