forked from Oryx-Embedded/CycloneSSL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tls_client_fsm.c
393 lines (346 loc) · 13.4 KB
/
tls_client_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
389
390
391
392
393
/**
* @file tls_client_fsm.c
* @brief TLS state machine (TLS client)
*
* @section License
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Copyright (C) 2010-2022 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.1.4
**/
//Switch to the appropriate trace level
#define TRACE_LEVEL TLS_TRACE_LEVEL
//Dependencies
#include "tls.h"
#include "tls_handshake.h"
#include "tls_client.h"
#include "tls_client_fsm.h"
#include "tls_common.h"
#include "tls_record.h"
#include "tls_misc.h"
#include "tls13_client.h"
#include "tls13_client_misc.h"
#include "tls13_common.h"
#include "tls13_key_material.h"
#include "debug.h"
//Check TLS library configuration
#if (TLS_SUPPORT == ENABLED && TLS_CLIENT_SUPPORT == ENABLED)
/**
* @brief TLS client handshake
* @param[in] context Pointer to the TLS context
* @return Error code
**/
error_t tlsPerformClientHandshake(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 client 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 ClientHello message?
case TLS_STATE_CLIENT_HELLO:
case TLS_STATE_CLIENT_HELLO_2:
//When a client first connects to a server, it is required to send
//the ClientHello as its first message
error = tlsSendClientHello(context);
break;
//Sending Certificate message?
case TLS_STATE_CLIENT_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 = tlsSendCertificate(context);
break;
//Sending CertificateVerify message?
case TLS_STATE_CLIENT_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 = tlsSendCertificateVerify(context);
break;
//Sending ChangeCipherSpec message?
case TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC:
case TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC_2:
//The ChangeCipherSpec message is sent by the client and to notify the
//server that subsequent records will be protected under the newly
//negotiated CipherSpec and keys
error = tlsSendChangeCipherSpec(context);
break;
//Sending Finished message?
case TLS_STATE_CLIENT_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 (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
//Sending ClientKeyExchange message?
case TLS_STATE_CLIENT_KEY_EXCHANGE:
//This message is always sent by the client. It 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 = tlsSendClientKeyExchange(context);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//Sending EndOfEarlyData message?
case TLS_STATE_END_OF_EARLY_DATA:
//The EndOfEarlyData message indicates that all 0-RTT application
//data messages, if any, have been transmitted and that the following
//records are protected under handshake traffic keys
error = tls13SendEndOfEarlyData(context);
break;
//Handshake traffic key generation?
case TLS_STATE_HANDSHAKE_TRAFFIC_KEYS:
//Compute handshake traffic keys
error = tls13GenerateHandshakeTrafficKeys(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 server?
case TLS_STATE_SERVER_HELLO:
case TLS_STATE_SERVER_HELLO_2:
case TLS_STATE_SERVER_HELLO_3:
case TLS_STATE_ENCRYPTED_EXTENSIONS:
case TLS_STATE_SERVER_CERTIFICATE:
case TLS_STATE_SERVER_KEY_EXCHANGE:
case TLS_STATE_SERVER_CERTIFICATE_VERIFY:
case TLS_STATE_CERTIFICATE_REQUEST:
case TLS_STATE_SERVER_HELLO_DONE:
case TLS_STATE_NEW_SESSION_TICKET:
case TLS_STATE_SERVER_CHANGE_CIPHER_SPEC:
case TLS_STATE_SERVER_FINISHED:
//Receive server's message
error = tlsReceiveHandshakeMessage(context);
break;
//Sending Alert message?
case TLS_STATE_CLOSING:
//Mark the TLS connection as closed
context->state = 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;
}
}
//Any error to report?
if(error)
{
//Send an alert message to the server, if applicable
tlsProcessError(context, error);
}
//Return status code
return error;
}
/**
* @brief Parse server'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 tlsParseServerHandshakeMessage(TlsContext *context, uint8_t msgType,
const void *message, size_t length)
{
error_t error;
//Check handshake message type
switch(msgType)
{
//HelloRequest message received?
case TLS_TYPE_HELLO_REQUEST:
//HelloRequest is a simple notification that the client should begin the
//negotiation process anew
error = tlsParseHelloRequest(context, message, length);
break;
//ServerHello message received?
case TLS_TYPE_SERVER_HELLO:
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//For backward compatibility with middleboxes the HelloRetryRequest
//message uses the same structure as the ServerHello, but with Random
//field set to a special value
if(tls13IsHelloRetryRequest(message, length))
{
//The server sends a HelloRetryRequest message if the ClientHello
//message does not contain sufficient information to proceed with
//the handshake
error = tls13ParseHelloRetryRequest(context, message, length);
}
else
#endif
{
//The server will send this message in response to a ClientHello
//message when it was able to find an acceptable set of algorithms
error = tlsParseServerHello(context, message, length);
}
break;
//Certificate message received?
case TLS_TYPE_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 = tlsParseCertificate(context, message, length);
break;
//CertificateRequest message received?
case TLS_TYPE_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 = tlsParseCertificateRequest(context, message, length);
break;
//NewSessionTicket message received?
case TLS_TYPE_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 = tls13ParseNewSessionTicket(context, message, length);
}
else
#endif
{
//The NewSessionTicket message is sent by the server during the TLS
//handshake before the ChangeCipherSpec message
error = tlsParseNewSessionTicket(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 (DTLS_SUPPORT == ENABLED)
//HelloVerifyRequest message received?
case TLS_TYPE_HELLO_VERIFY_REQUEST:
//When the client sends its ClientHello message to the server, the server
//may respond with a HelloVerifyRequest message
error = dtlsParseHelloVerifyRequest(context, message, length);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_0 && TLS_MIN_VERSION <= TLS_VERSION_1_2)
//ServerKeyExchange message received?
case TLS_TYPE_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 = tlsParseServerKeyExchange(context, message, length);
break;
//ServerHelloDone message received?
case TLS_TYPE_SERVER_HELLO_DONE:
//The ServerHelloDone message is sent by the server to indicate the end
//of the ServerHello and associated messages
error = tlsParseServerHelloDone(context, message, length);
break;
#endif
#if (TLS_MAX_VERSION >= TLS_VERSION_1_3 && TLS_MIN_VERSION <= TLS_VERSION_1_3)
//EncryptedExtensions message received?
case TLS_TYPE_ENCRYPTED_EXTENSIONS:
//The server sends the EncryptedExtensions message immediately after
//the ServerHello message. The EncryptedExtensions message contains
//extensions that can be protected
error = tls13ParseEncryptedExtensions(context, message, length);
break;
//CertificateVerify message received?
case TLS_TYPE_CERTIFICATE_VERIFY:
//Servers must send this message when authenticating via a certificate.
//When sent, this message must appear immediately after the Certificate
//message
error = tlsParseCertificateVerify(context, message, length);
break;
//KeyUpdate message received?
case TLS_TYPE_KEY_UPDATE:
//The KeyUpdate handshake message is used to indicate that the server
//is updating its sending cryptographic keys. This message can be sent
//by the server 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;
}
//Return status code
return error;
}
#endif