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