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