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