forked from Oryx-Embedded/CycloneSSL
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tls13_client_misc.c
344 lines (300 loc) · 10.5 KB
/
tls13_client_misc.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
/**
* @file tls13_client_misc.c
* @brief Helper functions for TLS 1.3 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 <string.h>
#include "tls.h"
#include "tls_handshake.h"
#include "tls_client.h"
#include "tls_common.h"
#include "tls_transcript_hash.h"
#include "tls_record.h"
#include "tls_misc.h"
#include "tls13_client_misc.h"
#include "tls13_key_material.h"
#include "tls13_ticket.h"
#include "debug.h"
//Check TLS library configuration
#if (TLS_SUPPORT == ENABLED && TLS_CLIENT_SUPPORT == ENABLED && \
TLS_MAX_VERSION >= TLS_VERSION_1_3)
/**
* @brief Check whether an incoming ServerHello message is a HelloRetryRequest
* @param[in] message Pointer to the ServerHello message
* @param[in] length Length of the ServerHello message
* @return TRUE is the message is a HelloRetryRequest, else FALSE
**/
bool_t tls13IsHelloRetryRequest(const TlsServerHello *message, size_t length)
{
bool_t res;
//Initialize flag
res = FALSE;
//Check the length of the incoming ServerHello message
if(length >= sizeof(TlsServerHello))
{
//Upon receiving a message with type ServerHello, implementations must
//first examine the Random field
if(!osMemcmp(&message->random, tls13HelloRetryRequestRandom,
sizeof(tls13HelloRetryRequestRandom)))
{
//The Random field matches the special value
res = TRUE;
}
}
//Return TRUE is the message is a HelloRetryRequest, else FALSE
return res;
}
/**
* @brief Compute PSK binder values
* @param[in] context Pointer to the TLS context
* @param[in] clientHello Pointer to the ClientHello message
* @param[in] clientHelloLen Length of the ClientHello message
* @param[in] identityList List of the identities that the client is willing
* to negotiate with the server
* @param[in,out] binderList List of HMAC values, one for each PSK offered in
* the PreSharedKey extension
* @return Error code
**/
error_t tls13ComputePskBinders(TlsContext *context, const void *clientHello,
size_t clientHelloLen, const Tls13PskIdentityList *identityList,
Tls13PskBinderList *binderList)
{
error_t error;
size_t n;
size_t m;
size_t truncatedClientHelloLen;
uint8_t *q;
const uint8_t *p;
Tls13PskBinder *binder;
const Tls13PskIdentity *identity;
//Initialize status code
error = NO_ERROR;
#if (TLS13_PSK_KE_SUPPORT == ENABLED || TLS13_PSK_DHE_KE_SUPPORT == ENABLED || \
TLS13_PSK_ECDHE_KE_SUPPORT == ENABLED)
//Check whether the ClientHello message contains a PreSharedKey extension
if(identityList != NULL && binderList != NULL)
{
//Point to the list of the identities that the client is willing to
//negotiate with the server
p = identityList->value;
n = ntohs(identityList->length);
//Point to the list of HMAC values, one for each PSK offered in the
//PreSharedKey extension
q = binderList->value;
m = ntohs(binderList->length);
//Each entry in the binders list is computed as an HMAC over a transcript
//hash containing a partial ClientHello up to the binders list itself
truncatedClientHelloLen = (uint8_t *) binderList - (uint8_t *) clientHello;
//Loop through the list of PSK identities
while(n > 0)
{
//Point to the current PskIdentity entry
identity = (Tls13PskIdentity *) p;
//Malformed PreSharedKey extension?
if(n < sizeof(TlsPskIdentity))
return ERROR_DECODING_FAILED;
if(n < (sizeof(TlsPskIdentity) + ntohs(identity->length)))
return ERROR_DECODING_FAILED;
//Point to the obfuscated_ticket_age field
p += sizeof(TlsPskIdentity) + ntohs(identity->length);
n -= sizeof(TlsPskIdentity) + ntohs(identity->length);
//The obfuscated_ticket_age field is a 32-bit unsigned integer
if(n < sizeof(uint32_t))
return ERROR_DECODING_FAILED;
//Point to the next PskIdentity entry
p += sizeof(uint32_t);
n -= sizeof(uint32_t);
//Point to the PskBinderEntry
binder = (Tls13PskBinder *) q;
//Malformed PreSharedKey extension?
if(m < sizeof(Tls13PskBinder))
return ERROR_DECODING_FAILED;
if(m < (sizeof(Tls13PskBinder) + binder->length))
return ERROR_DECODING_FAILED;
//Point to the next PskBinderEntry
q += sizeof(Tls13PskBinder) + binder->length;
m -= sizeof(Tls13PskBinder) + binder->length;
//Fix the value of the PSK binder
error = tls13ComputePskBinder(context, clientHello, clientHelloLen,
truncatedClientHelloLen, identity, binder->value, binder->length);
//Any error to report?
if(error)
break;
}
}
#endif
//Return status code
return error;
}
/**
* @brief Send early data to the remote TLS server
* @param[in] context Pointer to the TLS context
* @param[in] data Pointer to a buffer containing the data to be transmitted
* @param[in] length Number of bytes to be transmitted
* @param[out] written Actual number of bytes written
* @return Error code
**/
error_t tls13SendEarlyData(TlsContext *context, const void *data,
size_t length, size_t *written)
{
#if (TLS13_EARLY_DATA_SUPPORT == ENABLED)
error_t error;
size_t n;
//Actual number of bytes written
*written = 0;
//Valid PSK?
if(tls13IsPskValid(context))
{
//Make sure a valid cipher suite has been provisioned
if(context->pskCipherSuite == 0)
return ERROR_END_OF_STREAM;
}
else if(tls13IsTicketValid(context))
{
//Make sure the cipher suite associated with the ticket is valid
if(context->ticketCipherSuite == 0)
return ERROR_END_OF_STREAM;
}
else
{
//The pre-shared key is not valid
return ERROR_END_OF_STREAM;
}
//Initialize status code
error = NO_ERROR;
//TLS 1.3 allows clients to send data on the first flight
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;
}
}
//The TLS handshake is implemented as a state machine representing the
//current location in the protocol
if(context->state == TLS_STATE_INIT)
{
//TLS handshake initialization
error = tlsInitHandshake(context);
}
else if(context->state == TLS_STATE_CLIENT_HELLO)
{
//If the client opts to send application data in its first flight
//of messages, it must supply both the PreSharedKey and EarlyData
//extensions
context->earlyDataEnabled = TRUE;
//When a client first connects to a server, it is required to send
//the ClientHello as its first message
error = tlsSendClientHello(context);
}
else if(context->state == TLS_STATE_SERVER_HELLO)
{
//Initialize handshake message hashing
error = tlsInitTranscriptHash(context);
#if (TLS13_MIDDLEBOX_COMPAT_SUPPORT == ENABLED)
//In middlebox compatibility mode, the client sends a dummy
//ChangeCipherSpec record immediately before its second flight
context->state = TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC;
#else
//The client can send its second flight
context->state = TLS_STATE_CLIENT_HELLO_2;
#endif
}
else if(context->state == TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC)
{
//Send a dummy ChangeCipherSpec record
error = tlsSendChangeCipherSpec(context);
}
else if(context->state == TLS_STATE_CLIENT_HELLO_2)
{
//Compute early traffic keys
error = tls13GenerateEarlyTrafficKeys(context);
}
else if(context->state == TLS_STATE_EARLY_DATA)
{
//Send as much data as possible
if(*written < length &&
context->earlyDataLen < context->maxEarlyDataSize)
{
//Calculate the number of bytes to write at a time
n = MIN(context->txBufferMaxLen, length - *written);
n = MIN(n, context->maxEarlyDataSize - context->earlyDataLen);
//The record length must not exceed 16384 bytes
n = MIN(n, TLS_MAX_RECORD_LENGTH);
//Debug message
TRACE_INFO("Sending early data (%" PRIuSIZE " bytes)...\r\n", n);
//Send 0-RTT data
error = tlsWriteProtocolData(context, data, n,
TLS_TYPE_APPLICATION_DATA);
//Check status code
if(!error)
{
//Advance data pointer
data = (uint8_t *) data + n;
//Update byte counter
*written += n;
//Total amount of 0-RTT data that have been sent by the client
context->earlyDataLen += n;
}
}
else
{
//Clients must not more than max_early_data_size bytes of 0-RTT data
break;
}
}
else
{
//Report an error
error = ERROR_UNEXPECTED_STATE;
}
}
//Check status code
if(error == NO_ERROR && length != 0 && *written == 0)
{
error = ERROR_END_OF_STREAM;
}
//Return status code
return error;
#else
//Not implemented
return ERROR_NOT_IMPLEMENTED;
#endif
}
#endif