]> git.ipfire.org Git - thirdparty/chrony.git/blob - ntp_auth.c
ntp: fix log message for replaced source
[thirdparty/chrony.git] / ntp_auth.c
1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2019
6 *
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.
10 *
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.
15 *
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.
19 *
20 **********************************************************************
21
22 =======================================================================
23
24 NTP authentication
25 */
26
27 #include "config.h"
28
29 #include "sysincl.h"
30
31 #include "keys.h"
32 #include "logging.h"
33 #include "memory.h"
34 #include "ntp_auth.h"
35 #include "ntp_ext.h"
36 #include "ntp_signd.h"
37 #include "nts_ntp.h"
38 #include "nts_ntp_client.h"
39 #include "nts_ntp_server.h"
40 #include "srcparams.h"
41 #include "util.h"
42
43 /* Structure to hold authentication configuration and state */
44
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 */
49 };
50
51 /* ================================================== */
52
53 static int
54 generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info)
55 {
56 int auth_len, max_auth_len;
57
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);
62
63 auth_len = KEY_GenerateAuth(key_id, (unsigned char *)packet, info->length,
64 (unsigned char *)packet + info->length + 4, max_auth_len);
65 if (!auth_len) {
66 DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
67 return 0;
68 }
69
70 *(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
71 info->length += 4 + auth_len;
72
73 return 1;
74 }
75
76 /* ================================================== */
77
78 static int
79 check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
80 {
81 int trunc_len;
82
83 if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
84 return 0;
85
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;
88
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))
92 return 0;
93
94 return 1;
95 }
96
97 /* ================================================== */
98
99 static void
100 adjust_timestamp(NTP_AuthMode mode, uint32_t key_id, struct timespec *ts)
101 {
102 switch (mode) {
103 case NTP_AUTH_SYMMETRIC:
104 ts->tv_nsec += KEY_GetAuthDelay(key_id);
105 UTI_NormaliseTimespec(ts);
106 break;
107 case NTP_AUTH_MSSNTP:
108 ts->tv_nsec += NSD_GetAuthDelay(key_id);
109 UTI_NormaliseTimespec(ts);
110 default:
111 break;
112 }
113 }
114
115 /* ================================================== */
116
117 static int
118 is_zero_data(unsigned char *data, int length)
119 {
120 int i;
121
122 for (i = 0; i < length; i++)
123 if (data[i])
124 return 0;
125 return 1;
126 }
127
128 /* ================================================== */
129
130 static NAU_Instance
131 create_instance(NTP_AuthMode mode)
132 {
133 NAU_Instance instance;
134
135 instance = MallocNew(struct NAU_Instance_Record);
136 instance->mode = mode;
137 instance->key_id = INACTIVE_AUTHKEY;
138 instance->nts = NULL;
139
140 assert(sizeof (instance->key_id) == 4);
141
142 return instance;
143 }
144
145 /* ================================================== */
146
147 NAU_Instance
148 NAU_CreateNoneInstance(void)
149 {
150 return create_instance(NTP_AUTH_NONE);
151 }
152
153 /* ================================================== */
154
155 NAU_Instance
156 NAU_CreateSymmetricInstance(uint32_t key_id)
157 {
158 NAU_Instance instance = create_instance(NTP_AUTH_SYMMETRIC);
159
160 instance->key_id = key_id;
161
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");
166
167 return instance;
168 }
169
170 /* ================================================== */
171
172 NAU_Instance
173 NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *ntp_address)
174 {
175 NAU_Instance instance = create_instance(NTP_AUTH_NTS);
176
177 instance->nts = NNC_CreateInstance(nts_address, name, ntp_address);
178
179 return instance;
180 }
181
182 /* ================================================== */
183
184 void
185 NAU_DestroyInstance(NAU_Instance instance)
186 {
187 if (instance->nts)
188 NNC_DestroyInstance(instance->nts);
189 Free(instance);
190 }
191
192 /* ================================================== */
193
194 int
195 NAU_IsAuthEnabled(NAU_Instance instance)
196 {
197 return instance->mode != NTP_AUTH_NONE;
198 }
199
200 /* ================================================== */
201
202 int
203 NAU_GetSuggestedNtpVersion(NAU_Instance instance)
204 {
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)
209 return 3;
210
211 return NTP_VERSION;
212 }
213
214 /* ================================================== */
215
216 int
217 NAU_PrepareRequestAuth(NAU_Instance instance)
218 {
219 switch (instance->mode) {
220 case NTP_AUTH_NTS:
221 if (!NNC_PrepareForAuth(instance->nts))
222 return 0;
223 break;
224 default:
225 break;
226 }
227
228 return 1;
229 }
230
231 /* ================================================== */
232
233 void
234 NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *ts)
235 {
236 adjust_timestamp(instance->mode, instance->key_id, ts);
237 }
238
239 /* ================================================== */
240
241 int
242 NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
243 {
244 switch (instance->mode) {
245 case NTP_AUTH_NONE:
246 break;
247 case NTP_AUTH_SYMMETRIC:
248 if (!generate_symmetric_auth(instance->key_id, request, info))
249 return 0;
250 break;
251 case NTP_AUTH_NTS:
252 if (!NNC_GenerateRequestAuth(instance->nts, request, info))
253 return 0;
254 break;
255 default:
256 assert(0);
257 }
258
259 return 1;
260 }
261
262 /* ================================================== */
263
264 int
265 NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
266 {
267 int parsed, remainder, ef_length, ef_type;
268 unsigned char *data;
269
270 data = (void *)packet;
271 parsed = NTP_HEADER_LENGTH;
272 remainder = info->length - parsed;
273
274 info->ext_fields = 0;
275
276 /* Check if this is a plain NTP packet with no extension fields or MAC */
277 if (remainder <= 0)
278 return 1;
279
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));
287
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;
295 }
296
297 return 1;
298 }
299
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;
306 return 1;
307 }
308
309 /* Parse the rest of the NTPv4 packet */
310
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)
314 break;
315
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))
325 break;
326
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");
331 return 0;
332 }
333
334 assert(ef_length > 0);
335
336 switch (ef_type) {
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;
342 break;
343 default:
344 DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
345 }
346
347 info->ext_fields++;
348 parsed += ef_length;
349 remainder = info->length - parsed;
350 }
351
352 if (remainder == 0) {
353 /* No MAC */
354 return 1;
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
358 length */
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));
363 return 1;
364 }
365
366 DEBUG_LOG("Invalid format");
367 return 0;
368 }
369
370 /* ================================================== */
371
372 int
373 NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
374 {
375 *kod = 0;
376
377 switch (info->auth.mode) {
378 case NTP_AUTH_NONE:
379 break;
380 case NTP_AUTH_SYMMETRIC:
381 if (!check_symmetric_auth(request, info))
382 return 0;
383 break;
384 case NTP_AUTH_MSSNTP:
385 /* MS-SNTP requests are not authenticated */
386 break;
387 case NTP_AUTH_NTS:
388 if (!NNS_CheckRequestAuth(request, info, kod))
389 return 0;
390 break;
391 default:
392 return 0;
393 }
394
395 return 1;
396 }
397
398 /* ================================================== */
399
400 void
401 NAU_AdjustResponseTimestamp(NTP_Packet *request, NTP_PacketInfo *info, struct timespec *ts)
402 {
403 adjust_timestamp(info->auth.mode, info->auth.mac.key_id, ts);
404 }
405
406 /* ================================================== */
407
408 int
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,
412 uint32_t kod)
413 {
414 switch (request_info->auth.mode) {
415 case NTP_AUTH_NONE:
416 break;
417 case NTP_AUTH_SYMMETRIC:
418 if (!generate_symmetric_auth(request_info->auth.mac.key_id, response, response_info))
419 return 0;
420 break;
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))
425 return 0;
426 /* Don't send the original packet */
427 return 0;
428 case NTP_AUTH_NTS:
429 if (!NNS_GenerateResponseAuth(request, request_info, response, response_info, kod))
430 return 0;
431 break;
432 default:
433 DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info->auth.mode);
434 return 0;
435 }
436
437 return 1;
438 }
439
440 /* ================================================== */
441
442 int
443 NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response, NTP_PacketInfo *info)
444 {
445 /* The authentication must match the expected mode */
446 if (info->auth.mode != instance->mode)
447 return 0;
448
449 switch (info->auth.mode) {
450 case NTP_AUTH_NONE:
451 break;
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)
455 return 0;
456 /* and that the MAC is valid */
457 if (!check_symmetric_auth(response, info))
458 return 0;
459 break;
460 case NTP_AUTH_NTS:
461 if (!NNC_CheckResponseAuth(instance->nts, response, info))
462 return 0;
463 break;
464 default:
465 return 0;
466 }
467
468 return 1;
469 }
470
471 /* ================================================== */
472
473 void
474 NAU_ChangeAddress(NAU_Instance instance, IPAddr *address)
475 {
476 switch (instance->mode) {
477 case NTP_AUTH_NONE:
478 case NTP_AUTH_SYMMETRIC:
479 break;
480 case NTP_AUTH_NTS:
481 NNC_ChangeAddress(instance->nts, address);
482 break;
483 default:
484 assert(0);
485 }
486 }