tls13_client_misc.c
Go to the documentation of this file.
1 /**
2  * @file tls13_client_misc.c
3  * @brief Helper functions for TLS 1.3 client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSL Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TLS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "tls.h"
36 #include "tls_handshake.h"
37 #include "tls_client.h"
38 #include "tls_common.h"
39 #include "tls_transcript_hash.h"
40 #include "tls_record.h"
41 #include "tls_misc.h"
42 #include "tls13_client_misc.h"
43 #include "tls13_key_material.h"
44 #include "tls13_ticket.h"
45 #include "debug.h"
46 
47 //Check TLS library configuration
48 #if (TLS_SUPPORT == ENABLED && TLS_CLIENT_SUPPORT == ENABLED && \
49  TLS_MAX_VERSION >= TLS_VERSION_1_3)
50 
51 
52 /**
53  * @brief Check whether an incoming ServerHello message is a HelloRetryRequest
54  * @param[in] message Pointer to the ServerHello message
55  * @param[in] length Length of the ServerHello message
56  * @return TRUE is the message is a HelloRetryRequest, else FALSE
57  **/
58 
60 {
61  bool_t res;
62 
63  //Initialize flag
64  res = FALSE;
65 
66  //Check the length of the incoming ServerHello message
67  if(length >= sizeof(TlsServerHello))
68  {
69  //Upon receiving a message with type ServerHello, implementations must
70  //first examine the Random field
72  sizeof(tls13HelloRetryRequestRandom)) == 0)
73  {
74  //The Random field matches the special value
75  res = TRUE;
76  }
77  }
78 
79  //Return TRUE is the message is a HelloRetryRequest, else FALSE
80  return res;
81 }
82 
83 
84 /**
85  * @brief Compute PSK binder values
86  * @param[in] context Pointer to the TLS context
87  * @param[in] clientHello Pointer to the ClientHello message
88  * @param[in] clientHelloLen Length of the ClientHello message
89  * @param[in] identityList List of the identities that the client is willing
90  * to negotiate with the server
91  * @param[in,out] binderList List of HMAC values, one for each PSK offered in
92  * the PreSharedKey extension
93  * @return Error code
94  **/
95 
96 error_t tls13ComputePskBinders(TlsContext *context, const void *clientHello,
97  size_t clientHelloLen, const Tls13PskIdentityList *identityList,
98  Tls13PskBinderList *binderList)
99 {
100  error_t error;
101  size_t n;
102  size_t m;
103  size_t truncatedClientHelloLen;
104  uint8_t *q;
105  const uint8_t *p;
106  Tls13PskBinder *binder;
107  const Tls13PskIdentity *identity;
108 
109  //Initialize status code
110  error = NO_ERROR;
111 
112 #if (TLS13_PSK_KE_SUPPORT == ENABLED || TLS13_PSK_DHE_KE_SUPPORT == ENABLED || \
113  TLS13_PSK_ECDHE_KE_SUPPORT == ENABLED)
114  //Check whether the ClientHello message contains a PreSharedKey extension
115  if(identityList != NULL && binderList != NULL)
116  {
117  //Point to the list of the identities that the client is willing to
118  //negotiate with the server
119  p = identityList->value;
120  n = ntohs(identityList->length);
121 
122  //Point to the list of HMAC values, one for each PSK offered in the
123  //PreSharedKey extension
124  q = binderList->value;
125  m = ntohs(binderList->length);
126 
127  //Each entry in the binders list is computed as an HMAC over a transcript
128  //hash containing a partial ClientHello up to the binders list itself
129  truncatedClientHelloLen = (uint8_t *) binderList - (uint8_t *) clientHello;
130 
131  //Loop through the list of PSK identities
132  while(n > 0)
133  {
134  //Point to the current PskIdentity entry
135  identity = (Tls13PskIdentity *) p;
136 
137  //Malformed PreSharedKey extension?
138  if(n < sizeof(TlsPskIdentity))
139  return ERROR_DECODING_FAILED;
140  if(n < (sizeof(TlsPskIdentity) + ntohs(identity->length)))
141  return ERROR_DECODING_FAILED;
142 
143  //Point to the obfuscated_ticket_age field
144  p += sizeof(TlsPskIdentity) + ntohs(identity->length);
145  n -= sizeof(TlsPskIdentity) + ntohs(identity->length);
146 
147  //The obfuscated_ticket_age field is a 32-bit unsigned integer
148  if(n < sizeof(uint32_t))
149  return ERROR_DECODING_FAILED;
150 
151  //Point to the next PskIdentity entry
152  p += sizeof(uint32_t);
153  n -= sizeof(uint32_t);
154 
155  //Point to the PskBinderEntry
156  binder = (Tls13PskBinder *) q;
157 
158  //Malformed PreSharedKey extension?
159  if(m < sizeof(Tls13PskBinder))
160  return ERROR_DECODING_FAILED;
161  if(m < (sizeof(Tls13PskBinder) + binder->length))
162  return ERROR_DECODING_FAILED;
163 
164  //Point to the next PskBinderEntry
165  q += sizeof(Tls13PskBinder) + binder->length;
166  m -= sizeof(Tls13PskBinder) + binder->length;
167 
168  //Fix the value of the PSK binder
169  error = tls13ComputePskBinder(context, clientHello, clientHelloLen,
170  truncatedClientHelloLen, identity, binder->value, binder->length);
171  //Any error to report?
172  if(error)
173  break;
174  }
175  }
176 #endif
177 
178  //Return status code
179  return error;
180 }
181 
182 
183 /**
184  * @brief Send early data to the remote TLS server
185  * @param[in] context Pointer to the TLS context
186  * @param[in] data Pointer to a buffer containing the data to be transmitted
187  * @param[in] length Number of bytes to be transmitted
188  * @param[out] written Actual number of bytes written
189  * @return Error code
190  **/
191 
193  size_t length, size_t *written)
194 {
195 #if (TLS13_EARLY_DATA_SUPPORT == ENABLED)
196  error_t error;
197  size_t n;
198 
199  //Actual number of bytes written
200  *written = 0;
201 
202  //Valid PSK?
203  if(tls13IsPskValid(context))
204  {
205  //Make sure a valid cipher suite has been provisioned
206  if(context->pskCipherSuite == 0)
207  return ERROR_END_OF_STREAM;
208  }
209  else if(tls13IsTicketValid(context))
210  {
211  //Make sure the cipher suite associated with the ticket is valid
212  if(context->ticketCipherSuite == 0)
213  return ERROR_END_OF_STREAM;
214  }
215  else
216  {
217  //The pre-shared key is not valid
218  return ERROR_END_OF_STREAM;
219  }
220 
221  //Initialize status code
222  error = NO_ERROR;
223 
224  //TLS 1.3 allows clients to send data on the first flight
225  while(!error)
226  {
227  //TLS protocol?
228  if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_STREAM)
229  {
230  //Check current state
231  if(context->state != TLS_STATE_INIT &&
232  context->state != TLS_STATE_CLOSED)
233  {
234  //Flush send buffer
235  error = tlsWriteProtocolData(context, NULL, 0, TLS_TYPE_NONE);
236  //Any error to report?
237  if(error)
238  break;
239  }
240  }
241 
242  //The TLS handshake is implemented as a state machine representing the
243  //current location in the protocol
244  if(context->state == TLS_STATE_INIT)
245  {
246  //TLS handshake initialization
247  error = tlsInitHandshake(context);
248  }
249  else if(context->state == TLS_STATE_CLIENT_HELLO)
250  {
251  //If the client opts to send application data in its first flight
252  //of messages, it must supply both the PreSharedKey and EarlyData
253  //extensions
254  context->earlyDataEnabled = TRUE;
255 
256  //When a client first connects to a server, it is required to send
257  //the ClientHello as its first message
258  error = tlsSendClientHello(context);
259  }
260  else if(context->state == TLS_STATE_SERVER_HELLO)
261  {
262  //Initialize handshake message hashing
263  error = tlsInitTranscriptHash(context);
264 
265 #if (TLS13_MIDDLEBOX_COMPAT_SUPPORT == ENABLED)
266  //DTLS implementations do not use the "compatibility mode" and must
267  //not send ChangeCipherSpec messages (refer to RFC 9147, section 5)
268  if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_STREAM)
269  {
270  //In middlebox compatibility mode, the client sends a dummy
271  //ChangeCipherSpec record immediately before its second flight
273  }
274  else
275 #endif
276  {
277  //The client can send its second flight
279  }
280  }
281  else if(context->state == TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC)
282  {
283  //Send a dummy ChangeCipherSpec record
284  error = tlsSendChangeCipherSpec(context);
285  }
286  else if(context->state == TLS_STATE_CLIENT_HELLO_2)
287  {
288  //Compute early traffic keys
289  error = tls13GenerateEarlyTrafficKeys(context);
290  }
291  else if(context->state == TLS_STATE_EARLY_DATA)
292  {
293  //Send as much data as possible
294  if(*written < length &&
295  context->earlyDataLen < context->maxEarlyDataSize)
296  {
297  //Calculate the number of bytes to write at a time
298  n = MIN(context->txBufferMaxLen, length - *written);
299  n = MIN(n, context->maxEarlyDataSize - context->earlyDataLen);
300 
301  //The record length must not exceed 16384 bytes
303 
304  //Debug message
305  TRACE_INFO("Sending early data (%" PRIuSIZE " bytes)...\r\n", n);
306 
307  //Send 0-RTT data
308  error = tlsWriteProtocolData(context, data, n,
310 
311  //Check status code
312  if(!error)
313  {
314  //Advance data pointer
315  data = (uint8_t *) data + n;
316  //Update byte counter
317  *written += n;
318 
319  //Total amount of 0-RTT data that have been sent by the client
320  context->earlyDataLen += n;
321  }
322  }
323  else
324  {
325  //Clients must not more than max_early_data_size bytes of 0-RTT data
326  break;
327  }
328  }
329  else
330  {
331  //Report an error
332  error = ERROR_UNEXPECTED_STATE;
333  }
334  }
335 
336  //Check status code
337  if(error == NO_ERROR && length != 0 && *written == 0)
338  {
339  error = ERROR_END_OF_STREAM;
340  }
341 
342  //Return status code
343  return error;
344 #else
345  //Not implemented
346  return ERROR_NOT_IMPLEMENTED;
347 #endif
348 }
349 
350 #endif
uint8_t message[]
Definition: chap.h:154
#define PRIuSIZE
int bool_t
Definition: compiler_port.h:53
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
error_t
Error codes.
Definition: error.h:43
@ ERROR_END_OF_STREAM
Definition: error.h:210
@ ERROR_DECODING_FAILED
Definition: error.h:240
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_UNEXPECTED_STATE
Definition: error.h:99
uint8_t data[]
Definition: ethernet.h:222
uint8_t p
Definition: ndp.h:300
uint8_t m
Definition: ndp.h:304
#define MIN(a, b)
Definition: os_port.h:63
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
const uint8_t res[]
uint8_t length
Definition: tcp.h:368
error_t tls13SendEarlyData(TlsContext *context, const void *data, size_t length, size_t *written)
Send early data to the remote TLS server.
error_t tls13ComputePskBinders(TlsContext *context, const void *clientHello, size_t clientHelloLen, const Tls13PskIdentityList *identityList, Tls13PskBinderList *binderList)
Compute PSK binder values.
bool_t tls13IsHelloRetryRequest(const TlsServerHello *message, size_t length)
Check whether an incoming ServerHello message is a HelloRetryRequest.
Helper functions for TLS 1.3 client.
error_t tls13GenerateEarlyTrafficKeys(TlsContext *context)
Compute early traffic keys.
TLS 1.3 key schedule.
bool_t tls13IsPskValid(TlsContext *context)
Check whether an externally established PSK is valid.
Definition: tls13_misc.c:538
error_t tls13ComputePskBinder(TlsContext *context, const void *clientHello, size_t clientHelloLen, size_t truncatedClientHelloLen, const Tls13PskIdentity *identity, uint8_t *binder, size_t binderLen)
Compute PSK binder value.
Definition: tls13_misc.c:86
const uint8_t tls13HelloRetryRequestRandom[32]
Definition: tls13_misc.c:65
Tls13PskBinderList
Definition: tls13_misc.h:247
Tls13PskIdentityList
Definition: tls13_misc.h:225
Tls13PskBinder
Definition: tls13_misc.h:236
Tls13PskIdentity
Definition: tls13_misc.h:214
bool_t tls13IsTicketValid(TlsContext *context)
Check whether a session ticket is valid.
Definition: tls13_ticket.c:51
TLS 1.3 session tickets.
TLS (Transport Layer Security)
@ TLS_STATE_CLOSED
Definition: tls.h:1470
@ TLS_STATE_CLIENT_HELLO_2
Definition: tls.h:1440
@ TLS_STATE_SERVER_HELLO
Definition: tls.h:1444
@ TLS_STATE_EARLY_DATA
Definition: tls.h:1441
@ TLS_STATE_INIT
Definition: tls.h:1438
@ TLS_STATE_CLIENT_HELLO
Definition: tls.h:1439
@ TLS_STATE_CLIENT_CHANGE_CIPHER_SPEC
Definition: tls.h:1457
@ TLS_TRANSPORT_PROTOCOL_STREAM
Definition: tls.h:941
TlsServerHello
Definition: tls.h:1770
@ TLS_TYPE_NONE
Definition: tls.h:1008
@ TLS_TYPE_APPLICATION_DATA
Definition: tls.h:1012
TlsPskIdentity
Definition: tls.h:1678
#define TLS_MAX_RECORD_LENGTH
Definition: tls.h:919
#define TlsContext
Definition: tls.h:36
error_t tlsSendClientHello(TlsContext *context)
Send ClientHello message.
Definition: tls_client.c:81
Handshake message processing (TLS client)
error_t tlsSendChangeCipherSpec(TlsContext *context)
Send ChangeCipherSpec message.
Definition: tls_common.c:273
Handshake message processing (TLS client and server)
error_t tlsInitHandshake(TlsContext *context)
TLS handshake initialization.
Definition: tls_handshake.c:57
TLS handshake.
void tlsChangeState(TlsContext *context, TlsState newState)
Update TLS state.
Definition: tls_misc.c:54
TLS helper functions.
error_t tlsWriteProtocolData(TlsContext *context, const uint8_t *data, size_t length, TlsContentType contentType)
Write protocol data.
Definition: tls_record.c:54
TLS record protocol.
error_t tlsInitTranscriptHash(TlsContext *context)
Initialize handshake message hashing.
Transcript hash calculation.