nts_client_misc.c
Go to the documentation of this file.
1 /**
2  * @file nts_client_misc.c
3  * @brief Helper functions for NTS client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP 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.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NTS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "nts/nts_client.h"
37 #include "nts/nts_client_misc.h"
38 #include "nts/nts_debug.h"
39 #include "ntp/ntp_common.h"
40 #include "ntp/ntp_debug.h"
42 #include "aead/aead_algorithms.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (NTS_CLIENT_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Update NTS client state
51  * @param[in] context Pointer to the NTS client context
52  * @param[in] newState New state to switch to
53  **/
54 
56  NtsClientState newState)
57 {
58  //Update HTTP connection state
59  context->state = newState;
60 
61  //Save current time
62  context->timestamp = osGetSystemTime();
63 }
64 
65 
66 /**
67  * @brief Open NTS-KE connection
68  * @param[in] context Pointer to the NTS client context
69  * @return Error code
70  **/
71 
73 {
74  error_t error;
75 
76  //Invalid callback functions?
77  if(context->tlsInitCallback == NULL || context->randCallback == NULL)
78  return ERROR_OPEN_FAILED;
79 
80  //Open a TCP socket
81  context->ntsKeSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
82  //Failed to open socket?
83  if(context->ntsKeSocket == NULL)
84  return ERROR_OPEN_FAILED;
85 
86  //Associate the socket with the relevant interface
87  error = socketBindToInterface(context->ntsKeSocket, context->interface);
88  //Any error to report?
89  if(error)
90  return error;
91 
92  //Set timeout
93  error = socketSetTimeout(context->ntsKeSocket, context->timeout);
94  //Any error to report?
95  if(error)
96  return error;
97 
98  //Allocate TLS context
99  context->tlsContext = tlsInit();
100  //Failed to allocate TLS context?
101  if(context->tlsContext == NULL)
102  return ERROR_OPEN_FAILED;
103 
104  //Implementations must not negotiate TLS versions earlier than 1.3 (refer to
105  //RFC 8915, section 3)
106  error = tlsSetVersion(context->tlsContext, TLS_VERSION_1_3, TLS_VERSION_1_3);
107  //Any error to report?
108  if(error)
109  return error;
110 
111  //Select client operation mode
112  error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT);
113  //Any error to report?
114  if(error)
115  return error;
116 
117  //Bind TLS to the relevant socket
118  error = tlsSetSocket(context->tlsContext, context->ntsKeSocket);
119  //Any error to report?
120  if(error)
121  return error;
122 
123  //Set TX and RX buffer size
124  error = tlsSetBufferSize(context->tlsContext,
126  //Any error to report?
127  if(error)
128  return error;
129 
130  //The two endpoints carry out a TLS handshake, with the client offering (via
131  //an ALPN extension), and the server accepting, an application-layer protocol
132  //of "ntske/1" (refer to RFC 8915, section 4)
133  error = tlsSetAlpnProtocolList(context->tlsContext, "ntske/1");
134  //Any error to report?
135  if(error)
136  return error;
137 
138  //Restore TLS session
139  error = tlsRestoreSessionState(context->tlsContext, &context->tlsSession);
140  //Any error to report?
141  if(error)
142  return error;
143 
144  //Perform TLS related initialization
145  error = context->tlsInitCallback(context, context->tlsContext);
146  //Any error to report?
147  if(error)
148  return error;
149 
150  //Successful processing
151  return NO_ERROR;
152 }
153 
154 /**
155  * @brief Establish NTS-KE connection
156  * @param[in] context Pointer to the NTS client context
157  * @return Error code
158  **/
159 
161 {
162  error_t error;
163 
164  //The client connects to an NTS-KE server on the NTS TCP port
165  error = socketConnect(context->ntsKeSocket, &context->ntsKeServerIpAddr,
166  context->ntsKeServerPort);
167 
168  //Check status code
169  if(!error)
170  {
171  //Then, the two parties perform a TLS handshake
172  error = tlsConnect(context->tlsContext);
173  }
174 
175  //Return status code
176  return error;
177 }
178 
179 
180 /**
181  * @brief Format NTS-KE request
182  * @param[in] context Pointer to the NTS client context
183  * @return Error code
184  **/
185 
187 {
188  size_t length;
189  NtsKeRecord *record;
190 
191  //Total length of the NTS-KE request
192  length = 0;
193 
194  //The request each shall include exactly one NTS Next Protocol Negotiation
195  //record (refer to RFC 8915, section 4)
196  record = (NtsKeRecord *) (context->buffer + length);
197 
198  //Its body consists of a sequence of 16-bit unsigned integers in network
199  //byte order
201  record->bodyLength = HTONS(sizeof(uint16_t));
202  record->body[0] = MSB(NTS_PROTOCOL_ID_NTPV4);
203  record->body[1] = LSB(NTS_PROTOCOL_ID_NTPV4);
204 
205  //Adjust the length of the request
206  length += sizeof(NtsKeRecord) + ntohs(record->bodyLength);
207 
208  //If the NTS Next Protocol Negotiation record offers Protocol ID 0 (for
209  //NTPv4), then the AEAD Algorithm Negotiation record must be included
210  //exactly once
211  record = (NtsKeRecord *) (context->buffer + length);
212 
213  //Its body consists of a sequence of 16-bit unsigned integers in network
214  //byte order
216  record->bodyLength = HTONS(sizeof(uint16_t));
217  record->body[0] = MSB(AEAD_AES_SIV_CMAC_256);
218  record->body[1] = LSB(AEAD_AES_SIV_CMAC_256);
219 
220  //Adjust the length of the request
221  length += sizeof(NtsKeRecord) + ntohs(record->bodyLength);
222 
223  //The sequence shall be terminated by a End of Message record
224  record = (NtsKeRecord *) (context->buffer + length);
225 
226  //The End of Message record has a Record Type number of 0 and a zero-length
227  //body (refer to RFC 8915, section 4.1.1)
229  record->bodyLength = HTONS(0);
230 
231  //Adjust the length of the request
232  length += sizeof(NtsKeRecord) + ntohs(record->bodyLength);
233 
234  //Save the length of the NTS-KE request
235  context->bufferLen = length;
236  context->bufferPos = 0;
237 
238  //Debug message
239  TRACE_INFO("Sending NTS-KE request (%" PRIuSIZE " bytes)...\r\n", length);
240  //Dump NTS-KE records for debugging purpose
241  ntsDumpNtsKeRecords(context->buffer, length);
242 
243  //Sucessful processing
244  return NO_ERROR;
245 }
246 
247 
248 /**
249  * @brief Send NTS-KE request
250  * @param[in] context Pointer to the NTS client context
251  * @return Error code
252  **/
253 
255 {
256  error_t error;
257  size_t n;
258 
259  //Any remaining data to be sent?
260  if(context->bufferPos < context->bufferLen)
261  {
262  //Send more data
263  error = tlsWrite(context->tlsContext, context->buffer + context->bufferPos,
264  context->bufferLen - context->bufferPos, &n, 0);
265 
266  //Check status code
267  if(error == NO_ERROR || error == ERROR_TIMEOUT)
268  {
269  //Advance data pointer
270  context->bufferPos += n;
271  }
272  }
273  else
274  {
275  //The request has been successfully transmitted
276  error = NO_ERROR;
277 
278  //Flush the receive buffer
279  context->bufferLen = 0;
280  context->bufferPos = 0;
281 
282  //The client must discard all old cookies and parameters
283  context->cookieLen = 0;
284  context->ntsNextProtoNegoRecordReceived = FALSE;
285  context->aeadAlgoNegoRecordReceived = FALSE;
286 
287  //If no NTPv4 Server Negotiation record is sent, the client shall interpret
288  //this as a directive to associate with an NTPv4 server at the same IP
289  //address as the NTS-KE server (refer to RFC 8915, section 4.1.7)
290  ipAddrToString(&context->ntsKeServerIpAddr, context->ntpServerName);
291 
292  //If no NTPv4 Port Negotiation record is sent, the client shall assume a
293  //default of 123 (refer to RFC 8915, section 4.1.8)
294  context->ntpServerPort = NTP_PORT;
295 
296  //Debug message
297  TRACE_INFO("Receiving NTS-KE response...\r\n");
298 
299  //Wait for server's response
301  }
302 
303  //Return status code
304  return error;
305 }
306 
307 
308 /**
309  * @brief Receive NTS-KE response
310  * @param[in] context Pointer to the NTS client context
311  * @return Error code
312  **/
313 
315 {
316  error_t error;
317  size_t n;
318  uint16_t type;
319  NtsKeRecord *record;
320 
321  //The server's response each shall consist of a sequence of records
322  if(context->bufferPos < sizeof(NtsKeRecord))
323  {
324  //Read record header
325  error = tlsRead(context->tlsContext, context->buffer + context->bufferPos,
326  sizeof(NtsKeRecord) - context->bufferPos, &n, 0);
327 
328  //Check status code
329  if(!error)
330  {
331  //Advance data pointer
332  context->bufferPos += n;
333 
334  //Valid record header?
335  if(context->bufferPos >= sizeof(NtsKeRecord))
336  {
337  //Point to the received record header
338  record = (NtsKeRecord *) context->buffer;
339 
340  //Get the length of the record body
341  n = ntohs(record->bodyLength);
342 
343  //Clients may enforce length limits on responses
344  if((sizeof(NtsKeRecord) + n) <= NTS_CLIENT_BUFFER_SIZE)
345  {
346  //Save the total length of the record
347  context->bufferLen = sizeof(NtsKeRecord) + n;
348  }
349  else
350  {
351  //The record is malformed
352  error = ERROR_INVALID_SYNTAX;
353  }
354  }
355  }
356  }
357  else if(context->bufferPos < context->bufferLen)
358  {
359  //Read record body
360  error = tlsRead(context->tlsContext, context->buffer + context->bufferPos,
361  context->bufferLen - context->bufferPos, &n, 0);
362 
363  //Check status code
364  if(!error)
365  {
366  //Advance data pointer
367  context->bufferPos += n;
368  }
369  }
370  else
371  {
372  //Debug message
373  TRACE_DEBUG("NTS-KE record received (%" PRIuSIZE " bytes)...\r\n",
374  context->bufferLen);
375 
376  //Point to the received record
377  record = (NtsKeRecord *) context->buffer;
378 
379  //Get record type
380  type = ntohs(record->type) & NTS_KE_RECORD_TYPE_MASK;
381  //Get body length
382  n = ntohs(record->bodyLength);
383 
384  //Dump NTS-KE record for debugging purpose
385  ntsDumpNtsKeRecord(record, context->bufferLen);
386 
387  //Check record type
389  {
390  //Process End of Message record
391  error = ntsClientParseEndOfMessageRecord(context, record->body, n);
392  }
394  {
395  //Process NTS Next Protocol Negotiation record
396  error = ntsClientParseNtsNextProtoNegoRecord(context, record->body, n);
397  }
398  else if(type == NTS_KE_RECORD_TYPE_ERROR)
399  {
400  //Process Error record
401  error = ntsClientParseErrorRecord(context, record->body, n);
402  }
403  else if(type == NTS_KE_RECORD_TYPE_WARNING)
404  {
405  //Process Warning record
406  error = ntsClientParseWarningRecord(context, record->body, n);
407  }
409  {
410  //Process AEAD Algorithm Negotiation record
411  error = ntsClientParseAeadAlgoNegoRecord(context, record->body, n);
412  }
414  {
415  //Process New Cookie for NTPv4 record
416  error = ntsClientParseNewCookieForNtpv4Record(context, record->body, n);
417  }
419  {
420  //Process NTPv4 Server Negotiation record
421  error = ntsClientParseNtpv4ServerRecord(context, record->body, n);
422  }
424  {
425  //Process NTPv4 Port Negotiation record
426  error = ntsClientParseNtpv4PortRecord(context, record->body, n);
427  }
428  else
429  {
430  //Discard unknown records
431  error = NO_ERROR;
432  }
433 
434  //Flush the receive buffer
435  context->bufferLen = 0;
436  context->bufferPos = 0;
437  }
438 
439  //Return status code
440  return error;
441 }
442 
443 
444 /**
445  * @brief Parse End of Message record
446  * @param[in] context Pointer to the NTS client context
447  * @param[in] body Pointer to the record body
448  * @param[in] length Length of the record body, in bytes
449  * @return Error code
450  **/
451 
453  const uint8_t *body, size_t length)
454 {
455  error_t error;
456  uint8_t contextValue[5];
457 
458  //The NTS Next Protocol Negotiation record must be included exactly once
459  if(!context->ntsNextProtoNegoRecordReceived)
460  return ERROR_INVALID_SYNTAX;
461 
462  //If the NTS Next Protocol Negotiation record offers Protocol ID 0 (for
463  //NTPv4), then the AEAD Algorithm Negotiation record record must be included
464  //exactly once
465  if(!context->aeadAlgoNegoRecordReceived)
466  return ERROR_INVALID_SYNTAX;
467 
468  //Servers must send at least one New Cookie for NTPv4 record (refer to
469  //RFC 8915, section 4.1.6)
470  if(context->cookieLen == 0)
471  return ERROR_WRONG_COOKIE;
472 
473  //The per-association context value shall consist of the five octets
474  contextValue[0] = MSB(NTS_PROTOCOL_ID_NTPV4);
475  contextValue[1] = LSB(NTS_PROTOCOL_ID_NTPV4);
476  contextValue[2] = MSB(AEAD_AES_SIV_CMAC_256);
477  contextValue[3] = LSB(AEAD_AES_SIV_CMAC_256);
478 
479  //The final octet shall be 0x00 for the C2S key
480  contextValue[4] = 0x00;
481 
482  //Extract the client-to-server (C2S) key
483  error = tlsExportKeyingMaterial(context->tlsContext,
484  "EXPORTER-network-time-security", TRUE, contextValue,
485  sizeof(contextValue), context->c2sKey, 32);
486  //Failed to extract C2S key?
487  if(error)
488  return error;
489 
490  //The final octet shall be 0x01 for the S2C key
491  contextValue[4] = 0x01;
492 
493  //Extract the server-to-client (S2C) key
494  error = tlsExportKeyingMaterial(context->tlsContext,
495  "EXPORTER-network-time-security", TRUE, contextValue,
496  sizeof(contextValue), context->s2cKey, 32);
497  //Failed to extract S2C key?
498  if(error)
499  return error;
500 
501  //Save TLS session
502  error = tlsSaveSessionState(context->tlsContext, &context->tlsSession);
503  //Any error to report?
504  if(error)
505  return error;
506 
507  //After sending their respective request and response, the client and server
508  //shall send TLS "close_notify" alerts (refer to RFC 8915, section 4)
510 
511  //Successful processing
512  return NO_ERROR;
513 }
514 
515 
516 /**
517  * @brief Parse NTS Next Protocol Negotiation record
518  * @param[in] context Pointer to the NTS client context
519  * @param[in] body Pointer to the record body
520  * @param[in] length Length of the record body, in bytes
521  * @return Error code
522  **/
523 
525  const uint8_t *body, size_t length)
526 {
527  error_t error;
528 
529  //The NTS Next Protocol Negotiation record must be included exactly once
530  if(context->ntsNextProtoNegoRecordReceived)
531  {
532  //The response includes a duplicate record
533  error = ERROR_INVALID_SYNTAX;
534  }
535  else
536  {
537  //The response includes a NTS Next Protocol Negotiation record
538  context->ntsNextProtoNegoRecordReceived = TRUE;
539 
540  //Protocol IDs listed in the server's response must comprise a subset of
541  //those listed in the request (refer to RFC 8915, section 4.1.2)
542  if(length == sizeof(uint16_t) &&
543  body[0] == MSB(NTS_PROTOCOL_ID_NTPV4) &&
545  {
546  error = NO_ERROR;
547  }
548  else
549  {
550  error = ERROR_INVALID_PROTOCOL;
551  }
552  }
553 
554  //Return status code
555  return error;
556 }
557 
558 
559 /**
560  * @brief Parse Error record
561  * @param[in] context Pointer to the NTS client context
562  * @param[in] body Pointer to the record body
563  * @param[in] length Length of the record body, in bytes
564  * @return Error code
565  **/
566 
568  const uint8_t *body, size_t length)
569 {
570  //If clients receive a server response that includes an Error record, they
571  //must discard any key material negotiated during the initial TLS exchange
572  //and must not proceed to the Next Protocol (refer to RFC 8915, section 4.1.3)
574 }
575 
576 
577 /**
578  * @brief Parse Warning record
579  * @param[in] context Pointer to the NTS client context
580  * @param[in] body Pointer to the record body
581  * @param[in] length Length of the record body, in bytes
582  * @return Error code
583  **/
584 
586  const uint8_t *body, size_t length)
587 {
588  //If clients receive a server response that includes a Warning record, they
589  //may discard any negotiated key material and abort without proceeding to
590  //the Next Protocol
591  return NO_ERROR;
592 }
593 
594 
595 /**
596  * @brief Parse AEAD Algorithm Negotiation record
597  * @param[in] context Pointer to the NTS client context
598  * @param[in] body Pointer to the record body
599  * @param[in] length Length of the record body, in bytes
600  * @return Error code
601  **/
602 
604  const uint8_t *body, size_t length)
605 {
606  error_t error;
607 
608  //If the NTS Next Protocol Negotiation record offers Protocol ID 0 (for
609  //NTPv4), then this record must be included exactly once
610  if(context->aeadAlgoNegoRecordReceived)
611  {
612  //The response includes a duplicate record
613  error = ERROR_INVALID_SYNTAX;
614  }
615  else
616  {
617  //The response includes an AEAD Algorithm Negotiation record
618  context->aeadAlgoNegoRecordReceived = TRUE;
619 
620  //When included in a response, the AEAD Algorithm Negotiation record
621  //denotes which algorithm the server chooses to use. It is empty if the
622  //server supports none of the algorithms offered (refer to RFC 8915,
623  //section 4.1.5)
624  if(length == sizeof(uint16_t) &&
625  body[0] == MSB(AEAD_AES_SIV_CMAC_256) &&
627  {
628  error = NO_ERROR;
629  }
630  else
631  {
632  error = ERROR_UNSUPPORTED_ALGO;
633  }
634  }
635 
636  //Return status code
637  return error;
638 }
639 
640 
641 /**
642  * @brief Parse New Cookie for NTPv4 record
643  * @param[in] context Pointer to the NTS client context
644  * @param[in] body Pointer to the record body
645  * @param[in] length Length of the record body, in bytes
646  * @return Error code
647  **/
648 
650  const uint8_t *body, size_t length)
651 {
652  //Malformed record?
653  if(length == 0)
654  return ERROR_INVALID_SYNTAX;
655 
656  //The implementation limits the size of NTS cookies
658  return ERROR_BUFFER_OVERFLOW;
659 
660  //The server may send multiple cookies
661  if(context->cookieLen == 0)
662  {
663  //The contents of its body shall be implementation-defined, and clients
664  //must not attempt to interpret them (refer to RFC 8915, section 4.1.6)
665  osMemcpy(context->cookie, body, length);
666 
667  //Save the size of the NTS cookie
668  context->cookieLen = length;
669  }
670 
671  //Successful processing
672  return NO_ERROR;
673 }
674 
675 
676 /**
677  * @brief Parse NTPv4 Server Negotiation record
678  * @param[in] context Pointer to the NTS client context
679  * @param[in] body Pointer to the record body
680  * @param[in] length Length of the record body, in bytes
681  * @return Error code
682  **/
683 
685  const uint8_t *body, size_t length)
686 {
687  //Malformed record?
688  if(length == 0)
689  return ERROR_INVALID_SYNTAX;
690 
691  //The implementation limits the length of NTP server names
693  return ERROR_BUFFER_OVERFLOW;
694 
695  //The body consists of an ASCII-encoded string. The contents of the string
696  //shall be either an IPv4 address, an IPv6 address, or a fully qualified
697  //domain name (refer to RFC 8915, section 4.1.7)
698  osMemcpy(context->ntpServerName, body, length);
699 
700  //Properly terminate the string with a NULL character
701  context->ntpServerName[length] = '\0';
702 
703  //Successful processing
704  return NO_ERROR;
705 }
706 
707 
708 /**
709  * @brief Parse NTPv4 Port Negotiation record
710  * @param[in] context Pointer to the NTS client context
711  * @param[in] body Pointer to the record body
712  * @param[in] length Length of the record body, in bytes
713  * @return Error code
714  **/
715 
717  const uint8_t *body, size_t length)
718 {
719  //Malformed record?
720  if(length != sizeof(uint16_t))
721  return ERROR_INVALID_SYNTAX;
722 
723  //The body consists of a 16-bit unsigned integer in network byte order,
724  //denoting a UDP port number (refer to RFC 8915, section 4.1.8)
725  context->ntpServerPort = LOAD16BE(body);
726 
727  //Successful processing
728  return NO_ERROR;
729 }
730 
731 
732 /**
733  * @brief Shutdown NTS-KE connection
734  * @param[in] context Pointer to the NTS client context
735  * @return Error code
736  **/
737 
739 {
740  error_t error;
741 
742  //After sending their respective request and response, the client and server
743  //shall send TLS "close_notify" alerts
744  error = tlsShutdown(context->tlsContext);
745 
746  //Check status code
747  if(!error)
748  {
749  //Valid TCP socket?
750  if(context->ntsKeSocket != NULL)
751  {
752  //Shutdown TCP connection
753  error = socketShutdown(context->ntsKeSocket, SOCKET_SD_BOTH);
754  }
755  }
756 
757  //Return status code
758  return error;
759 }
760 
761 
762 /**
763  * @brief Close NTS-KE connection
764  * @param[in] context Pointer to the NTS client context
765  **/
766 
768 {
769  //Valid TLS context?
770  if(context->tlsContext != NULL)
771  {
772  //Release TLS context
773  tlsFree(context->tlsContext);
774  context->tlsContext = NULL;
775  }
776 
777  //Valid socket?
778  if(context->ntsKeSocket != NULL)
779  {
780  //Close NTS-KE socket
781  socketClose(context->ntsKeSocket);
782  context->ntsKeSocket = NULL;
783  }
784 }
785 
786 
787 /**
788  * @brief Determine whether a timeout error has occurred (NTS-KE phase)
789  * @param[in] context Pointer to the NTS client context
790  * @return Error code
791  **/
792 
794 {
795 #if (NET_RTOS_SUPPORT == DISABLED)
796  error_t error;
797  systime_t time;
798 
799  //Get current time
800  time = osGetSystemTime();
801 
802  //Check whether the timeout has elapsed
803  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
804  {
805  //Report a timeout error
806  error = ERROR_TIMEOUT;
807  }
808  else
809  {
810  //The operation would block
811  error = ERROR_WOULD_BLOCK;
812  }
813 
814  //Return status code
815  return error;
816 #else
817  //Report a timeout error
818  return ERROR_TIMEOUT;
819 #endif
820 }
821 
822 
823 /**
824  * @brief Open NTP connection
825  * @param[in] context Pointer to the NTS client context
826  * @return Error code
827  **/
828 
830 {
831  error_t error;
832 
833  //Generate a unique identifier
834  error = context->randCallback(context->uniqueId, NTS_CLIENT_UNIQUE_ID_SIZE);
835  //Any error to report?
836  if(error)
837  return error;
838 
839  //Generate a nonce
840  error = context->randCallback(context->nonce, NTS_CLIENT_NONCE_SIZE);
841  //Any error to report?
842  if(error)
843  return error;
844 
845  //Open a UDP socket
846  context->ntpSocket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
847  //Failed to open socket?
848  if(context->ntpSocket == NULL)
849  return ERROR_OPEN_FAILED;
850 
851  //Associate the socket with the relevant interface
852  error = socketBindToInterface(context->ntpSocket, context->interface);
853  //Any error to report?
854  if(error)
855  return error;
856 
857  //Successful processing
858  return NO_ERROR;
859 }
860 
861 
862 /**
863  * @brief Send NTP request to the server
864  * @param[in] context Pointer to the NTS client context
865  * @return Error code
866  **/
867 
869 {
870  error_t error;
871  size_t length;
872  NtpHeader *header;
873  NtpExtension *extension;
874  NtpNtsAeadExtension *ntsAeadExtension;
875  DataChunk ad[2];
876 
877  //Point to the buffer where to format the NTP message
878  header = (NtpHeader *) context->buffer;
879 
880  //The client initializes the NTP message header. For this purpose, all
881  //the NTP header fields are set to 0, except the Mode, VN, and optional
882  //Transmit Timestamp fields
883  osMemset(header, 0, sizeof(NtpHeader));
884 
885  //Format NTP request
886  header->vn = NTP_VERSION_4;
887  header->mode = NTP_MODE_CLIENT;
888 
889  //Time at which the NTP request was sent
890  context->retransmitStartTime = osGetSystemTime();
891 
892  //The Transmit Timestamp allows a simple calculation to determine the
893  //propagation delay between the server and client and to align the system
894  //clock generally within a few tens of milliseconds relative to the server
895  header->transmitTimestamp.seconds = 0;
896  header->transmitTimestamp.fraction = 0;
897 
898  //The NTP header is 48 octets long
899  length = sizeof(NtpHeader);
900 
901  //The Unique Identifier extension field provides the client with a
902  //cryptographically strong means of detecting replayed packets (refer to
903  //RFC 8915, section 5.3)
904  extension = (NtpExtension *) (context->buffer + length);
905  extension->fieldType = HTONS(NTP_EXTENSION_TYPE_UNIQUE_ID);
906 
907  //The string must be at least 32 octets long
908  osMemcpy(extension->value, context->uniqueId, NTS_CLIENT_UNIQUE_ID_SIZE);
909 
910  //Calculate the length of the extension
911  extension->length = HTONS(sizeof(NtpExtension) + NTS_CLIENT_UNIQUE_ID_SIZE);
912  //Adjust the length of the packet
913  length += ntohs(extension->length);
914 
915  //The purpose of the NTS Cookie extension is to carry information that
916  //enables the server to recompute keys and other session state without
917  //having to store any per-client state (refer to RFC 8915, section 5.4)
918  extension = (NtpExtension *) (context->buffer + length);
919  extension->fieldType = HTONS(NTP_EXTENSION_TYPE_NTS_COOKIE);
920 
921  //The cookie must be one which has been previously provided to the client,
922  //either from the key establishment server during the NTS-KE handshake or
923  //from the NTP server in response to a previous NTS-protected NTP request
924  //(refer to RFC 8915, section 5.7)
925  osMemcpy(extension->value, context->cookie, context->cookieLen);
926 
927  //Calculate the length of the extension
928  extension->length = htons(sizeof(NtpExtension) + context->cookieLen);
929  //Adjust the length of the packet
930  length += ntohs(extension->length);
931 
932  //The NTS Authenticator and Encrypted Extension Fields extension is the
933  //central cryptographic element of an NTS-protected NTP packet (refer to
934  //RFC 8915, section 5.6)
935  ntsAeadExtension = (NtpNtsAeadExtension *) (context->buffer + length);
936  ntsAeadExtension->fieldType = HTONS(NTP_EXTENSION_TYPE_NTS_AEAD);
937  ntsAeadExtension->nonceLength = HTONS(NTS_CLIENT_NONCE_SIZE);
938  ntsAeadExtension->ciphertextLength = HTONS(SIV_IV_LEN);
939 
940  //Copy the nonce
941  osMemcpy(ntsAeadExtension->nonce, context->nonce, NTS_CLIENT_NONCE_SIZE);
942 
943  //The associated data shall consist of the portion of the NTP packet
944  //beginning from the start of the NTP header and ending at the end of the
945  //last extension field that precedes the NTS Authenticator and Encrypted
946  //Extension Fields extension field (refer to RFC 8915, section 5.6)
947  ad[0].buffer = context->buffer;
948  ad[0].length = length;
949  ad[1].buffer = context->nonce;
951 
952  //The Ciphertext field is the output of the negotiated AEAD algorithm
953  error = sivEncrypt(AES_CIPHER_ALGO, context->c2sKey, 32, ad, arraysize(ad),
954  NULL, NULL, 0, ntsAeadExtension->nonce + NTS_CLIENT_NONCE_SIZE);
955  //AEAD encryption failed?
956  if(error)
957  return error;
958 
959  //Calculate the length of the extension
960  ntsAeadExtension->length = htons(sizeof(NtpNtsAeadExtension) +
962 
963  //Adjust the length of the packet
964  length += ntohs(ntsAeadExtension->length);
965  //Save the length of the resulting NTP request
966  context->bufferLen = length;
967 
968  //Debug message
969  TRACE_INFO("Sending NTP request message (%" PRIuSIZE " bytes)...\r\n",
970  context->bufferLen);
971 
972  //Dump the contents of the NTP packet for debugging purpose
973  ntpDumpPacket(header, context->bufferLen);
974 
975  //Send the NTP request to the designated server
976  error = socketSendTo(context->ntpSocket, &context->ntpServerIpAddr,
977  context->ntpServerPort, context->buffer, context->bufferLen,
978  NULL, 0);
979 
980  //Check status code
981  if(!error)
982  {
983  //Wait for server's response
985  }
986 
987  //Return status code
988  return error;
989 }
990 
991 
992 /**
993  * @brief Wait for NTP response
994  * @param[in] context Pointer to the NTS client context
995  * @return Error code
996  **/
997 
999 {
1000  error_t error;
1001  systime_t t1;
1002  systime_t t2;
1003  systime_t time;
1004  IpAddr ipAddr;
1005  uint16_t port;
1006 
1007  //Get current time
1008  time = osGetSystemTime();
1009 
1010  //Compute request timeout
1011  if(timeCompare(context->startTime + context->timeout, time) > 0)
1012  {
1013  t1 = context->startTime + context->timeout - time;
1014  }
1015  else
1016  {
1017  t1 = 0;
1018  }
1019 
1020  //Compute retransmission timeout
1021  if(timeCompare(context->retransmitStartTime + context->retransmitTimeout, time) > 0)
1022  {
1023  t2 = context->retransmitStartTime + context->retransmitTimeout - time;
1024  }
1025  else
1026  {
1027  t2 = 0;
1028  }
1029 
1030  //Adjust receive timeout
1031  error = socketSetTimeout(context->ntpSocket, MIN(t1, t2));
1032 
1033  //Check status code
1034  if(!error)
1035  {
1036  //Wait for server's response
1037  error = socketReceiveFrom(context->ntpSocket, &ipAddr, &port,
1038  context->buffer, NTS_CLIENT_BUFFER_SIZE, &context->bufferLen, 0);
1039  }
1040 
1041  //Any datagram received?
1042  if(error == NO_ERROR)
1043  {
1044  //Decrypt NTP response
1045  error = ntsClientDecryptNtpResponse(context, &ipAddr, port,
1046  context->buffer, context->bufferLen);
1047 
1048  //Check status code
1049  if(!error)
1050  {
1051  //A valid NTP response has been received
1053  }
1054  else
1055  {
1056  //Silently discard invalid NTP packets
1057  error = ntsClientCheckNtpTimeout(context);
1058  }
1059  }
1060  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1061  {
1062  //Check whether the timeout has elapsed
1063  error = ntsClientCheckNtpTimeout(context);
1064  }
1065  else
1066  {
1067  //A communication error has occurred
1068  }
1069 
1070  //Return status code
1071  return error;
1072 }
1073 
1074 
1075 /**
1076  * @brief Decrypt NTP response
1077  * @param[in] context Pointer to the NTS client context
1078  * @param[in] ipAddr Remote IP address
1079  * @param[in] port Remote port number
1080  * @param[in] message Pointer to the NTP message
1081  * @param[in] length Length of the NTP message, in bytes
1082  * @return Error code
1083  **/
1084 
1086  const IpAddr *ipAddr, uint16_t port, const uint8_t *message,
1087  size_t length)
1088 {
1089  error_t error;
1090  size_t n;
1091  size_t nonceLen;
1092  const NtpHeader *header;
1093  const NtpExtension *uniqueIdExtension;
1094  const NtpNtsAeadExtension *ntsAeadExtension;
1095  const NtpExtension *ntsCookieExtension;
1096  const uint8_t *iv;
1097  const uint8_t *ciphertext;
1098  uint8_t *plaintext;
1099  DataChunk ad[2];
1100 
1101  //Ensure the NTP packet is valid
1102  if(length < sizeof(NtpHeader))
1103  return ERROR_INVALID_MESSAGE;
1104 
1105  //Point to the NTP response
1106  header = (NtpHeader *) context->buffer;
1107 
1108  //Debug message
1109  TRACE_INFO("NTP response message received (%" PRIuSIZE " bytes)...\r\n",
1110  length);
1111 
1112  //Dump the contents of the NTP packet for debugging purpose
1113  ntpDumpPacket(header, length);
1114 
1115  //Check NTP version
1116  if(header->vn != NTP_VERSION_4)
1117  return ERROR_INVALID_MESSAGE;
1118 
1119  //The server reply should be discarded if the Transmit Timestamp fields is 0
1120  if(header->transmitTimestamp.seconds == 0 &&
1121  header->transmitTimestamp.fraction == 0)
1122  {
1123  return ERROR_INVALID_MESSAGE;
1124  }
1125 
1126  //The server reply should be discarded if the Mode field is not 4 (unicast)
1127  //or 5 (broadcast)
1128  if(header->mode != NTP_MODE_SERVER && header->mode != NTP_MODE_BROADCAST)
1129  return ERROR_INVALID_MESSAGE;
1130 
1131  //The Originate Timestamp in the server reply should match the Transmit
1132  //Timestamp used in the client request
1133  if(header->originateTimestamp.seconds != 0 ||
1134  header->originateTimestamp.fraction != 0)
1135  {
1136  return ERROR_INVALID_MESSAGE;
1137  }
1138 
1139  //Determine the total length occupied by the NTP extensions
1140  length -= sizeof(NtpHeader);
1141 
1142  //All server packets generated by NTS-implementing servers in response to
1143  //client packets containing the Unique Identifier extension field must also
1144  //contain this field with the same content as in the client's request (refer
1145  //to RFC 8915, section 5.3)
1146  uniqueIdExtension = ntpGetExtension(header->extensions, length,
1148 
1149  //Exactly one Unique Identifier extension must be present
1150  if(ntpGetExtension(header->extensions, length, NTP_EXTENSION_TYPE_UNIQUE_ID,
1151  1) != NULL || uniqueIdExtension == NULL)
1152  {
1153  return ERROR_INVALID_MESSAGE;
1154  }
1155 
1156  //Retrieve the length of the octet string
1157  n = ntohs(uniqueIdExtension->length) - sizeof(NtpExtension);
1158 
1159  //Upon receiving an NTS-protected response, the client must verify that the
1160  //Unique Identifier matches that of an outstanding request (refer to
1161  //RFC 8915, section 5.7)
1162  if(n != NTS_CLIENT_UNIQUE_ID_SIZE ||
1163  osMemcmp(uniqueIdExtension->value, context->uniqueId, n) != 0)
1164  {
1165  return ERROR_INVALID_MESSAGE;
1166  }
1167 
1168  //Search for the NTS Authenticator and Encrypted Extension Fields extension
1169  ntsAeadExtension = (NtpNtsAeadExtension *) ntpGetExtension(header->extensions,
1171 
1172  //Exactly one NTS Authenticator and Encrypted Extension Fields extension
1173  //must be present
1174  if(ntpGetExtension(header->extensions, length, NTP_EXTENSION_TYPE_NTS_AEAD,
1175  1) != NULL || ntsAeadExtension == NULL)
1176  {
1177  return ERROR_INVALID_MESSAGE;
1178  }
1179 
1180  //Malformed NTS Authenticator and Encrypted Extension Fields extension?
1181  if(ntohs(ntsAeadExtension->length) < sizeof(NtpNtsAeadExtension))
1182  {
1183  return ERROR_INVALID_MESSAGE;
1184  }
1185 
1186  //Retrieve the length of the nonce and ciphertext
1187  nonceLen = ntohs(ntsAeadExtension->nonceLength);
1188  n = ntohs(ntsAeadExtension->ciphertextLength);
1189 
1190  //Malformed NTS Authenticator and Encrypted Extension Fields extension?
1191  if(ntohs(ntsAeadExtension->length) < (sizeof(NtpNtsAeadExtension) +
1192  nonceLen + n))
1193  {
1194  return ERROR_INVALID_MESSAGE;
1195  }
1196 
1197  //Check the length of the ciphertext
1198  if(n < SIV_IV_LEN)
1199  return ERROR_INVALID_MESSAGE;
1200 
1201  //Point to the synthetic IV
1202  iv = ntsAeadExtension->nonce + nonceLen;
1203 
1204  //Point to the ciphertext
1205  ciphertext = iv + SIV_IV_LEN;
1206  n -= SIV_IV_LEN;
1207 
1208  //Point to the buffer where to store the resulting plaintext
1209  plaintext = (uint8_t *) ciphertext;
1210 
1211  //The associated data shall consist of the portion of the NTP packet
1212  //beginning from the start of the NTP header and ending at the end of the
1213  //last extension field that precedes the NTS Authenticator and Encrypted
1214  //Extension Fields extension field (refer to RFC 8915, section 5.6)
1215  ad[0].buffer = context->buffer;
1216  ad[0].length = (uint8_t *) ntsAeadExtension - context->buffer;
1217  ad[1].buffer = ntsAeadExtension->nonce;
1218  ad[1].length = nonceLen;
1219 
1220  //The Unique Identifier extension field must be authenticated but must not
1221  //be encrypted
1222  if((uint8_t *) uniqueIdExtension >= (uint8_t *) ntsAeadExtension)
1223  return ERROR_INVALID_MESSAGE;
1224 
1225  //The client must verify that the packet is authentic under the S2C key
1226  //associated with that request (refer to RFC 8915, section 5.7)
1227  error = sivDecrypt(AES_CIPHER_ALGO, context->s2cKey, 32, ad, arraysize(ad),
1228  ciphertext, plaintext, n, iv);
1229  //AEAD decryption failed?
1230  if(error)
1231  return ERROR_INVALID_MESSAGE;
1232 
1233  //Debug message
1234  TRACE_DEBUG("Plaintext (%" PRIuSIZE " bytes):\r\n", n);
1235  //Dump plaintext for debugging purpose
1236  ntpDumpExtensions(plaintext, n);
1237 
1238  //One or more NTS Cookie extension fields must be authenticated and
1239  //encrypted (refer to RFC 8915, section 5.7)
1240  ntsCookieExtension = ntpGetExtension(plaintext, n,
1242 
1243  //NTS Cookie extension not found?
1244  if(ntsCookieExtension == NULL)
1245  return ERROR_MISSING_EXTENSION;
1246 
1247  //Retrieve the length of the cookie
1248  n = ntohs(ntsCookieExtension->length) - sizeof(NtpExtension);
1249 
1250  //The implementation limits the size of NTS cookies
1252  return ERROR_BUFFER_OVERFLOW;
1253 
1254  //The contents of its body shall be implementation-defined, and clients
1255  //must not attempt to interpret them (refer to RFC 8915, section 4.1.6)
1256  osMemcpy(context->cookie, ntsCookieExtension->value, n);
1257 
1258  //Save the size of the NTS cookie
1259  context->cookieLen = n;
1260 
1261  //The NTP response message is acceptable
1262  return NO_ERROR;
1263 }
1264 
1265 
1266 /**
1267  * @brief Parse NTP response
1268  * @param[in] context Pointer to the NTS client context
1269  * @param[out] timestamp Pointer to the NTP timestamp
1270  * @return Error code
1271  **/
1272 
1274  NtpTimestamp *timestamp)
1275 {
1276  NtpHeader *header;
1277 
1278  //Ensure the NTP packet is valid
1279  if(context->bufferLen < sizeof(NtpHeader))
1280  return ERROR_INVALID_LENGTH;
1281 
1282  //Point to the NTP response
1283  header = (NtpHeader *) context->buffer;
1284 
1285  //Clear kiss code
1286  context->kissCode = 0;
1287 
1288  //Kiss-of-Death packet received?
1289  if(header->stratum == 0)
1290  {
1291  //The kiss code is encoded in four-character ASCII strings left
1292  //justified and zero filled
1293  context->kissCode = htonl(header->referenceId);
1294 
1295  //An NTS client should stop sending to a particular server if that
1296  //server returns a reply with a Stratum field of 0
1297  return ERROR_REQUEST_REJECTED;
1298  }
1299 
1300  //Extract NTP timestamp from server's response
1301  timestamp->seconds = ntohl(header->transmitTimestamp.seconds);
1302  timestamp->fraction = ntohl(header->transmitTimestamp.fraction);
1303 
1304  //Successful processing
1305  return NO_ERROR;
1306 }
1307 
1308 
1309 /**
1310  * @brief Close NTP connection
1311  * @param[in] context Pointer to the NTS client context
1312  **/
1313 
1315 {
1316  //Valid socket?
1317  if(context->ntpSocket != NULL)
1318  {
1319  //Close UDP socket
1320  socketClose(context->ntpSocket);
1321  context->ntpSocket = NULL;
1322  }
1323 }
1324 
1325 
1326 /**
1327  * @brief Determine whether a timeout error has occurred (NTP phase)
1328  * @param[in] context Pointer to the NTS client context
1329  * @return Error code
1330  **/
1331 
1333 {
1334  error_t error;
1335  systime_t time;
1336 
1337  //Get current time
1338  time = osGetSystemTime();
1339 
1340  //Check whether the timeout has elapsed
1341  if(timeCompare(time, context->startTime + context->timeout) >= 0)
1342  {
1343  //Report a timeout error
1344  error = ERROR_TIMEOUT;
1345  }
1346  else if(timeCompare(time, context->retransmitStartTime + context->retransmitTimeout) >= 0)
1347  {
1348  //The timeout value is doubled for each subsequent retransmission
1349  context->retransmitTimeout = MIN(context->retransmitTimeout * 2,
1351 
1352  //Retransmit NTP request
1354 
1355  //Continue processing
1356  error = NO_ERROR;
1357  }
1358  else
1359  {
1360 #if (NET_RTOS_SUPPORT == ENABLED)
1361  //Report a timeout error
1362  error = ERROR_TIMEOUT;
1363 #else
1364  //The operation would block
1365  error = ERROR_WOULD_BLOCK;
1366 #endif
1367  }
1368 
1369  //Return status code
1370  return error;
1371 }
1372 
1373 #endif
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:67
error_t ntsClientParseNewCookieForNtpv4Record(NtsClientContext *context, const uint8_t *body, size_t length)
Parse New Cookie for NTPv4 record.
void ntsClientChangeState(NtsClientContext *context, NtsClientState newState)
Update NTS client state.
#define htons(value)
Definition: cpu_endian.h:413
@ NTP_EXTENSION_TYPE_NTS_COOKIE
NTS Cookie.
Definition: ntp_common.h:155
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
void ntpDumpPacket(const NtpHeader *packet, size_t length)
Dump NTP packet for debugging purpose.
Definition: ntp_debug.c:108
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:357
error_t ntsClientParseNtpv4PortRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse NTPv4 Port Negotiation record.
@ ERROR_WOULD_BLOCK
Definition: error.h:96
IP network address.
Definition: ip.h:90
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
error_t ntsClientOpenNtpConnection(NtsClientContext *context)
Open NTP connection.
NtpTimestamp
Definition: ntp_common.h:179
#define NTS_CLIENT_UNIQUE_ID_SIZE
Definition: nts_client.h:111
error_t ntsClientOpenNtsKeConnection(NtsClientContext *context)
Open NTS-KE connection.
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
Collection of AEAD algorithms.
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2067
const void * buffer
Definition: crypto.h:1018
@ NTS_CLIENT_STATE_NTS_KE_DISCONNECTING
Definition: nts_client.h:149
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:804
#define NTS_CLIENT_BUFFER_SIZE
Definition: nts_client.h:76
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
@ NTP_MODE_SERVER
Definition: ntp_common.h:88
uint8_t type
Definition: coap_common.h:176
#define osMemcmp(p1, p2, length)
Definition: os_port.h:156
void ntpDumpExtensions(const uint8_t *extensions, size_t length)
Dump NTP extension fields.
Definition: ntp_debug.c:212
@ ERROR_WRONG_COOKIE
Definition: error.h:92
NtpNtsAeadExtension
Definition: ntp_common.h:234
#define NTS_KE_RECORD_TYPE_MASK
Definition: nts_common.h:43
@ NTS_CLIENT_STATE_NTS_KE_RECEIVING
Definition: nts_client.h:148
@ NTS_KE_RECORD_TYPE_NTPV4_SERVER_NEGO
NTPv4 Server Negotiation.
Definition: nts_common.h:63
@ ERROR_INVALID_MESSAGE
Definition: error.h:105
void ntsClientCloseNtpConnection(NtsClientContext *context)
Close NTP connection.
@ NTS_KE_RECORD_TYPE_END_OF_MESSAGE
End of Message.
Definition: nts_common.h:57
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
NTS client (Network Time Security)
#define timeCompare(t1, t2)
Definition: os_port.h:40
@ NTS_KE_RECORD_TYPE_NTS_NEXT_PROTO_NEGO
NTS Next Protocol Negotiation.
Definition: nts_common.h:58
@ AEAD_AES_SIV_CMAC_256
RFC 5297.
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:2818
void ntsDumpNtsKeRecords(const uint8_t *records, size_t length)
Dump NTS-KE records.
Definition: nts_debug.c:83
@ NTP_MODE_BROADCAST
Definition: ntp_common.h:89
#define SIV_IV_LEN
Definition: siv.h:38
@ ERROR_OPEN_FAILED
Definition: error.h:75
error_t tlsSetVersion(TlsContext *context, uint16_t versionMin, uint16_t versionMax)
Set minimum and maximum versions permitted.
Definition: tls.c:289
#define NTS_CLIENT_TLS_RX_BUFFER_SIZE
Definition: nts_client.h:90
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2423
#define FALSE
Definition: os_port.h:46
#define NTP_PORT
Definition: ntp_common.h:38
error_t ntsClientParseNtsNextProtoNegoRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse NTS Next Protocol Negotiation record.
#define htonl(value)
Definition: cpu_endian.h:414
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define tlsSetSocket(context, socket)
Definition: tls.h:949
error_t ntsClientParseEndOfMessageRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse End of Message record.
error_t
Error codes.
Definition: error.h:43
Data logging functions for debugging purpose (NTP)
@ ERROR_UNSUPPORTED_ALGO
Definition: error.h:126
error_t ntsClientSendNtpRequest(NtsClientContext *context)
Send NTP request to the server.
NtsClientState
NTS client states.
Definition: nts_client.h:143
error_t ntsClientShutdownNtsKeConnection(NtsClientContext *context)
Shutdown NTS-KE connection.
#define NTS_CLIENT_TLS_TX_BUFFER_SIZE
Definition: nts_client.h:83
@ ERROR_MISSING_EXTENSION
Definition: error.h:245
#define TLS_VERSION_1_3
Definition: tls.h:97
@ NTP_EXTENSION_TYPE_UNIQUE_ID
Unique Identifier.
Definition: ntp_common.h:154
@ ERROR_INVALID_LENGTH
Definition: error.h:111
error_t socketReceiveFrom(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, uint_t flags)
Receive a datagram from a connectionless socket.
Definition: socket.c:1719
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1354
uint8_t iv[]
Definition: ike.h:1626
@ NTS_KE_RECORD_TYPE_NEW_COOKIE_FOR_NTPV4
New Cookie for NTPv4.
Definition: nts_common.h:62
#define MSB(x)
Definition: os_port.h:59
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2025
error_t ntsClientReceiveNtpResponse(NtsClientContext *context)
Wait for NTP response.
@ ERROR_UNEXPECTED_RESPONSE
Definition: error.h:70
error_t ntsClientReceiveNtsKeResponse(NtsClientContext *context)
Receive NTS-KE response.
uint32_t t2
#define TRACE_INFO(...)
Definition: debug.h:105
error_t tlsSaveSessionState(const TlsContext *context, TlsSessionState *session)
Save TLS session.
Definition: tls.c:2749
uint8_t length
Definition: tcp.h:375
#define LSB(x)
Definition: os_port.h:55
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
error_t ntsClientParseWarningRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse Warning record.
error_t tlsRead(TlsContext *context, void *data, size_t size, size_t *received, uint_t flags)
Receive application data from a the remote host using TLS.
Definition: tls.c:2105
error_t ntsClientEstablishNtsKeConnection(NtsClientContext *context)
Establish NTS-KE connection.
@ ERROR_INVALID_PROTOCOL
Definition: error.h:101
#define MIN(a, b)
Definition: os_port.h:63
@ NTS_KE_RECORD_TYPE_AEAD_ALGO_NEGO
AEAD Algorithm Negotiation.
Definition: nts_common.h:61
error_t ntsClientCheckNtpTimeout(NtsClientContext *context)
Determine whether a timeout error has occurred (NTP phase)
@ NTS_CLIENT_STATE_NTP_RECEIVING
Definition: nts_client.h:153
#define socketBindToInterface
Definition: net_legacy.h:193
#define NtsClientContext
Definition: nts_client.h:130
const NtpExtension * ntpGetExtension(const uint8_t *extensions, size_t length, uint16_t type, uint_t index)
Search a NTP packet for a given extension.
Definition: ntp_common.c:53
@ NTS_CLIENT_STATE_NTP_SENDING
Definition: nts_client.h:152
error_t ntsClientDecryptNtpResponse(NtsClientContext *context, const IpAddr *ipAddr, uint16_t port, const uint8_t *message, size_t length)
Decrypt NTP response.
@ NTS_PROTOCOL_ID_NTPV4
Network Time Protocol version 4 (NTPv4)
Definition: nts_common.h:74
error_t ntsClientParseErrorRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse Error record.
Data chunk descriptor.
Definition: crypto.h:1017
uint32_t systime_t
System time.
uint16_t port
Definition: dns_common.h:267
#define ntohs(value)
Definition: cpu_endian.h:421
#define TRACE_DEBUG(...)
Definition: debug.h:119
@ ERROR_TIMEOUT
Definition: error.h:95
void ntsClientCloseNtsKeConnection(NtsClientContext *context)
Close NTS-KE connection.
@ NTP_MODE_CLIENT
Definition: ntp_common.h:87
uint32_t time
@ NTS_KE_RECORD_TYPE_ERROR
Error.
Definition: nts_common.h:59
uint32_t t1
error_t tlsSetBufferSize(TlsContext *context, size_t txBufferSize, size_t rxBufferSize)
Set TLS buffer size.
Definition: tls.c:529
NtpHeader
Definition: ntp_common.h:208
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
error_t ntsClientParseNtpv4ServerRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse NTPv4 Server Negotiation record.
NtsKeRecord
Definition: nts_common.h:107
error_t sivDecrypt(const CipherAlgo *cipher, const uint8_t *k, size_t kLen, const DataChunk *ad, uint_t adLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *v)
Authenticated decryption using SIV.
Definition: siv.c:133
error_t ntsClientParseNtpResponse(NtsClientContext *context, NtpTimestamp *timestamp)
Parse NTP response.
error_t ntsClientSendNtsKeRequest(NtsClientContext *context)
Send NTS-KE request.
error_t ntsClientParseAeadAlgoNegoRecord(NtsClientContext *context, const uint8_t *body, size_t length)
Parse AEAD Algorithm Negotiation record.
@ TLS_CONNECTION_END_CLIENT
Definition: tls.h:990
#define NTS_CLIENT_MAX_NTP_RETRANSMIT_TIMEOUT
Definition: nts_client.h:69
error_t tlsWrite(TlsContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Send application data to the remote host using TLS.
Definition: tls.c:1970
error_t socketSendTo(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written, uint_t flags)
Send a datagram to a specific destination.
Definition: socket.c:1512
#define AES_CIPHER_ALGO
Definition: aes.h:45
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
error_t ntsClientCheckNtsKeTimeout(NtsClientContext *context)
Determine whether a timeout error has occurred (NTS-KE phase)
error_t tlsSetAlpnProtocolList(TlsContext *context, const char_t *protocolList)
Set the list of supported ALPN protocols.
Definition: tls.c:892
size_t length
Definition: crypto.h:1019
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2585
Ipv4Addr ipAddr
Definition: ipcp.h:105
Definitions common to NTP client and server.
@ NTS_KE_RECORD_TYPE_WARNING
Warning.
Definition: nts_common.h:60
#define NTS_CLIENT_MAX_COOKIE_SIZE
Definition: nts_client.h:97
@ NTS_CLIENT_STATE_COMPLETE
Definition: nts_client.h:154
@ ERROR_REQUEST_REJECTED
Definition: error.h:273
error_t sivEncrypt(const CipherAlgo *cipher, const uint8_t *k, size_t kLen, const DataChunk *ad, uint_t adLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *v)
Authenticated encryption using SIV.
Definition: siv.c:65
NtpExtension
Definition: ntp_common.h:220
#define NTS_CLIENT_MAX_NTP_SERVER_NAME_LEN
Definition: nts_client.h:104
#define PRIuSIZE
#define LOAD16BE(p)
Definition: cpu_endian.h:186
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
uint8_t body[]
Definition: nts_common.h:106
Data logging functions for debugging purpose (NTS)
@ NTS_KE_RECORD_TYPE_NTPV4_PORT_NEGO
NTPv4 Port Negotiation.
Definition: nts_common.h:64
@ SOCKET_SD_BOTH
Definition: socket.h:161
error_t tlsExportKeyingMaterial(TlsContext *context, const char_t *label, bool_t useContextValue, const uint8_t *contextValue, size_t contextValueLen, uint8_t *output, size_t outputLen)
Export keying material per RFC 5705 standard.
Definition: tls.c:1824
error_t ntsClientFormatNtsKeRequest(NtsClientContext *context)
Format NTS-KE request.
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1730
void ntsDumpNtsKeRecord(const NtsKeRecord *record, size_t length)
Dump NTS-KE record.
Definition: nts_debug.c:121
@ NTP_VERSION_4
Definition: ntp_common.h:75
#define ntohl(value)
Definition: cpu_endian.h:422
#define NTS_KE_CRITICAL
Definition: nts_common.h:41
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
Helper functions for NTS client.
#define NTS_CLIENT_NONCE_SIZE
Definition: nts_client.h:118
@ NTP_EXTENSION_TYPE_NTS_AEAD
NTS Authenticator and Encrypted Extension Fields.
Definition: ntp_common.h:157
#define arraysize(a)
Definition: os_port.h:71
systime_t osGetSystemTime(void)
Retrieve system time.