]> git.ipfire.org Git - thirdparty/chrony.git/blame - nts_ntp_server.c
ntp: add server support for KoD RATE
[thirdparty/chrony.git] / nts_ntp_server.c
CommitLineData
6043632f
ML
1/*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5f66722b 5 * Copyright (C) Miroslav Lichvar 2020, 2022
6043632f
ML
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 Server NTS-NTP authentication
25 */
26
27#include "config.h"
28
29#include "sysincl.h"
30
31#include "nts_ntp_server.h"
32
33#include "conf.h"
34#include "logging.h"
35#include "memory.h"
36#include "ntp.h"
37#include "ntp_ext.h"
38#include "nts_ke_server.h"
39#include "nts_ntp.h"
40#include "nts_ntp_auth.h"
41#include "siv.h"
42#include "util.h"
43
790a336e 44#define MAX_SERVER_SIVS 2
adcf0734 45
6043632f 46struct NtsServer {
790a336e
ML
47 SIV_Instance sivs[MAX_SERVER_SIVS];
48 SIV_Algorithm siv_algorithms[MAX_SERVER_SIVS];
6043632f
ML
49 unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
50 NKE_Cookie cookies[NTS_MAX_COOKIES];
51 int num_cookies;
790a336e 52 int siv_index;
6043632f
ML
53 NTP_int64 req_tx;
54};
55
56/* The server instance handling all requests */
57struct NtsServer *server;
58
59/* ================================================== */
60
61void
62NNS_Initialise(void)
63{
90557cf1 64 const char **certs, **keys;
790a336e 65 int i;
90557cf1 66
6043632f 67 /* Create an NTS-NTP server instance only if NTS-KE server is enabled */
90557cf1 68 if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0) {
6043632f
ML
69 server = NULL;
70 return;
71 }
72
73 server = Malloc(sizeof (struct NtsServer));
790a336e
ML
74
75 server->siv_algorithms[0] = AEAD_AES_SIV_CMAC_256;
76 server->siv_algorithms[1] = AEAD_AES_128_GCM_SIV;
77 assert(MAX_SERVER_SIVS == 2);
78
79 for (i = 0; i < 2; i++)
80 server->sivs[i] = SIV_CreateInstance(server->siv_algorithms[i]);
81
82 /* AES-SIV-CMAC-256 is required on servers */
83 if (!server->sivs[0])
84 LOG_FATAL("Missing AES-SIV-CMAC-256");
6043632f
ML
85}
86
87/* ================================================== */
88
89void
90NNS_Finalise(void)
91{
790a336e
ML
92 int i;
93
6043632f
ML
94 if (!server)
95 return;
96
790a336e
ML
97 for (i = 0; i < MAX_SERVER_SIVS; i++) {
98 if (server->sivs[i])
99 SIV_DestroyInstance(server->sivs[i]);
100 }
6043632f
ML
101 Free(server);
102 server = NULL;
103}
104
105/* ================================================== */
106
107int
108NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
109{
110 int ef_type, ef_body_length, ef_length, has_uniq_id = 0, has_auth = 0, has_cookie = 0;
111 int i, plaintext_length, parsed, requested_cookies, cookie_length = -1, auth_start = 0;
112 unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
adcf0734 113 NKE_Context context;
6043632f 114 NKE_Cookie cookie;
790a336e 115 SIV_Instance siv;
6043632f
ML
116 void *ef_body;
117
f020d479
ML
118 *kod = 0;
119
6043632f
ML
120 if (!server)
121 return 0;
122
6043632f 123 server->num_cookies = 0;
790a336e 124 server->siv_index = -1;
6043632f
ML
125 server->req_tx = packet->transmit_ts;
126
127 if (info->ext_fields == 0 || info->mode != MODE_CLIENT)
128 return 0;
129
130 requested_cookies = 0;
131
132 for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
133 if (!NEF_ParseField(packet, info->length, parsed,
134 &ef_length, &ef_type, &ef_body, &ef_body_length))
d48f0128
ML
135 /* This is not expected as the packet already passed NAU_ParsePacket() */
136 return 0;
6043632f
ML
137
138 switch (ef_type) {
139 case NTP_EF_NTS_UNIQUE_IDENTIFIER:
140 has_uniq_id = 1;
141 break;
142 case NTP_EF_NTS_COOKIE:
d48f0128
ML
143 if (has_cookie || ef_body_length > sizeof (cookie.cookie)) {
144 DEBUG_LOG("Unexpected cookie/length");
6043632f 145 return 0;
d48f0128 146 }
6043632f
ML
147 cookie.length = ef_body_length;
148 memcpy(cookie.cookie, ef_body, ef_body_length);
149 has_cookie = 1;
150 /* Fall through */
151 case NTP_EF_NTS_COOKIE_PLACEHOLDER:
152 requested_cookies++;
153
154 if (cookie_length >= 0 && cookie_length != ef_body_length) {
155 DEBUG_LOG("Invalid cookie/placeholder length");
156 return 0;
157 }
158 cookie_length = ef_body_length;
159 break;
160 case NTP_EF_NTS_AUTH_AND_EEF:
de4ecc72
ML
161 if (parsed + ef_length != info->length) {
162 DEBUG_LOG("Auth not last EF");
163 return 0;
164 }
165
6043632f
ML
166 auth_start = parsed;
167 has_auth = 1;
168 break;
169 default:
170 break;
171 }
172 }
173
174 if (!has_uniq_id || !has_cookie || !has_auth) {
175 DEBUG_LOG("Missing an NTS EF");
176 return 0;
177 }
178
adcf0734 179 if (!NKS_DecodeCookie(&cookie, &context)) {
6043632f
ML
180 *kod = NTP_KOD_NTS_NAK;
181 return 0;
182 }
183
790a336e
ML
184 /* Find the SIV instance needed for authentication */
185 for (i = 0; i < MAX_SERVER_SIVS && context.algorithm != server->siv_algorithms[i]; i++)
186 ;
187 if (i == MAX_SERVER_SIVS || !server->sivs[i]) {
adcf0734
ML
188 DEBUG_LOG("Unexpected SIV");
189 return 0;
190 }
790a336e
ML
191 server->siv_index = i;
192 siv = server->sivs[i];
adcf0734 193
790a336e 194 if (!SIV_SetKey(siv, context.c2s.key, context.c2s.length)) {
6043632f
ML
195 DEBUG_LOG("Could not set C2S key");
196 return 0;
197 }
198
790a336e 199 if (!NNA_DecryptAuthEF(packet, info, siv, auth_start,
6043632f
ML
200 plaintext, sizeof (plaintext), &plaintext_length)) {
201 *kod = NTP_KOD_NTS_NAK;
202 return 0;
203 }
204
205 for (parsed = 0; parsed < plaintext_length; parsed += ef_length) {
206 if (!NEF_ParseSingleField(plaintext, plaintext_length, parsed,
fd8fbcd0
ML
207 &ef_length, &ef_type, &ef_body, &ef_body_length)) {
208 DEBUG_LOG("Could not parse encrypted EF");
209 return 0;
210 }
6043632f
ML
211
212 switch (ef_type) {
213 case NTP_EF_NTS_COOKIE_PLACEHOLDER:
214 if (cookie_length != ef_body_length) {
215 DEBUG_LOG("Invalid cookie/placeholder length");
216 return 0;
217 }
218 requested_cookies++;
219 break;
220 default:
221 break;
222 }
223 }
224
790a336e 225 if (!SIV_SetKey(siv, context.s2c.key, context.s2c.length)) {
6043632f
ML
226 DEBUG_LOG("Could not set S2C key");
227 return 0;
228 }
229
d48f0128
ML
230 /* Prepare data for NNS_GenerateResponseAuth() to minimise the time spent
231 there (when the TX timestamp is already set) */
232
6043632f
ML
233 UTI_GetRandomBytes(server->nonce, sizeof (server->nonce));
234
d48f0128
ML
235 assert(sizeof (server->cookies) / sizeof (server->cookies[0]) == NTS_MAX_COOKIES);
236 for (i = 0; i < NTS_MAX_COOKIES && i < requested_cookies; i++)
adcf0734 237 if (!NKS_GenerateCookie(&context, &server->cookies[i]))
6043632f
ML
238 return 0;
239
d48f0128
ML
240 server->num_cookies = i;
241
6043632f
ML
242 return 1;
243}
244
245/* ================================================== */
246
247int
248NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
249 NTP_Packet *response, NTP_PacketInfo *res_info,
250 uint32_t kod)
251{
252 int i, ef_type, ef_body_length, ef_length, parsed;
253 void *ef_body;
254 unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
255 int plaintext_length;
256
257 if (!server || req_info->mode != MODE_CLIENT || res_info->mode != MODE_SERVER)
258 return 0;
259
d48f0128
ML
260 /* Make sure this is a response to the request from the last call
261 of NNS_CheckRequestAuth() */
6043632f
ML
262 if (UTI_CompareNtp64(&server->req_tx, &request->transmit_ts) != 0)
263 assert(0);
264
265 for (parsed = NTP_HEADER_LENGTH; parsed < req_info->length; parsed += ef_length) {
266 if (!NEF_ParseField(request, req_info->length, parsed,
267 &ef_length, &ef_type, &ef_body, &ef_body_length))
36356ef0 268 /* This is not expected as the packet already passed parsing */
d48f0128 269 return 0;
6043632f
ML
270
271 switch (ef_type) {
272 case NTP_EF_NTS_UNIQUE_IDENTIFIER:
273 /* Copy the ID from the request */
274 if (!NEF_AddField(response, res_info, ef_type, ef_body, ef_body_length))
275 return 0;
276 default:
277 break;
278 }
279 }
280
281 /* NTS NAK response does not have any other fields */
ce956c99 282 if (kod == NTP_KOD_NTS_NAK)
6043632f
ML
283 return 1;
284
285 for (i = 0, plaintext_length = 0; i < server->num_cookies; i++) {
286 if (!NEF_SetField(plaintext, sizeof (plaintext), plaintext_length,
d48f0128 287 NTP_EF_NTS_COOKIE, server->cookies[i].cookie,
6043632f
ML
288 server->cookies[i].length, &ef_length))
289 return 0;
290
291 plaintext_length += ef_length;
292 assert(plaintext_length <= sizeof (plaintext));
293 }
294
295 server->num_cookies = 0;
296
790a336e
ML
297 if (server->siv_index < 0)
298 return 0;
299
d48f0128
ML
300 /* Generate an authenticator field which will make the length
301 of the response equal to the length of the request */
790a336e 302 if (!NNA_GenerateAuthEF(response, res_info, server->sivs[server->siv_index],
6043632f
ML
303 server->nonce, sizeof (server->nonce),
304 plaintext, plaintext_length,
305 req_info->length - res_info->length))
306 return 0;
307
308 return 1;
309}