-
Notifications
You must be signed in to change notification settings - Fork 16
/
tls_server_fsm.c
388 lines (343 loc) · 12.9 KB
/
tls_server_fsm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/**
* @file tls_server_fsm.c
* @brief TLS state machine (TLS server)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
*
* This file is part of CycloneSSL Open.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @author Oryx Embedded SARL (www.oryx-embedded.com)
* @version 2.4.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL TLS_TRACE_LEVEL
//Dependencies
#include "tls.h"
#include "tls_handshake.h"
#include "tls_server.h"
#include "tls_server_fsm.h"
#include "tls_common.h"
#include "tls_cache.h"
#include "tls_record.h"
#include "tls_misc.h"
#include "tls13_server.h"
#include "tls13_common.h"
#include "tls13_key_material.h"
#include "debug.h"
//Check TLS library configuration
#if (TLS_SUPPORT == ENABLED && TLS_SERVER_SUPPORT == ENABLED)
/**
* @brief TLS server handshake
* @param[in] context Pointer to the TLS context
* @return Error code
**/
error_t tlsPerformServerHandshake(TlsContext *context)
{
error_t error;
//Initialize status code
error = NO_ERROR;
//Wait for the handshake to complete
while(!error)
{
//TLS protocol?
if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_STREAM)
{
//Check current state
if(context->state != TLS_STATE_INIT &&
context->state != TLS_STATE_CLOSED)
{
//Flush send buffer
error = tlsWriteProtocolData(context, NULL, 0, TLS_TYPE_NONE);
//Any error to report?
if(error)
break;
}
}
//Check whether the handshake is complete
if(context->state == TLS_STATE_APPLICATION_DATA)
{
//At this is point, the handshake is complete and the server starts
//to exchange application-layer data
break;
}
//The TLS handshake is implemented as a state machine representing the
//current location in the protocol
switch(context->state)
{
//Initial state?
case TLS_STATE_INIT:
//TLS handshake initialization
error = tlsInitHandshake(context);
break;
//Sending ServerHello message?
case TLS_STATE_SERVER_HELLO:
case TLS_STATE_SERVER_HELLO_2:
//The server will send this message in response to a ClientHello
//message when it was able to find an acceptable set of algorithms
error = tlsSendServerHello(context);
break;
//Sending Certificate message?
case TLS_STATE_SERVER_CERTIFICATE:
//The server must send a Certificate message whenever the agreed-
//upon key exchange method uses certificates for authentication. This
//message will always immediately follow the ServerHello message
error = tlsSendCertificate(context);
break;
//Sending Certificate message?
case TLS_STATE_CERTIFICATE_REQUEST:
//A non-anonymous server can optionally request a certificate from the
//client, if appropriate for the selected cipher suite. This message,
//if sent, will immediately follow the ServerKeyExchange message
error = tlsSendCertificateRequest(context);
break;
//Sending NewSessionTicket message?
case TLS_STATE_NEW_SESSION_TICKET:
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//TLS 1.3 currently selected?
if(context->version == TLS_VERSION_1_3)
{
//At any time after the server has received the client Finished
//message, it may send a NewSessionTicket message
error = tls13SendNewSessionTicket(context);
}
else
#endif
{
//The NewSessionTicket message is sent by the server during the TLS
//handshake before the ChangeCipherSpec message
error = tlsSendNewSessionTicket(context);
}
break;
//Sending ChangeCipherSpec message?
case TLS_STATE_SERVER_CHANGE_CIPHER_SPEC:
case TLS_STATE_SERVER_CHANGE_CIPHER_SPEC_2:
//The ChangeCipherSpec message is sent by the server and to notify the
//client that subsequent records will be protected under the newly
//negotiated CipherSpec and keys
error = tlsSendChangeCipherSpec(context);
break;
//Sending Finished message?
case TLS_STATE_SERVER_FINISHED:
//A Finished message is always sent immediately after a ChangeCipherSpec
//message to verify that the key exchange and authentication processes
//were successful
error = tlsSendFinished(context);
break;
#if (DTLS_SUPPORT == ENABLED)
//Sending HelloVerifyRequest message?
case TLS_STATE_HELLO_VERIFY_REQUEST:
//When the client sends its ClientHello message to the server, the
//server may respond with a HelloVerifyRequest message
error = dtlsSendHelloVerifyRequest(context);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
//Sending ServerKeyExchange message?
case TLS_STATE_SERVER_KEY_EXCHANGE:
//The ServerKeyExchange message is sent by the server only when the
//server Certificate message (if sent) does not contain enough data
//to allow the client to exchange a premaster secret
error = tlsSendServerKeyExchange(context);
break;
//Sending ServerHelloDone message?
case TLS_STATE_SERVER_HELLO_DONE:
//The ServerHelloDone message is sent by the server to indicate the
//end of the ServerHello and associated messages
error = tlsSendServerHelloDone(context);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//Sending HelloRetryRequest message?
case TLS_STATE_HELLO_RETRY_REQUEST:
//The server sends a HelloRetryRequest message if the ClientHello
//message does not contain sufficient information to proceed with
//the handshake
error = tls13SendHelloRetryRequest(context);
break;
//Handshake traffic key generation?
case TLS_STATE_HANDSHAKE_TRAFFIC_KEYS:
//Compute handshake traffic keys
error = tls13GenerateHandshakeTrafficKeys(context);
break;
//Sending EncryptedExtensions message?
case TLS_STATE_ENCRYPTED_EXTENSIONS:
//The server sends the EncryptedExtensions message immediately after
//the ServerHello message. The EncryptedExtensions message contains
//extensions that can be protected
error = tls13SendEncryptedExtensions(context);
break;
//Sending CertificateVerify message?
case TLS_STATE_SERVER_CERTIFICATE_VERIFY:
//Servers must send this message when authenticating via a
//certificate. When sent, this message must appear immediately
//after the Certificate message
error = tlsSendCertificateVerify(context);
break;
//Server application traffic key generation?
case TLS_STATE_SERVER_APP_TRAFFIC_KEYS:
//Compute server application traffic keys
error = tls13GenerateServerAppTrafficKeys(context);
break;
//Client application traffic key generation?
case TLS_STATE_CLIENT_APP_TRAFFIC_KEYS:
//Compute client application traffic keys
error = tls13GenerateClientAppTrafficKeys(context);
break;
//Sending KeyUpdate message?
case TLS_STATE_KEY_UPDATE:
//The KeyUpdate handshake message is used to indicate that the sender
//is updating its sending cryptographic keys
error = tls13SendKeyUpdate(context);
break;
#endif
//Waiting for a message from the client?
case TLS_STATE_CLIENT_HELLO:
case TLS_STATE_CLIENT_HELLO_2:
case TLS_STATE_CLIENT_CERTIFICATE:
case TLS_STATE_CLIENT_KEY_EXCHANGE:
case TLS_STATE_CLIENT_CERTIFICATE_VERIFY:
case TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC:
case TLS_STATE_CLIENT_FINISHED:
//Receive client's message
error = tlsReceiveHandshakeMessage(context);
break;
//Sending Alert message?
case TLS_STATE_CLOSING:
//Mark the TLS connection as closed
tlsChangeState(context, TLS_STATE_CLOSED);
break;
//TLS connection closed?
case TLS_STATE_CLOSED:
//Debug message
TRACE_WARNING("TLS handshake failure!\r\n");
//Report an error
error = ERROR_HANDSHAKE_FAILED;
break;
//Invalid state?
default:
//Report an error
error = ERROR_UNEXPECTED_STATE;
break;
}
}
//Successful TLS handshake?
if(!error)
{
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
//Version of TLS prior to TLS 1.3?
if(context->version <= TLS_VERSION_1_2)
{
#if (TLS_TICKET_SUPPORT == ENABLED)
//Any ticket presented by the client?
if(context->sessionTicketExtReceived)
{
//If a ticket is presented by the client, the server must not
//attempt to use the Session ID in the ClientHello for stateful
//session resumption
}
else
#endif
{
//Save current session in the session cache for further reuse
tlsSaveToCache(context);
}
}
#endif
}
else
{
//Send an alert message to the client, if applicable
tlsProcessError(context, error);
}
//Return status code
return error;
}
/**
* @brief Parse client's handshake message
* @param[in] context Pointer to the TLS context
* @param[in] msgType Handshake message type
* @param[in] message Pointer to the handshake message to parse
* @param[in] length Length of the handshake messaged
* @return Error code
**/
error_t tlsParseClientHandshakeMessage(TlsContext *context, uint8_t msgType,
const void *message, size_t length)
{
error_t error;
//Check handshake message type
switch(msgType)
{
//ClientHello message received?
case TLS_TYPE_CLIENT_HELLO:
//When a client first connects to a server, it is required to send the
//ClientHello as its first message
error = tlsParseClientHello(context, message, length);
break;
//Certificate message received?
case TLS_TYPE_CERTIFICATE:
//This is the first message the client can send after receiving a
//ServerHelloDone message. This message is only sent if the server
//requests a certificate
error = tlsParseCertificate(context, message, length);
break;
//CertificateVerify message received?
case TLS_TYPE_CERTIFICATE_VERIFY:
//This message is used to provide explicit verification of a client
//certificate. This message is only sent following a client certificate
//that has signing capability. When sent, it must immediately follow
//the clientKeyExchange message
error = tlsParseCertificateVerify(context, message, length);
break;
//Finished message received?
case TLS_TYPE_FINISHED:
//A Finished message is always sent immediately after a ChangeCipherSpec
//message to verify that the key exchange and authentication processes
//were successful
error = tlsParseFinished(context, message, length);
break;
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
//ClientKeyExchange message received?
case TLS_TYPE_CLIENT_KEY_EXCHANGE:
//This message must immediately follow the client certificate message, if
//it is sent. Otherwise, it must be the first message sent by the client
//after it receives the ServerHelloDone message
error = tlsParseClientKeyExchange(context, message, length);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//KeyUpdate message received?
case TLS_TYPE_KEY_UPDATE:
//The KeyUpdate handshake message is used to indicate that the client is
//updating its sending cryptographic keys. This message can be sent by
//the client after it has sent a Finished message
error = tls13ParseKeyUpdate(context, message, length);
break;
#endif
//Invalid handshake message received?
default:
//Report an error
error = ERROR_UNEXPECTED_MESSAGE;
break;
}
//Return status code
return error;
}
#endif