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