dtls13_server_extensions.c
Go to the documentation of this file.
1 /**
2  * @file dtls13_server_extensions.c
3  * @brief Formatting and parsing of extensions (DTLS 1.3 server)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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.6.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TLS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "tls/tls.h"
36 #include "tls/tls_misc.h"
39 #include "debug.h"
40 
41 //Check TLS library configuration
42 #if (TLS_SUPPORT == ENABLED && DTLS_SUPPORT == ENABLED && \
43  TLS_SERVER_SUPPORT == ENABLED && TLS_MAX_VERSION >= TLS_VERSION_1_3)
44 
45 
46 /**
47  * @brief Format Cookie extension
48  * @param[in] context Pointer to the TLS context
49  * @param[in] p Output stream where to write the Cookie extension
50  * @param[out] written Total number of bytes that have been written
51  * @return Error code
52  **/
53 
55  size_t *written)
56 {
57  size_t n;
58  TlsExtension *extension;
60 
61  //Initialize length field
62  n = 0;
63 
64  //When sending a HelloRetryRequest, the server may provide a Cookie
65  //extension to the client
66  if(context->cookieLen > 0)
67  {
68  //Add the Cookie extension
69  extension = (TlsExtension *) p;
70  //Type of the extension
71  extension->type = HTONS(TLS_EXT_COOKIE);
72 
73  //Point to the extension data field
74  cookie = (Tls13Cookie *) extension->value;
75 
76  //When sending the new ClientHello, the client must copy the contents
77  //of the Cookie extension received in the HelloRetryRequest
78  osMemcpy(cookie->value, context->cookie, context->cookieLen);
79 
80  //Set the length of the cookie
81  cookie->length = ntohs(context->cookieLen);
82 
83  //Consider the 2-byte length field that precedes the cookie
84  n = sizeof(Tls13Cookie) + context->cookieLen;
85  //Fix the length of the extension
86  extension->length = htons(n);
87 
88  //Compute the length, in bytes, of the Cookie extension
89  n += sizeof(TlsExtension);
90  }
91 
92  //Total number of bytes that have been written
93  *written = n;
94 
95  //Successful processing
96  return NO_ERROR;
97 }
98 
99 
100 /**
101  * @brief Parse Cookie extension
102  * @param[in] context Pointer to the TLS context
103  * @param[in] cookie Pointer to the Cookie extension
104  * @return Error code
105  **/
106 
108  const Tls13Cookie *cookie)
109 {
110  error_t error;
111  DtlsClientParameters clientParams;
112 
113  //Invalid key share?
114  if(context->wrongKeyShare)
115  {
116  //Cookie extension found?
117  if(cookie != NULL)
118  {
119  //If the server has sent a HelloRetryRequest, the client needs to
120  //restart the handshake with an appropriate group
121  error = ERROR_HANDSHAKE_FAILED;
122  }
123  else
124  {
125  //DTLS servers should perform a cookie exchange whenever a new
126  //handshake is being performed (refer to RFC 9147, section 5.1)
127  if(context->cookieVerifyCallback != NULL &&
128  context->cookieGenerateCallback != NULL)
129  {
130  error = ERROR_WRONG_COOKIE;
131  }
132  else
133  {
134  error = NO_ERROR;
135  }
136  }
137  }
138  else
139  {
140  //Any registered callbacks?
141  if(context->cookieVerifyCallback != NULL &&
142  context->cookieGenerateCallback != NULL)
143  {
144  //Cookie extension found?
145  if(cookie != NULL)
146  {
147  size_t n;
148  const HashAlgo *hashAlgo;
149 
150  //The hash function used by HKDF is the cipher suite hash algorithm
151  hashAlgo = context->cipherSuite.prfHashAlgo;
152 
153  //Make sure the HKDF hash algorithm is valid
154  if(hashAlgo != NULL)
155  {
156  //Retrieve the length of the cookie
157  n = ntohs(cookie->length);
158 
159  //Check the length of the cookie
160  if(n > (hashAlgo->digestSize + 4) && n <= TLS13_MAX_COOKIE_SIZE)
161  {
162  //The internal state is covered by the integrity check
163  osMemset(&clientParams, 0, sizeof(DtlsClientParameters));
164  clientParams.state = cookie->value;
165  clientParams.stateLen = hashAlgo->digestSize + 4;
166 
167  //The server proceeds with the handshake only if the cookie is
168  //valid (refer to RFC 9147, section 5.1)
169  error = context->cookieVerifyCallback(context, &clientParams,
170  cookie->value + clientParams.stateLen,
171  n - clientParams.stateLen, context->cookieParam);
172 
173  //Check status code
174  if(!error)
175  {
176  //The cookie allows the server to offload state to the client
177  error = dtls13ParseCookie(context, cookie->value, n);
178  }
179  }
180  else
181  {
182  //Malformed cookie
183  error = ERROR_WRONG_COOKIE;
184  }
185  }
186  else
187  {
188  //Invalid HKDF hash algorithm
189  error = ERROR_FAILURE;
190  }
191  }
192  else
193  {
194  //The Cookie extension is not present
195  error = ERROR_WRONG_COOKIE;
196  }
197  }
198  else
199  {
200  //The server may be configured not to perform a cookie exchange
201  error = NO_ERROR;
202  }
203  }
204 
205  //Invalid cookie?
206  if(error == ERROR_WRONG_COOKIE)
207  {
208  context->wrongCookie = TRUE;
209  error = NO_ERROR;
210  }
211 
212  //Return status code
213  return error;
214 }
215 
216 
217 /**
218  * @brief Cookie generation
219  * @param[in] context Pointer to the TLS context
220  * @return Error code
221  **/
222 
224 {
225  error_t error;
226  size_t n;
227  DtlsClientParameters clientParams;
228 
229  //Any registered callbacks?
230  if(context->cookieVerifyCallback != NULL &&
231  context->cookieGenerateCallback != NULL)
232  {
233  //Release cookie
234  if(context->cookie != NULL)
235  {
236  tlsFreeMem(context->cookie);
237  }
238 
239  //Set the cookie size limit
240  context->cookieLen = TLS13_MAX_COOKIE_SIZE;
241  //Allocate a memory block to hold the cookie
242  context->cookie = tlsAllocMem(context->cookieLen);
243 
244  //Successful memory allocation?
245  if(context->cookie != NULL)
246  {
247  //Store the cipher suite identifier
248  STORE16BE(context->cipherSuite.identifier, context->cookie);
249 
250  //Store the group identifier
251  if(context->wrongKeyShare)
252  {
253  STORE16BE(context->namedGroup, context->cookie + 2);
254  }
255  else
256  {
257  STORE16BE(0, context->cookie + 2);
258  }
259 
260  //A stateless server-cookie implementation requires the content or hash
261  //of the initial ClientHello (and HelloRetryRequest) to be stored in
262  //the cookie (refer to RFC 9147, section 5.1)
263  osMemcpy(context->cookie + 4, context->clientHelloDigest,
264  context->clientHelloDigestLen);
265 
266  //The internal state is covered by the integrity check
267  osMemset(&clientParams, 0, sizeof(DtlsClientParameters));
268  clientParams.state = context->cookie;
269  clientParams.stateLen = context->clientHelloDigestLen + 4;
270 
271  //Maximum length of the integrity check value
272  n = TLS13_MAX_COOKIE_SIZE - clientParams.stateLen;
273 
274  //The DTLS server should generate cookies in such a way that
275  //they can be verified without retaining any per-client state on
276  //the server
277  error = context->cookieGenerateCallback(context, &clientParams,
278  context->cookie + clientParams.stateLen, &n, context->cookieParam);
279 
280  //Check status code
281  if(!error)
282  {
283  //Save the length of the cookie
284  context->cookieLen = clientParams.stateLen + n;
285  }
286  }
287  else
288  {
289  //Failed to allocate memory
290  error = ERROR_OUT_OF_MEMORY;
291  }
292 
293  //Check status code
294  if(!error)
295  {
296  //The DTLS 1.3 specification changes how cookies are exchanged
297  //compared to DTLS 1.2. DTLS 1.3 reuses the HelloRetryRequest
298  //message and conveys the cookie to the client via an extension
299  context->wrongCookie = TRUE;
300  }
301  }
302  else
303  {
304  //The server may be configured not to perform a cookie exchange
305  error = NO_ERROR;
306  }
307 
308  //Return status code
309  return error;
310 }
311 
312 
313 /**
314  * @brief Cookie parsing
315  * @param[in] context Pointer to the TLS context
316  * @param[in] cookie Pointer to the Cookie extension
317  * @param[in] cookieLen Length of the cookie
318  * @return Error code
319  **/
320 
321 error_t dtls13ParseCookie(TlsContext *context, const uint8_t *cookie,
322  size_t cookieLen)
323 {
324  error_t error;
325  uint16_t cipherSuite;
326  uint16_t namedGroup;
327  const HashAlgo *hashAlgo;
328 
329  //The hash function used by HKDF is the cipher suite hash algorithm
330  hashAlgo = context->cipherSuite.prfHashAlgo;
331 
332  //The cookie allows the server to offload state to the client
334  namedGroup = LOAD16BE(cookie + 2);
335 
336  //The cookie must allow the server to produce the right handshake transcript
337  osMemcpy(context->clientHelloDigest, cookie + 4, hashAlgo->digestSize);
338 
339  //Save the length of Hash(ClientHello1)
340  context->clientHelloDigestLen = hashAlgo->digestSize;
341 
342  //Invalid cipher suite?
343  if(context->cipherSuite.identifier != cipherSuite)
344  return ERROR_HANDSHAKE_FAILED;
345 
346  //Incorrect (EC)DHE share in the initial ClientHello?
347  if(context->state == TLS_STATE_CLIENT_HELLO &&
348  namedGroup != TLS_GROUP_NONE)
349  {
350  //Restore state
351  context->namedGroup = namedGroup;
353  }
354 
355  //Release cookie
356  if(context->cookie != NULL)
357  {
358  tlsFreeMem(context->cookie);
359  }
360 
361  //Save the length of the cookie
362  context->cookieLen = cookieLen;
363  //Allocate a memory block to store the cookie
364  context->cookie = tlsAllocMem(context->cookieLen);
365 
366  //Successful memory allocation?
367  if(context->cookie != NULL)
368  {
369  //Save cookie
370  osMemcpy(context->cookie, cookie, cookieLen);
371 
372  //When the server responds to a ClientHello with a HelloRetryRequest, the
373  //value of ClientHello1 is replaced with a special synthetic handshake
374  //message of handshake type MessageHash containing Hash(ClientHello1)
375  error = tls13DigestClientHello1(context);
376 
377  //Check status code
378  if(!error)
379  {
380  //Update the hash value with the contents of the HelloRetryRequest
381  //message
382  error = tls13DigestHelloRetryRequest(context, namedGroup);
383  }
384  }
385  else
386  {
387  //Failed to allocate memory
388  error = ERROR_OUT_OF_MEMORY;
389  }
390 
391  //Return status code
392  return error;
393 }
394 
395 #endif
error_t dtls13FormatServerCookieExtension(TlsContext *context, uint8_t *p, size_t *written)
Format Cookie extension.
#define tlsAllocMem(size)
Definition: tls.h:889
#define htons(value)
Definition: cpu_endian.h:413
TLS helper functions.
uint16_t cipherSuite
Cipher suite identifier.
Definition: tls.h:2026
Tls13Cookie
Definition: tls13_misc.h:197
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
error_t dtls13GenerateCookie(TlsContext *context)
Cookie generation.
size_t digestSize
Definition: crypto.h:1157
#define TLS13_MAX_COOKIE_SIZE
Definition: tls13_misc.h:113
error_t dtls13ParseClientCookieExtension(TlsContext *context, const Tls13Cookie *cookie)
Parse Cookie extension.
error_t dtls13ParseCookie(TlsContext *context, const uint8_t *cookie, size_t cookieLen)
Cookie parsing.
error_t tls13DigestHelloRetryRequest(TlsContext *context, TlsNamedGroup namedGroup)
Hash HelloRetryRequest in the transcript.
@ ERROR_HANDSHAKE_FAILED
Definition: error.h:234
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_WRONG_COOKIE
Definition: error.h:92
TlsExtension
Definition: tls.h:1716
@ TLS_STATE_CLIENT_HELLO
Definition: tls.h:1559
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:43
@ TLS_GROUP_NONE
Definition: tls.h:1468
Client parameters.
Definition: dtls_misc.h:228
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define STORE16BE(a, p)
Definition: cpu_endian.h:262
@ TLS_EXT_COOKIE
Definition: tls.h:1405
Helper functions for TLS 1.3 server.
#define ntohs(value)
Definition: cpu_endian.h:421
@ TLS_STATE_CLIENT_HELLO_2
Definition: tls.h:1560
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
Formatting and parsing of extensions (DTLS 1.3 server)
TLS (Transport Layer Security)
uint8_t cookie[]
Definition: dtls_misc.h:211
Common interface for hash algorithms.
Definition: crypto.h:1151
void tlsChangeState(TlsContext *context, TlsState newState)
Update TLS state.
Definition: tls_misc.c:54
#define LOAD16BE(p)
Definition: cpu_endian.h:186
#define osMemset(p, value, length)
Definition: os_port.h:138
#define tlsFreeMem(p)
Definition: tls.h:894
error_t tls13DigestClientHello1(TlsContext *context)
Hash ClientHello1 in the transcript when HelloRetryRequest is used.
Definition: tls13_misc.c:844
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
const uint8_t * state
Definition: dtls_misc.h:238