2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2019
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **********************************************************************
22 =======================================================================
36 #include "ntp_signd.h"
38 #include "nts_ntp_client.h"
39 #include "nts_ntp_server.h"
40 #include "srcparams.h"
43 /* Structure to hold authentication configuration and state */
45 struct NAU_Instance_Record
{
46 NTP_AuthMode mode
; /* Authentication mode of NTP packets */
47 uint32_t key_id
; /* Identifier of a symmetric key */
48 NNC_Instance nts
; /* Client NTS state */
51 /* ================================================== */
54 generate_symmetric_auth(uint32_t key_id
, NTP_Packet
*packet
, NTP_PacketInfo
*info
)
56 int auth_len
, max_auth_len
;
58 /* Truncate long MACs in NTPv4 packets to allow deterministic parsing
59 of extension fields (RFC 7822) */
60 max_auth_len
= (info
->version
== 4 ? NTP_MAX_V4_MAC_LENGTH
: NTP_MAX_MAC_LENGTH
) - 4;
61 max_auth_len
= MIN(max_auth_len
, sizeof (NTP_Packet
) - info
->length
- 4);
63 auth_len
= KEY_GenerateAuth(key_id
, (unsigned char *)packet
, info
->length
,
64 (unsigned char *)packet
+ info
->length
+ 4, max_auth_len
);
66 DEBUG_LOG("Could not generate auth data with key %"PRIu32
, key_id
);
70 *(uint32_t *)((unsigned char *)packet
+ info
->length
) = htonl(key_id
);
71 info
->length
+= 4 + auth_len
;
76 /* ================================================== */
79 check_symmetric_auth(NTP_Packet
*packet
, NTP_PacketInfo
*info
)
83 if (info
->auth
.mac
.length
< NTP_MIN_MAC_LENGTH
)
86 trunc_len
= info
->version
== 4 && info
->auth
.mac
.length
<= NTP_MAX_V4_MAC_LENGTH
?
87 NTP_MAX_V4_MAC_LENGTH
: NTP_MAX_MAC_LENGTH
;
89 if (!KEY_CheckAuth(info
->auth
.mac
.key_id
, (void *)packet
, info
->auth
.mac
.start
,
90 (unsigned char *)packet
+ info
->auth
.mac
.start
+ 4,
91 info
->auth
.mac
.length
- 4, trunc_len
- 4))
97 /* ================================================== */
100 adjust_timestamp(NTP_AuthMode mode
, uint32_t key_id
, struct timespec
*ts
)
103 case NTP_AUTH_SYMMETRIC
:
104 ts
->tv_nsec
+= KEY_GetAuthDelay(key_id
);
105 UTI_NormaliseTimespec(ts
);
107 case NTP_AUTH_MSSNTP
:
108 ts
->tv_nsec
+= NSD_GetAuthDelay(key_id
);
109 UTI_NormaliseTimespec(ts
);
115 /* ================================================== */
118 is_zero_data(unsigned char *data
, int length
)
122 for (i
= 0; i
< length
; i
++)
128 /* ================================================== */
131 create_instance(NTP_AuthMode mode
)
133 NAU_Instance instance
;
135 instance
= MallocNew(struct NAU_Instance_Record
);
136 instance
->mode
= mode
;
137 instance
->key_id
= INACTIVE_AUTHKEY
;
138 instance
->nts
= NULL
;
140 assert(sizeof (instance
->key_id
) == 4);
145 /* ================================================== */
148 NAU_CreateNoneInstance(void)
150 return create_instance(NTP_AUTH_NONE
);
153 /* ================================================== */
156 NAU_CreateSymmetricInstance(uint32_t key_id
)
158 NAU_Instance instance
= create_instance(NTP_AUTH_SYMMETRIC
);
160 instance
->key_id
= key_id
;
162 if (!KEY_KeyKnown(key_id
))
163 LOG(LOGS_WARN
, "Key %"PRIu32
" is %s", key_id
, "missing");
164 else if (!KEY_CheckKeyLength(key_id
))
165 LOG(LOGS_WARN
, "Key %"PRIu32
" is %s", key_id
, "too short");
170 /* ================================================== */
173 NAU_CreateNtsInstance(IPSockAddr
*nts_address
, const char *name
, const IPSockAddr
*ntp_address
)
175 NAU_Instance instance
= create_instance(NTP_AUTH_NTS
);
177 instance
->nts
= NNC_CreateInstance(nts_address
, name
, ntp_address
);
182 /* ================================================== */
185 NAU_DestroyInstance(NAU_Instance instance
)
188 NNC_DestroyInstance(instance
->nts
);
192 /* ================================================== */
195 NAU_IsAuthEnabled(NAU_Instance instance
)
197 return instance
->mode
!= NTP_AUTH_NONE
;
200 /* ================================================== */
203 NAU_GetSuggestedNtpVersion(NAU_Instance instance
)
205 /* If the MAC in NTPv4 packets would be truncated, prefer NTPv3 for
206 compatibility with older chronyd servers */
207 if (instance
->mode
== NTP_AUTH_SYMMETRIC
&&
208 KEY_GetAuthLength(instance
->key_id
) + sizeof (instance
->key_id
) > NTP_MAX_V4_MAC_LENGTH
)
214 /* ================================================== */
217 NAU_PrepareRequestAuth(NAU_Instance instance
)
219 switch (instance
->mode
) {
221 if (!NNC_PrepareForAuth(instance
->nts
))
231 /* ================================================== */
234 NAU_AdjustRequestTimestamp(NAU_Instance instance
, struct timespec
*ts
)
236 adjust_timestamp(instance
->mode
, instance
->key_id
, ts
);
239 /* ================================================== */
242 NAU_GenerateRequestAuth(NAU_Instance instance
, NTP_Packet
*request
, NTP_PacketInfo
*info
)
244 switch (instance
->mode
) {
247 case NTP_AUTH_SYMMETRIC
:
248 if (!generate_symmetric_auth(instance
->key_id
, request
, info
))
252 if (!NNC_GenerateRequestAuth(instance
->nts
, request
, info
))
262 /* ================================================== */
265 NAU_ParsePacket(NTP_Packet
*packet
, NTP_PacketInfo
*info
)
267 int parsed
, remainder
, ef_length
, ef_type
;
270 data
= (void *)packet
;
271 parsed
= NTP_HEADER_LENGTH
;
272 remainder
= info
->length
- parsed
;
274 info
->ext_fields
= 0;
276 /* Check if this is a plain NTP packet with no extension fields or MAC */
280 /* In NTPv3 and older packets don't have extension fields. Anything after
281 the header is assumed to be a MAC. */
282 if (info
->version
<= 3) {
283 info
->auth
.mode
= NTP_AUTH_SYMMETRIC
;
284 info
->auth
.mac
.start
= parsed
;
285 info
->auth
.mac
.length
= remainder
;
286 info
->auth
.mac
.key_id
= ntohl(*(uint32_t *)(data
+ parsed
));
288 /* Check if it is an MS-SNTP authenticator field or extended authenticator
289 field with zeroes as digest */
290 if (info
->version
== 3 && info
->auth
.mac
.key_id
) {
291 if (remainder
== 20 && is_zero_data(data
+ parsed
+ 4, remainder
- 4))
292 info
->auth
.mode
= NTP_AUTH_MSSNTP
;
293 else if (remainder
== 72 && is_zero_data(data
+ parsed
+ 8, remainder
- 8))
294 info
->auth
.mode
= NTP_AUTH_MSSNTP_EXT
;
300 /* Check for a crypto NAK */
301 if (remainder
== 4 && ntohl(*(uint32_t *)(data
+ parsed
)) == 0) {
302 info
->auth
.mode
= NTP_AUTH_SYMMETRIC
;
303 info
->auth
.mac
.start
= parsed
;
304 info
->auth
.mac
.length
= remainder
;
305 info
->auth
.mac
.key_id
= 0;
309 /* Parse the rest of the NTPv4 packet */
311 while (remainder
> 0) {
312 /* Check if the remaining data is a MAC */
313 if (remainder
>= NTP_MIN_MAC_LENGTH
&& remainder
<= NTP_MAX_V4_MAC_LENGTH
)
316 /* The NTPv4-specific limit for MAC length enables deterministic parsing of
317 packets with extension fields (RFC 7822), but we support longer MACs in
318 packets with no extension fields for compatibility with older chrony
319 clients. Check if the longer MAC would authenticate the packet before
320 trying to parse the data as an extension field. */
321 if (parsed
== NTP_HEADER_LENGTH
&&
322 remainder
> NTP_MAX_V4_MAC_LENGTH
&& remainder
<= NTP_MAX_MAC_LENGTH
&&
323 KEY_CheckAuth(ntohl(*(uint32_t *)(data
+ parsed
)), data
, parsed
,
324 (void *)(data
+ parsed
+ 4), remainder
- 4, NTP_MAX_MAC_LENGTH
- 4))
327 /* Check if this is a valid NTPv4 extension field and skip it */
328 if (!NEF_ParseField(packet
, info
->length
, parsed
, &ef_length
, &ef_type
, NULL
, NULL
)) {
329 /* Invalid MAC or format error */
330 DEBUG_LOG("Invalid format or MAC");
334 assert(ef_length
> 0);
337 case NTP_EF_NTS_UNIQUE_IDENTIFIER
:
338 case NTP_EF_NTS_COOKIE
:
339 case NTP_EF_NTS_COOKIE_PLACEHOLDER
:
340 case NTP_EF_NTS_AUTH_AND_EEF
:
341 info
->auth
.mode
= NTP_AUTH_NTS
;
344 DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type
);
349 remainder
= info
->length
- parsed
;
352 if (remainder
== 0) {
355 } else if (remainder
>= NTP_MIN_MAC_LENGTH
) {
356 /* This is not 100% reliable as a MAC could fail to authenticate and could
357 pass as an extension field, leaving reminder smaller than the minimum MAC
359 info
->auth
.mode
= NTP_AUTH_SYMMETRIC
;
360 info
->auth
.mac
.start
= parsed
;
361 info
->auth
.mac
.length
= remainder
;
362 info
->auth
.mac
.key_id
= ntohl(*(uint32_t *)(data
+ parsed
));
366 DEBUG_LOG("Invalid format");
370 /* ================================================== */
373 NAU_CheckRequestAuth(NTP_Packet
*request
, NTP_PacketInfo
*info
, uint32_t *kod
)
377 switch (info
->auth
.mode
) {
380 case NTP_AUTH_SYMMETRIC
:
381 if (!check_symmetric_auth(request
, info
))
384 case NTP_AUTH_MSSNTP
:
385 /* MS-SNTP requests are not authenticated */
388 if (!NNS_CheckRequestAuth(request
, info
, kod
))
398 /* ================================================== */
401 NAU_AdjustResponseTimestamp(NTP_Packet
*request
, NTP_PacketInfo
*info
, struct timespec
*ts
)
403 adjust_timestamp(info
->auth
.mode
, info
->auth
.mac
.key_id
, ts
);
406 /* ================================================== */
409 NAU_GenerateResponseAuth(NTP_Packet
*request
, NTP_PacketInfo
*request_info
,
410 NTP_Packet
*response
, NTP_PacketInfo
*response_info
,
411 NTP_Remote_Address
*remote_addr
, NTP_Local_Address
*local_addr
,
414 switch (request_info
->auth
.mode
) {
417 case NTP_AUTH_SYMMETRIC
:
418 if (!generate_symmetric_auth(request_info
->auth
.mac
.key_id
, response
, response_info
))
421 case NTP_AUTH_MSSNTP
:
422 /* Sign the packet asynchronously by ntp_signd */
423 if (!NSD_SignAndSendPacket(request_info
->auth
.mac
.key_id
, response
, response_info
,
424 remote_addr
, local_addr
))
426 /* Don't send the original packet */
429 if (!NNS_GenerateResponseAuth(request
, request_info
, response
, response_info
, kod
))
433 DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info
->auth
.mode
);
440 /* ================================================== */
443 NAU_CheckResponseAuth(NAU_Instance instance
, NTP_Packet
*response
, NTP_PacketInfo
*info
)
445 /* The authentication must match the expected mode */
446 if (info
->auth
.mode
!= instance
->mode
)
449 switch (info
->auth
.mode
) {
452 case NTP_AUTH_SYMMETRIC
:
453 /* Check if it is authenticated with the specified key */
454 if (info
->auth
.mac
.key_id
!= instance
->key_id
)
456 /* and that the MAC is valid */
457 if (!check_symmetric_auth(response
, info
))
461 if (!NNC_CheckResponseAuth(instance
->nts
, response
, info
))
471 /* ================================================== */
474 NAU_ChangeAddress(NAU_Instance instance
, IPAddr
*address
)
476 switch (instance
->mode
) {
478 case NTP_AUTH_SYMMETRIC
:
481 NNC_ChangeAddress(instance
->nts
, address
);