dtls_misc.c
Go to the documentation of this file.
1 /**
2  * @file dtls_misc.c
3  * @brief DTLS (Datagram Transport Layer Security)
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_common.h"
38 #include "tls_misc.h"
39 #include "dtls_misc.h"
40 #include "debug.h"
41 
42 //Check TLS library configuration
43 #if (TLS_SUPPORT == ENABLED && DTLS_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Set the DTLS version to be used
48  * @param[in] context Pointer to the TLS context
49  * @param[in] version DTLS version
50  * @return Error code
51  **/
52 
54 {
55  error_t error;
56 
57  //Initialize status code
59 
60  //Check DTLS version
62  {
63  //DTLS 1.0 is defined as a series of deltas from TLS 1.1
64  if(context->versionMin <= TLS_VERSION_1_1 &&
65  context->versionMax >= TLS_VERSION_1_1)
66  {
67  //Save protocol version
68  context->version = TLS_VERSION_1_1;
69  //The specified DTLS version is acceptable
70  error = NO_ERROR;
71  }
72  }
73  else if(version == DTLS_VERSION_1_2)
74  {
75  //DTLS 1.2 is defined as a series of deltas from TLS 1.2
76  if(context->versionMin <= TLS_VERSION_1_2 &&
77  context->versionMax >= TLS_VERSION_1_2)
78  {
79  //Save protocol version
80  context->version = TLS_VERSION_1_2;
81  //The specified DTLS version is acceptable
82  error = NO_ERROR;
83  }
84  }
85  else
86  {
87  //Unknown DTLS version
88  }
89 
90  //Check whether the DTLS version is supported
91  if(!error)
92  {
93  //Initial handshake?
94  if(context->encryptionEngine.epoch == 0)
95  {
96  //Save the negotiated version
97  context->encryptionEngine.version = context->version;
98  }
99  }
100 
101  //Return status code
102  return error;
103 }
104 
105 
106 /**
107  * @brief Translate TLS version into DTLS version
108  * @param[in] version TLS version
109  * @return DTLS version
110  **/
111 
112 uint16_t dtlsTranslateVersion(uint16_t version)
113 {
114  //Check current version
115  if(version == TLS_VERSION_1_2)
116  {
117  //DTLS 1.2 is defined as a series of deltas from TLS 1.2
119  }
120  else if(version == TLS_VERSION_1_3)
121  {
122  //DTLS 1.3 is defined as a series of deltas from TLS 1.3
124  }
125  else
126  {
127  //DTLS 1.0 is defined as a series of deltas from TLS 1.1
129  }
130 
131  //Return the version of the DTLS protocol
132  return version;
133 }
134 
135 
136 /**
137  * @brief Format Cookie field
138  * @param[in] context Pointer to the TLS context
139  * @param[in] p Output stream where to write the Cookie field
140  * @param[out] written Total number of bytes that have been written
141  * @return Error code
142  **/
143 
144 error_t dtlsFormatCookie(TlsContext *context, uint8_t *p, size_t *written)
145 {
147 
148  //Add Cookie field
149  cookie = (DtlsCookie *) p;
150 
151  //When a HelloVerifyRequest message has been received by the client, it
152  //must retransmit the ClientHello with the cookie added
153  if(context->cookieLen > 0)
154  {
155  //Copy cookie
156  osMemcpy(cookie->value, context->cookie, context->cookieLen);
157  }
158 
159  //Set the length of the cookie
160  cookie->length = (uint8_t) context->cookieLen;
161 
162  //Total number of bytes that have been written
163  *written = sizeof(DtlsCookie) + cookie->length;
164 
165  //Successful processing
166  return NO_ERROR;
167 }
168 
169 
170 /**
171  * @brief Cookie verification
172  * @param[in] context Pointer to the TLS context
173  * @param[in] cookie Pointer to the client's cookie
174  * @param[in] clientParams Client's parameters
175  * @return Error code
176  **/
177 
179  const DtlsClientParameters *clientParams)
180 {
181  error_t error;
182 
183  //Any registered callbacks?
184  if(context->cookieVerifyCallback != NULL &&
185  context->cookieGenerateCallback != NULL)
186  {
187  //Verify that the cookie is valid
188  error = context->cookieVerifyCallback(context, clientParams,
189  cookie->value, cookie->length, context->cookieParam);
190 
191  //Invalid cookie?
192  if(error == ERROR_WRONG_COOKIE)
193  {
194  //Set the cookie size limit (32 or 255 bytes depending on DTLS version)
195  context->cookieLen = DTLS_MAX_COOKIE_SIZE;
196 
197  //Allocate a memory block to hold the cookie
198  if(context->cookie == NULL)
199  {
200  context->cookie = tlsAllocMem(context->cookieLen);
201  }
202 
203  //Successful memory allocation?
204  if(context->cookie != NULL)
205  {
206  //The DTLS server should generate cookies in such a way that they can
207  //be verified without retaining any per-client state on the server
208  error = context->cookieGenerateCallback(context, clientParams,
209  context->cookie, &context->cookieLen, context->cookieParam);
210  }
211  else
212  {
213  //Failed to allocate memory
214  error = ERROR_OUT_OF_MEMORY;
215  }
216 
217  //Check status code
218  if(!error)
219  {
220  //Send a HelloVerifyRequest message to the DTLS client
222  }
223  }
224  }
225  else
226  {
227  //The server may be configured not to perform a cookie exchange
228  error = NO_ERROR;
229  }
230 
231  //Return status code
232  return error;
233 }
234 
235 
236 /**
237  * @brief Send HelloVerifyRequest message
238  *
239  * When the client sends its ClientHello message to the server, the server may
240  * respond with a HelloVerifyRequest message. This message contains a stateless
241  * cookie
242  *
243  * @param[in] context Pointer to the TLS context
244  * @return Error code
245  **/
246 
248 {
249  error_t error;
250  size_t length;
252 
253  //Point to the buffer where to format the message
254  message = (DtlsHelloVerifyRequest *) (context->txBuffer + context->txBufferLen);
255 
256  //Format HelloVerifyRequest message
257  error = dtlsFormatHelloVerifyRequest(context, message, &length);
258 
259  //Check status code
260  if(!error)
261  {
262  //Debug message
263  TRACE_INFO("Sending HelloVerifyRequest message (%" PRIuSIZE " bytes)...\r\n", length);
265 
266  //Send handshake message
267  error = tlsSendHandshakeMessage(context, message, length,
269  }
270 
271  //Check status code
272  if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
273  {
274  //The client must retransmit the ClientHello with the cookie added
276  }
277 
278  //Return status code
279  return error;
280 }
281 
282 
283 /**
284  * @brief Format HelloVerifyRequest message
285  * @param[in] context Pointer to the TLS context
286  * @param[out] message Buffer where to format the HelloVerifyRequest message
287  * @param[out] length Length of the resulting HelloVerifyRequest message
288  * @return Error code
289  **/
290 
293 {
294  //In order to avoid the requirement to do version negotiation in the initial
295  //handshake, DTLS 1.2 server implementations should use DTLS version 1.0
296  //regardless of the version of TLS that is expected to be negotiated
297  message->serverVersion = HTONS(DTLS_VERSION_1_0);
298 
299  //Valid cookie?
300  if(context->cookieLen > 0)
301  {
302  //Copy cookie
303  osMemcpy(message->cookie, context->cookie, context->cookieLen);
304  }
305 
306  //Set the length of the cookie
307  message->cookieLength = (uint8_t) context->cookieLen;
308 
309  //Length of the handshake message
310  *length = sizeof(DtlsHelloVerifyRequest) + context->cookieLen;
311 
312  //Successful processing
313  return NO_ERROR;
314 }
315 
316 
317 /**
318  * @brief Parse HelloVerifyRequest message
319  *
320  * When the client sends its ClientHello message to the server,
321  * the server may respond with a HelloVerifyRequest message
322  *
323  * @param[in] context Pointer to the TLS context
324  * @param[in] message Incoming HelloVerifyRequest message to parse
325  * @param[in] length Message length
326  * @return Error code
327  **/
328 
330  const DtlsHelloVerifyRequest *message, size_t length)
331 {
332  //Debug message
333  TRACE_INFO("HelloVerifyRequest message received (%" PRIuSIZE " bytes)...\r\n", length);
335 
336  //DTLS protocol?
337  if(context->transportProtocol == TLS_TRANSPORT_PROTOCOL_DATAGRAM)
338  {
339  //Check the length of the HelloVerifyRequest message
340  if(length < sizeof(DtlsHelloVerifyRequest))
341  return ERROR_DECODING_FAILED;
342 
343  //Check current state
344  if(context->state != TLS_STATE_SERVER_HELLO)
346 
347  //Remaining bytes to process
348  length -= sizeof(DtlsHelloVerifyRequest);
349 
350  //If the amount of data in the message does not precisely match the format
351  //of the HelloVerifyRequest message, then send a fatal alert
352  if(message->cookieLength != length)
353  return ERROR_DECODING_FAILED;
354 
355  //Sanity check
356  if(context->cookie != NULL)
357  {
358  //Release memory
359  tlsFreeMem(context->cookie);
360  context->cookie = NULL;
361  context->cookieLen = 0;
362  }
363 
364  //Valid cookie received?
365  if(message->cookieLength > 0)
366  {
367  //Allocate a memory block to store the cookie
368  context->cookie = tlsAllocMem(message->cookieLength);
369  //Failed to allocate memory?
370  if(context->cookie == NULL)
371  return ERROR_OUT_OF_MEMORY;
372 
373  //Save cookie
374  osMemcpy(context->cookie, message->cookie, message->cookieLength);
375  }
376 
377  //Save the length of the cookie
378  context->cookieLen = message->cookieLength;
379 
380  //The client sends a second ClientHello message
382 
383  //Successful processing
384  return NO_ERROR;
385  }
386  else
387  {
388  //Report an error
390  }
391 }
392 
393 
394 /**
395  * @brief Parse SupportedVersions extension
396  * @param[in] context Pointer to the TLS context
397  * @param[in] supportedVersionList Pointer to the SupportedVersions extension
398  * @return Error code
399  **/
400 
402  const DtlsSupportedVersionList *supportedVersionList)
403 {
404  error_t error;
405  uint_t i;
406  uint_t j;
407  uint_t n;
408 
409  //Supported DTLS versions
410  const uint16_t supportedVersions[] =
411  {
414  };
415 
416  //Initialize status code
418 
419  //Retrieve the number of items in the list
420  n = supportedVersionList->length / sizeof(uint16_t);
421 
422  //Loop through the list of DTLS versions supported by the server
423  for(i = 0; i < arraysize(supportedVersions) && error; i++)
424  {
425  //The extension contains a list of DTLS versions supported by the client
426  for(j = 0; j < n && error; j++)
427  {
428  //Servers must only select a version of DTLS present in that extension
429  //and must ignore any unknown versions
430  if(ntohs(supportedVersionList->value[j]) == supportedVersions[i])
431  {
432  //Set the DTLS version to be used
433  error = dtlsSelectVersion(context, supportedVersions[i]);
434  }
435  }
436  }
437 
438  //Return status code
439  return error;
440 }
441 
442 
443 /**
444  * @brief Initialize sliding window
445  * @param[in] context Pointer to the TLS context
446  **/
447 
449 {
450 #if (DTLS_REPLAY_DETECTION_SUPPORT == ENABLED)
451  uint_t i;
452 
453  //Clear the bitmap window
454  for(i = 0; i < (DTLS_REPLAY_WINDOW_SIZE + 31) / 32; i++)
455  {
456  context->replayWindow[i] = 0;
457  }
458 #endif
459 }
460 
461 
462 /**
463  * @brief Perform replay detection
464  * @param[in] context Pointer to the TLS context
465  * @param[in] seqNum Sequence number of the received DTLS record
466  * @return Error code
467  **/
468 
470 {
471  error_t error;
472 
473 #if (DTLS_REPLAY_DETECTION_SUPPORT == ENABLED)
474  //Check whether anti-replay mechanism is enabled
475  if(context->replayDetectionEnabled)
476  {
477  uint_t j;
478  uint_t k;
479  uint64_t n;
480  uint64_t right;
481 
482  //Get the sequence number of the received DTLS record
483  n = LOAD48BE(seqNum);
484 
485  //The right edge of the window represents the highest validated sequence
486  //number value received on this session
487  right = LOAD48BE(&context->decryptionEngine.dtlsSeqNum);
488 
489  //Check sequence number
490  if(n <= right)
491  {
492  //Calculate the position relative to the right edge of the window
493  n = right - n;
494 
495  //Check whether the sequence number falls within the window
497  {
498  //Records falling within the window are checked against a list of
499  //received packets within the window
500  j = (uint_t) (n / 32);
501  k = (uint_t) (n % 32);
502 
503  //Duplicate record are rejected through the use of a sliding
504  //receive window
505  if(context->replayWindow[j] & (1U << k))
506  {
507  //The received record is a duplicate
509  }
510  else
511  {
512  //If the received record falls within the window and is new,
513  //then the receiver proceeds to MAC verification
514  error = NO_ERROR;
515  }
516 
517  }
518  else
519  {
520  //Records that contain sequence numbers lower than the left edge
521  //of the window are rejected
523  }
524  }
525  else
526  {
527  //If the packet is to the right of the window, then the receiver
528  //proceeds to MAC verification
529  error = NO_ERROR;
530  }
531  }
532  else
533 #endif
534  {
535  //Anti-replay mechanism is disabled
536  error = NO_ERROR;
537  }
538 
539  //Return status code
540  return error;
541 }
542 
543 
544 /**
545  * @brief Update sliding window
546  * @param[in] context Pointer to the TLS context
547  * @param[in] seqNum Sequence number of the received DTLS record
548  **/
549 
551 {
552  uint64_t n;
553  uint64_t right;
554 
555  //Get the sequence number of the received DTLS record
556  n = LOAD48BE(seqNum);
557 
558  //The right edge of the window represents the highest validated sequence
559  //number value received on this session
560  right = LOAD48BE(&context->decryptionEngine.dtlsSeqNum);
561 
562  //Check sequence number
563  if(n <= right)
564  {
565 #if (DTLS_REPLAY_DETECTION_SUPPORT == ENABLED)
566  uint_t j;
567  uint_t k;
568 
569  //Calculate the position relative to the right edge of the window
570  n = right - n;
571 
572  //Check whether the sequence number falls within the window
574  {
575  j = (uint_t) (n / 32);
576  k = (uint_t) (n % 32);
577 
578  //Set the corresponding bit in the bitmap window
579  context->replayWindow[j] |= 1U << k;
580  }
581 #endif
582  }
583  else
584  {
585 #if (DTLS_REPLAY_DETECTION_SUPPORT == ENABLED)
586  uint_t i;
587  uint_t j;
588  uint_t k;
589 
590  //Calculate the position relative to the right edge of the window
591  n -= right;
592 
593  //Check resulting value
595  {
596  j = (uint_t) (n / 32);
597  k = (uint_t) (n % 32);
598 
599  //First, shift words
600  if(j > 0)
601  {
602  //Shift the most significant words of the window
603  for(i = (DTLS_REPLAY_WINDOW_SIZE - 1) / 32; i >= j; i--)
604  {
605  context->replayWindow[i] = context->replayWindow[i - j];
606  }
607 
608  //Fill the least significant words with zeroes
609  for(i = 0; i < j; i++)
610  {
611  context->replayWindow[i] = 0;
612  }
613  }
614 
615  //Then shift bits
616  if(k > 0)
617  {
618  //Shift the most significant words of the window
619  for(i = (DTLS_REPLAY_WINDOW_SIZE - 1) / 32; i >= 1; i--)
620  {
621  context->replayWindow[i] = (context->replayWindow[i] << k) |
622  (context->replayWindow[i - 1] >> (32 - k));
623  }
624 
625  //Shift the least significant word
626  context->replayWindow[0] <<= k;
627  }
628  }
629  else
630  {
631  //Clear the bitmap window
632  for(i = 0; i < (DTLS_REPLAY_WINDOW_SIZE + 31) / 32; i++)
633  {
634  context->replayWindow[i] = 0;
635  }
636  }
637 
638  //Set the corresponding bit in the bitmap window
639  context->replayWindow[0] |= 1;
640 #endif
641 
642  //Save the highest sequence number value received on this session
643  context->decryptionEngine.dtlsSeqNum = *seqNum;
644  }
645 }
646 
647 #endif
uint8_t message[]
Definition: chap.h:154
uint8_t version
Definition: coap_common.h:177
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
#define HTONS(value)
Definition: cpu_endian.h:410
#define ntohs(value)
Definition: cpu_endian.h:421
#define LOAD48BE(p)
Definition: cpu_endian.h:226
Debugging facilities.
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
void dtlsUpdateReplayWindow(TlsContext *context, DtlsSequenceNumber *seqNum)
Update sliding window.
Definition: dtls_misc.c:550
error_t dtlsSelectVersion(TlsContext *context, uint16_t version)
Set the DTLS version to be used.
Definition: dtls_misc.c:53
uint16_t dtlsTranslateVersion(uint16_t version)
Translate TLS version into DTLS version.
Definition: dtls_misc.c:112
error_t dtlsParseClientSupportedVersionsExtension(TlsContext *context, const DtlsSupportedVersionList *supportedVersionList)
Parse SupportedVersions extension.
Definition: dtls_misc.c:401
error_t dtlsParseHelloVerifyRequest(TlsContext *context, const DtlsHelloVerifyRequest *message, size_t length)
Parse HelloVerifyRequest message.
Definition: dtls_misc.c:329
void dtlsInitReplayWindow(TlsContext *context)
Initialize sliding window.
Definition: dtls_misc.c:448
error_t dtlsSendHelloVerifyRequest(TlsContext *context)
Send HelloVerifyRequest message.
Definition: dtls_misc.c:247
error_t dtlsCheckReplayWindow(TlsContext *context, DtlsSequenceNumber *seqNum)
Perform replay detection.
Definition: dtls_misc.c:469
error_t dtlsVerifyCookie(TlsContext *context, const DtlsCookie *cookie, const DtlsClientParameters *clientParams)
Cookie verification.
Definition: dtls_misc.c:178
error_t dtlsFormatHelloVerifyRequest(TlsContext *context, DtlsHelloVerifyRequest *message, size_t *length)
Format HelloVerifyRequest message.
Definition: dtls_misc.c:291
error_t dtlsFormatCookie(TlsContext *context, uint8_t *p, size_t *written)
Format Cookie field.
Definition: dtls_misc.c:144
DTLS (Datagram Transport Layer Security)
uint8_t cookie[]
Definition: dtls_misc.h:206
DtlsCookie
Definition: dtls_misc.h:154
#define DTLS_VERSION_1_2
Definition: dtls_misc.h:36
#define DTLS_VERSION_1_3
Definition: dtls_misc.h:37
DtlsHelloVerifyRequest
Definition: dtls_misc.h:207
#define DTLS_MAX_COOKIE_SIZE
Definition: dtls_misc.h:76
DtlsSequenceNumber
Definition: dtls_misc.h:143
DtlsSupportedVersionList
Definition: dtls_misc.h:165
#define DTLS_REPLAY_WINDOW_SIZE
Definition: dtls_misc.h:69
#define DTLS_VERSION_1_0
Definition: dtls_misc.h:35
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_SEQUENCE_NUMBER
Definition: error.h:109
@ ERROR_WOULD_BLOCK
Definition: error.h:96
@ ERROR_VERSION_NOT_SUPPORTED
Definition: error.h:67
@ ERROR_TIMEOUT
Definition: error.h:95
@ ERROR_WRONG_COOKIE
Definition: error.h:92
@ ERROR_DECODING_FAILED
Definition: error.h:240
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_UNEXPECTED_MESSAGE
Definition: error.h:194
uint8_t p
Definition: ndp.h:300
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define arraysize(a)
Definition: os_port.h:71
Client parameters.
Definition: dtls_misc.h:223
uint8_t length
Definition: tcp.h:368
uint32_t seqNum
Definition: tcp.h:341
TLS (Transport Layer Security)
#define tlsAllocMem(size)
Definition: tls.h:846
@ TLS_STATE_HELLO_VERIFY_REQUEST
Definition: tls.h:1442
@ TLS_STATE_SERVER_HELLO
Definition: tls.h:1444
@ TLS_STATE_CLIENT_HELLO
Definition: tls.h:1439
@ TLS_TRANSPORT_PROTOCOL_DATAGRAM
Definition: tls.h:942
#define tlsFreeMem(p)
Definition: tls.h:851
#define TLS_VERSION_1_1
Definition: tls.h:95
#define TLS_VERSION_1_3
Definition: tls.h:97
#define TlsContext
Definition: tls.h:36
@ TLS_TYPE_HELLO_VERIFY_REQUEST
Definition: tls.h:1028
#define TLS_VERSION_1_2
Definition: tls.h:96
Handshake message processing (TLS client and server)
error_t tlsSendHandshakeMessage(TlsContext *context, const void *data, size_t length, TlsMessageType type)
Send handshake message.
TLS handshake.
void tlsChangeState(TlsContext *context, TlsState newState)
Update TLS state.
Definition: tls_misc.c:54
TLS helper functions.