Coverage Report

Created: 2026-01-10 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ntpsec/ntpd/nts_client.c
Line
Count
Source
1
/*
2
 * nts_client.c - Network Time Security (NTS) client side support
3
 * Copyright the NTPsec project contributors
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 *
6
 * Section references are to
7
 * https://tools.ietf.org/html/rfc8915
8
 *
9
 */
10
#include "config.h"
11
12
#include <ctype.h>
13
#include <sys/types.h>
14
#include <sys/socket.h>
15
#include <sys/stat.h>
16
#include <unistd.h>
17
#include <fcntl.h>
18
19
#ifdef HAVE_RES_INIT
20
#include <netinet/in.h>
21
#include <arpa/nameser.h>
22
#include <resolv.h>
23
#endif
24
25
#include <openssl/ssl.h>
26
#include <openssl/x509.h>
27
#include <openssl/x509v3.h>
28
29
#include "ntp_types.h"
30
#include "ntpd.h"
31
#include "nts.h"
32
#include "nts2.h"
33
#include "ntp_dns.h"
34
#include "ntp_stdlib.h"
35
#include "timespecops.h"
36
37
SSL_CTX* make_ssl_client_ctx(const char *filename);
38
int open_TCP_socket(struct peer *peer, const char *hostname);
39
struct addrinfo * find_best_addr(struct addrinfo *answer);
40
bool connect_TCP_socket(int sockfd, struct addrinfo *addr);
41
bool nts_set_cert_search(SSL_CTX *ctx, const char *filename);
42
void set_hostname(SSL *ssl, const char *hostname);
43
bool check_certificate(SSL *ssl, struct peer *peer);
44
bool check_alpn(SSL *ssl, struct peer *peer, const char *hostname);
45
bool nts_client_send_request(SSL *ssl, struct peer *peer);
46
bool nts_client_send_request_core(uint8_t *buff, int buf_size, int *used, struct peer* peer);
47
bool nts_client_process_response(SSL *ssl, struct peer *peer);
48
bool nts_client_process_response_core(uint8_t *buff, int transferred, struct peer* peer);
49
bool nts_server_lookup(char *server, sockaddr_u *addr, int af);
50
51
static SSL_CTX *client_ctx = NULL;
52
53
/* Ugly global variables passed from worker thread back to main thread. */
54
static sockaddr_u sockaddr;
55
static bool addrOK;
56
57
58
0
bool nts_client_init(void) {
59
60
0
  client_ctx = make_ssl_client_ctx(ntsconfig.ca);
61
62
63
/* Ugly global variables passed from worker thread back to main thread. */
64
0
  return true;
65
0
}
66
67
0
bool nts_probe(struct peer * peer) {
68
0
  struct timeval timeout = {.tv_sec = NTS_KE_TIMEOUT, .tv_usec = 0};
69
0
  const char *hostname = peer->hostname;
70
0
  char hostbuf[100];
71
0
  char errbuf[100];
72
0
  SSL     *ssl;
73
0
  int      server;
74
0
  struct timespec start, finish;
75
0
  int      err;
76
77
0
  if (NULL == client_ctx)
78
0
    return false;
79
80
0
  addrOK = false;
81
0
  clock_gettime(CLOCK_MONOTONIC, &start);
82
83
0
  if (NULL == hostname) {
84
    /* IP Address case */
85
0
    int af = AF(&peer->srcadr);
86
0
    switch (af) {
87
0
        case AF_INET:
88
0
      inet_ntop(af, PSOCK_ADDR4(&peer->srcadr), hostbuf, sizeof(hostbuf));
89
0
      break;
90
0
        case AF_INET6:
91
      /* Add [] in case [xxx]:port */
92
0
      hostbuf[0] = '[';
93
0
      inet_ntop(af, PSOCK_ADDR6(&peer->srcadr), hostbuf+1, sizeof(hostbuf)-1);
94
0
      strlcat(hostbuf, "]", sizeof(hostbuf));
95
0
      break;
96
0
        default:
97
0
      return false;
98
0
    }
99
0
    hostname = hostbuf;
100
//    msyslog(LOG_INFO, "NTSc: Address Literal: %s", hostbuf);
101
0
  }
102
103
0
  server = open_TCP_socket(peer, hostname);
104
0
  if (-1 == server) {
105
0
    ntske_cnt.probes_bad++;
106
0
    return false;
107
0
  }
108
109
0
  err = setsockopt(server, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
110
0
  if (0 > err) {
111
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
112
0
    msyslog(LOG_ERR, "NTSc: can't set recv timeout: %s", errbuf);
113
0
    close(server);
114
0
    ntske_cnt.probes_bad++;
115
0
    return false;
116
0
  }
117
0
  err = setsockopt(server, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
118
0
  if (0 > err) {
119
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
120
0
    msyslog(LOG_ERR, "NTSc: can't set send timeout: %s", errbuf);
121
0
    close(server);
122
0
    ntske_cnt.probes_bad++;
123
0
    return false;
124
0
  }
125
126
0
  if (NULL == peer->cfg.nts_cfg.ca)
127
0
    ssl = SSL_new(client_ctx);
128
0
  else {
129
0
    SSL_CTX *ctx;
130
0
    ctx = make_ssl_client_ctx(peer->cfg.nts_cfg.ca);
131
0
    if (NULL == ctx) {
132
0
      close(server);
133
0
      return false;
134
0
    }
135
0
    ssl = SSL_new(ctx);
136
0
    SSL_CTX_free(ctx);
137
0
  }
138
0
  set_hostname(ssl, hostname);
139
0
  SSL_set_fd(ssl, server);
140
141
0
  if (1 != SSL_connect(ssl)) {
142
0
    msyslog(LOG_INFO, "NTSc: SSL_connect failed");
143
0
    nts_log_ssl_error();
144
0
    goto bail;
145
0
  }
146
0
  if (1 != SSL_do_handshake(ssl)) {
147
0
    msyslog(LOG_INFO, "NTSc: SSL_do_handshake failed");
148
0
    nts_log_ssl_error();
149
0
    goto bail;
150
0
  }
151
152
  /* This may be clutter, but this is how to do it. */
153
0
  msyslog(LOG_INFO, "NTSc: Using %s, %s (%d)",
154
0
    SSL_get_version(ssl),
155
0
    SSL_get_cipher_name(ssl),
156
0
    SSL_get_cipher_bits(ssl, NULL));
157
158
0
  if (!check_certificate(ssl, peer))
159
0
    goto bail;
160
0
  if (!check_alpn(ssl, peer, hostname))
161
0
    goto bail;
162
163
0
  if (!nts_client_send_request(ssl, peer))
164
0
    goto bail;
165
0
  if (!nts_client_process_response(ssl, peer))
166
0
    goto bail;
167
168
  /* We are using AEAD_AES_SIV_CMAC_xxx, from RFC 5297
169
   * key length depends upon which key is selected */
170
0
  peer->nts_state.keylen = nts_get_key_length(peer->nts_state.aead);
171
0
  if (0 == peer->nts_state.keylen) {
172
0
    msyslog(LOG_ERR, "NTSc: Unknown AEAD code: %d", peer->nts_state.aead);
173
0
    goto bail;
174
0
  }
175
0
  if (!nts_make_keys(ssl,
176
0
         peer->nts_state.aead,
177
0
         peer->nts_state.c2s,
178
0
         peer->nts_state.s2c,
179
0
         peer->nts_state.keylen))
180
0
    goto bail;
181
182
0
  addrOK = true;
183
0
  ntske_cnt.probes_good++;
184
185
0
  bail:
186
0
  if (!addrOK) {
187
0
    ntske_cnt.probes_bad++;
188
0
    peer->nts_state.count = -1;
189
0
  }
190
0
  SSL_shutdown(ssl);
191
0
  SSL_free(ssl);
192
0
  close(server);
193
194
0
  clock_gettime(CLOCK_MONOTONIC, &finish);
195
0
  finish = sub_tspec(finish, start);
196
0
  msyslog(LOG_INFO, "NTSc: NTS-KE req to %s took %.3f sec, %s",
197
0
    hostname, tspec_to_d(finish),
198
0
    addrOK? "OK" : "fail");
199
200
0
  return addrOK;
201
0
}
202
203
0
bool nts_check(struct peer *peer) {
204
0
  if (0) {
205
0
    char errbuf[100];
206
0
    sockporttoa_r(&sockaddr, errbuf, sizeof(errbuf));
207
0
    msyslog(LOG_INFO, "NTSc: nts_check %s, %d", errbuf, addrOK);
208
0
  }
209
0
  if (addrOK) {
210
0
    dns_take_server(peer, &sockaddr);
211
0
    dns_take_status(peer, DNS_good);
212
0
  } else
213
0
    dns_take_status(peer, DNS_error);
214
0
  return addrOK;
215
0
}
216
217
0
SSL_CTX* make_ssl_client_ctx(const char * filename) {
218
0
  bool ok = true;
219
0
  SSL_CTX *ctx;
220
221
0
  ctx = SSL_CTX_new(TLS_client_method());
222
0
  if (NULL == ctx) {
223
    /* Happens if no ciphers */
224
0
    msyslog(LOG_ERR, "NTSc: NULL ctx");
225
0
    nts_log_ssl_error();
226
0
    return NULL;
227
0
  }
228
229
0
  {
230
    // 4., ALPN, RFC 7301
231
0
    static unsigned char alpn [] = { 7, 'n', 't', 's', 'k', 'e', '/', '1' };
232
0
    SSL_CTX_set_alpn_protos(ctx, alpn, sizeof(alpn));
233
0
  }
234
235
0
  SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
236
0
  SSL_CTX_set_timeout(ctx, NTS_KE_TIMEOUT);   /* session lifetime */
237
238
0
  ok &= nts_load_versions(ctx);
239
0
  ok &= nts_load_ciphers(ctx);
240
0
  ok &= nts_load_ecdhcurves(ctx);
241
0
  ok &= nts_set_cert_search(ctx, filename);
242
243
0
  if (!ok) {
244
0
    msyslog(LOG_ERR, "NTSc: Troubles setting up client SSL CTX");
245
0
    SSL_CTX_free(ctx);
246
0
    return NULL;
247
0
  };
248
249
0
  return ctx;
250
0
}
251
252
/* FIXME - split out DNS work. */
253
254
/* Note that there are 2 DNS lookups.
255
 *   One for the NTS-KE server and another for the NTP server.
256
 *   The latter is optional.
257
 *   The default is to use the same IP Address as NTS-KE server.
258
 *
259
 * In the non-NTS case, when a server name returns multiple addresses,
260
 * we skip the ones that are already in use.
261
 *
262
 * If the NTS-KE server has multiple addresses, we also skip the ones
263
 * that are already in use for NTP.  That works great if the NTS-KE server
264
 * is running on the same system as the NTP server which is true
265
 * for most servers.
266
 */
267
268
/* return -1 on error */
269
0
int open_TCP_socket(struct peer *peer, const char *hostname) {
270
0
  char host[256], port[32];
271
0
  char errbuf[100];
272
0
  char *tmp;
273
0
  struct addrinfo hints;
274
0
  struct addrinfo *answer, *worker;
275
0
  int gai_rc;
276
0
  int sockfd;
277
0
  struct timespec start, finish;
278
279
  /* FIXME -- const bug in OpenSSL */
280
0
  strlcpy(host, hostname, sizeof(host));
281
282
  /* handle xxx:port case */
283
0
  if ('[' == host[0]) {
284
    /* IPv6 case, drop [], start search after ] */
285
0
    SET_AF(&peer->srcadr, AF_INET6);
286
0
    strlcpy(host, hostname+1, sizeof(host));
287
0
    tmp = strchr(host, ']');
288
0
    if (NULL == tmp) {
289
0
      msyslog(LOG_ERR, "NTSc: open_TCP_socket: missing ']': %s",
290
0
        hostname);
291
0
      return -1;
292
0
    }
293
0
    *tmp++ = 0;
294
    /* We have chopped off the [] around the host literal.
295
     * There should be nothing left or :<port> */
296
0
    if ((0 != *tmp) && (':' != *tmp)) {
297
0
      msyslog(LOG_ERR, "NTSc: open_TCP_socket: missing ':': %s",
298
0
        hostname);
299
0
      return -1;
300
0
    }
301
0
    if (0 == *tmp) tmp = NULL; /* no : */
302
0
  } else {
303
0
    tmp = strchr(host, ':');
304
0
  }
305
0
  if (NULL == tmp) {
306
    /* simple case, no : */
307
0
    strlcpy(port, NTS_KE_PORTA, sizeof(port));
308
0
  } else {
309
    /* Complicated case, found a : */
310
0
    *tmp++ = 0;
311
0
    strlcpy(port, tmp, sizeof(port));
312
0
    msyslog(LOG_INFO, "NTSc: open_TCP_socket: found port %s", port);
313
0
  }
314
315
0
  ZERO(hints);
316
0
  hints.ai_protocol = IPPROTO_TCP;
317
0
  hints.ai_socktype = SOCK_STREAM;
318
0
  hints.ai_family = AF(&peer->srcadr);  /* -4, -6 switch */
319
0
  clock_gettime(CLOCK_MONOTONIC, &start);
320
0
  gai_rc = getaddrinfo(host, port, &hints, &answer);
321
0
  if (0 != gai_rc) {
322
0
    msyslog(LOG_INFO, "NTSc: open_TCP_socket: DNS error trying to contact %s, %d, %s",
323
0
      hostname, gai_rc, gai_strerror(gai_rc));
324
0
    return -1;
325
0
  }
326
0
  clock_gettime(CLOCK_MONOTONIC, &finish);
327
0
  finish = sub_tspec(finish, start);
328
0
  msyslog(LOG_INFO, "NTSc: DNS lookup of %s (%d) took %.3f sec",
329
0
    hostname, hints.ai_family, tspec_to_d(finish));
330
331
  /* sockaddr is global for NTP address
332
   * also use as temp for printing here */
333
0
  if (NULL == peer->hostname) {
334
    /* Address literal case, use first/only answer */
335
0
    worker = answer;
336
0
  } else {
337
0
    worker = find_best_addr(answer);
338
0
    if (NULL == worker) {
339
0
      msyslog(LOG_INFO, "NTSc: All addresses in use.");
340
0
      freeaddrinfo(answer);
341
0
      return -1;
342
0
    }
343
0
  }
344
0
  memcpy(&sockaddr, worker->ai_addr, worker->ai_addrlen);
345
0
  sockporttoa_r(&sockaddr, errbuf, sizeof(errbuf));
346
0
  msyslog(LOG_INFO, "NTSc: connecting to %s+%s => %s",
347
0
    host, port, errbuf);
348
349
  /* setup default NTP port now
350
   *   in case of server-name:port later on
351
   */
352
0
  SET_PORT(&sockaddr, NTP_PORT);
353
0
  sockfd = socket(worker->ai_family, SOCK_STREAM, 0);
354
0
  if (-1 == sockfd) {
355
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
356
0
    msyslog(LOG_INFO, "NTSc: open_TCP_socket: no socket: %s", errbuf);
357
0
  } else {
358
0
    if (!connect_TCP_socket(sockfd, worker)) {
359
0
      close(sockfd);
360
0
      sockfd = -1;
361
0
    }
362
0
  }
363
364
0
  freeaddrinfo(answer);
365
0
  return sockfd;
366
367
0
}
368
369
0
struct addrinfo *find_best_addr(struct addrinfo *answer) {
370
0
  for ( ; NULL != answer; answer = answer->ai_next) {
371
0
    sockaddr_u addr;
372
0
    struct peer *pp;
373
0
    if (sizeof(sockaddr_u) < answer->ai_addrlen)
374
0
      continue;  /* Weird */
375
0
    memcpy(&addr, answer->ai_addr, answer->ai_addrlen);
376
    /* findexistingpeer checks port too */
377
0
    for (pp = peer_list; NULL != pp; pp = pp->p_link) {
378
0
      if (MDF_POOL & pp->cast_flags) continue;
379
0
      if (FLAG_LOOKUP & pp->cfg.flags) continue;
380
0
      if (SOCK_EQ(&addr, &pp->srcadr)) break;
381
0
    }
382
0
    if (NULL != pp) {
383
0
      char errbuf[200];
384
0
      socktoa_r(&addr, errbuf, sizeof(errbuf));
385
0
      msyslog(LOG_INFO, "NTSc: Skipping %s", errbuf);
386
0
      continue;  /* already in use */
387
0
    }
388
0
    break; 
389
0
  }
390
0
  return(answer);
391
0
}
392
393
394
/* This kludgery is needed to get a sane timeout.
395
 * The default is unspecified but long.
396
 * On Linux, man connect gets man 2 which doesn't mention O_NONBLOCK
397
 * Use man 3 connect.
398
 */
399
0
bool connect_TCP_socket(int sockfd, struct addrinfo *addr) {
400
0
  char errbuf[100];
401
0
  int err;
402
0
  fd_set fdset;
403
0
  struct timeval timeout;
404
0
  int so_error;
405
0
  socklen_t so_len = sizeof(so_error);
406
407
0
  err = fcntl(sockfd, F_SETFL, O_NONBLOCK);
408
0
  if (-1 == err) {
409
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
410
0
    msyslog(LOG_INFO, "NTSc: can't set O_NONBLOCK %s", errbuf);
411
0
    return false;
412
0
  }
413
0
  err = connect(sockfd, addr->ai_addr, addr->ai_addrlen);
414
  /* The normal case is -1 and errno == EINPROGRESS
415
   * Getting connected should be possible if the scheduler
416
   * avoids us for long enough.
417
   * Other errors may be possible.  No route?
418
   * I haven't seen that yet.  HGM, 2020 Jan 19
419
   */
420
0
  if (-1 != err || EINPROGRESS != errno) {
421
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
422
0
    msyslog(LOG_INFO, "NTSc: connect_TCP_socket: connect failed: %s", errbuf);
423
0
    return false;
424
0
  }
425
426
0
  FD_ZERO(&fdset);
427
0
  FD_SET(sockfd, &fdset);
428
0
  timeout.tv_sec = NTS_KE_TIMEOUT;
429
0
  timeout.tv_usec = 0;
430
431
0
  if (0 == select(sockfd + 1, NULL, &fdset, NULL, &timeout)) {
432
0
    msyslog(LOG_INFO, "NTSc: connect_TCP_socket: timeout");
433
0
    return false;
434
0
  }
435
436
  /* It's ready, either connected or error. */
437
0
  if (-1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &so_len)) {
438
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
439
0
    msyslog(LOG_INFO, "NTSc: connect_TCP_socket: getsockopt failed: %s", errbuf);
440
0
    return false;
441
0
  }
442
443
0
  if (0 != so_error) {
444
0
    ntp_strerror_r(so_error, errbuf, sizeof(errbuf));
445
0
    msyslog(LOG_INFO, "NTSc: connect_TCP_socket: connect failed: %s", errbuf);
446
0
    return false;
447
0
  }
448
449
0
  err = fcntl(sockfd, F_SETFL, 0); /* turn off O_NONBLOCK */
450
0
  if (-1 == err) {
451
0
    ntp_strerror_r(errno, errbuf, sizeof(errbuf));
452
0
    msyslog(LOG_INFO, "NTSc: can't unset O_NONBLOCK %s", errbuf);
453
0
    return false;
454
0
  }
455
456
0
  return true;
457
0
}
458
459
460
0
void set_hostname(SSL *ssl, const char *hostname) {
461
0
  char host[256], *tmp;
462
463
  /* chop off trailing :port */
464
0
  strlcpy(host, hostname, sizeof(host));
465
0
  tmp = strchr(host, ']');
466
0
  if (NULL == tmp) {
467
0
    tmp = host;     /* not IPv6 [...] format */
468
0
  }
469
0
  tmp = strchr(tmp, ':');
470
0
  if (NULL != tmp) {
471
0
    *tmp = 0;
472
0
  }
473
474
/* https://wiki.openssl.org/index.php/Hostname_validation
475
 * draft-ietf-uta-rfc6125bis section 3 relaxes the restrictions around the use
476
 * of wildcards to make it clear that they're permitted unless specifically
477
 * prohibited in an RFC
478
 */
479
0
  SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
480
0
  SSL_set1_host(ssl, host);
481
0
  msyslog(LOG_DEBUG, "NTSc: set cert host: %s", host);
482
483
0
}
484
485
486
// X509v3 Subject Alternative Name:
487
//    DNS:*.time.nl, DNS:time.nl
488
489
0
bool check_certificate(SSL *ssl, struct peer* peer) {
490
0
  X509 *cert = SSL_get_peer_certificate(ssl);
491
0
  X509_NAME *certname;
492
0
  GENERAL_NAMES *gens;
493
0
  char name[200];
494
0
  int certok;
495
0
  int numgens = 0;
496
497
0
  if (NULL == cert) {
498
0
    msyslog(LOG_INFO, "NTSc: No certificate");
499
0
    if (!(FLAG_NTS_NOVAL & peer->cfg.flags))
500
0
      return false;
501
0
    return true;
502
0
  }
503
504
0
  certname = X509_get_subject_name(cert);
505
0
  X509_NAME_oneline(certname, name, sizeof(name));
506
0
  msyslog(LOG_INFO, "NTSc: certificate subject name: %s", name);
507
0
  certname = X509_get_issuer_name(cert);
508
0
  X509_NAME_oneline(certname, name, sizeof(name));
509
0
  msyslog(LOG_INFO, "NTSc: certificate issuer name: %s", name);
510
  /* print SAN:DNS strings */
511
0
  gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
512
0
  if (gens) {
513
0
    char buff[150];
514
0
    numgens = sk_GENERAL_NAME_num(gens);
515
0
    buff[0] = 0;
516
0
    for (int i = 0; i<numgens; i++) {
517
0
      const GENERAL_NAME *gen;
518
0
      const char *dnsname;
519
0
      unsigned int len;
520
0
      gen = sk_GENERAL_NAME_value(gens, i);
521
0
      if (gen->type != GEN_DNS)
522
0
        continue;
523
      // string is NUL terminated but may have internal NULs
524
0
      len = (unsigned int)ASN1_STRING_length(gen->d.ia5);
525
0
      dnsname = (const char *)ASN1_STRING_get0_data(gen->d.ia5);
526
0
      if (0 != buff[0])
527
0
        strlcat(buff, ", ", sizeof(buff));
528
0
      strlcat(buff, dnsname, sizeof(buff));
529
0
      if (len != strlen(dnsname))
530
0
        strlcat(buff, "??", sizeof(buff));
531
0
    }
532
0
    msyslog(LOG_INFO, "NTSc: SAN:DNS %s", buff);
533
0
    GENERAL_NAMES_free(gens);
534
0
  }
535
0
  if (0 == numgens) {
536
0
    const char *peername = SSL_get0_peername(ssl);
537
0
    msyslog(LOG_INFO, "NTSc: matching with subject:CN %s", peername);
538
0
  } else if (1 > numgens) {
539
0
    const char *peername = SSL_get0_peername(ssl);
540
0
    msyslog(LOG_INFO, "NTSc: matching with SAN:DNS: %s", peername);
541
0
  }
542
0
  X509_free(cert);
543
0
  certok = SSL_get_verify_result(ssl);
544
0
  if (X509_V_OK == certok) {
545
0
    msyslog(LOG_INFO, "NTSc: certificate is valid.");
546
0
  } else {
547
0
    msyslog(LOG_ERR, "NTSc: certificate invalid: %d=>%s",
548
0
      certok, X509_verify_cert_error_string(certok));
549
0
    if (FLAG_NTS_NOVAL & peer->cfg.flags) {
550
0
      msyslog(LOG_INFO, "NTSc: noval - accepting invalid cert.");
551
0
      return true;
552
0
    }
553
0
    return false;
554
0
  }
555
0
  return true;
556
0
}
557
558
0
bool check_alpn(SSL *ssl, struct peer* peer, const char *hostname) {
559
0
  UNUSED_ARG(peer);
560
0
  const unsigned char *data;
561
0
  unsigned int len;
562
0
  SSL_get0_alpn_selected(ssl, &data, &len);
563
0
  if (0 == len) {
564
0
    msyslog(LOG_DEBUG, "NTSc: No ALPN from %s (%s)",
565
0
      hostname, SSL_get_version(ssl));
566
0
    return false;
567
0
  }
568
  /* For now, we only support one version.
569
   * This will get more complicated when version 2 arrives. */
570
0
  if (len != 7 ||
571
0
      0 != memcmp(data, "ntske/1", len)) {
572
    /* copy data over so we can print it. */
573
    /* don't read past end of data */
574
0
    unsigned int i, l;
575
0
    char buff [16];
576
0
    l = min(len, sizeof(buff)-1);
577
0
    memcpy(buff, data, l);
578
0
    buff[l] = '\0';
579
0
    for (i=0; i<l; i++) {
580
0
      if (!isgraph((int)buff[i])) {
581
0
        buff[i] = '*'; /* fix non-printing crap */
582
0
      }
583
0
    }
584
0
    msyslog(LOG_DEBUG, "NTSc: Strange ALPN %s (%u) from %s",
585
0
      buff, len, hostname);
586
0
    return false;
587
0
  }
588
0
  msyslog(LOG_DEBUG, "NTSc: Good ALPN from %s", hostname);
589
590
0
  return true;
591
0
}
592
593
594
0
bool nts_make_keys(SSL *ssl, uint16_t aead, uint8_t *c2s, uint8_t *s2c, int keylen) {
595
0
  const char *label = "EXPORTER-network-time-security";
596
0
  unsigned char context[5];
597
0
  context[0] = (nts_protocol_NTP >> 8) & 0xFF;
598
0
  context[1] = nts_protocol_NTP & 0xFF;
599
0
  context[2] = (aead >> 8) & 0xFF;
600
0
  context[3] = aead & 0xFF;
601
0
  context[4] = 0x00;
602
0
  if (1 != SSL_export_keying_material(ssl, c2s, keylen,
603
0
              label, strlen(label),
604
0
              context, 5, 1)) {
605
0
    msyslog(LOG_ERR, "NTS: Error making c2s\n");
606
0
    nts_log_ssl_error();
607
0
    return false;
608
0
  }
609
0
  context[4] = 0x01;
610
0
  if (1 != SSL_export_keying_material(ssl, s2c, keylen,
611
0
              label, strlen(label),
612
0
              context, 5, 1)) {
613
0
    msyslog(LOG_ERR, "NTS: Error making s2c\n");
614
0
    nts_log_ssl_error();
615
0
    return false;
616
0
  }
617
0
  return true;
618
0
}
619
620
0
bool nts_client_send_request(SSL *ssl, struct peer* peer) {
621
0
  uint8_t buff[1000];
622
0
  int     used, transferred;
623
0
  bool    success;
624
0
  const char *errtxt = NULL;
625
626
0
  success = nts_client_send_request_core(buff, sizeof(buff), &used, peer);
627
0
  if (!success) {
628
0
    return false;
629
0
  }
630
631
0
  transferred = nts_ssl_write(ssl, buff, used, &errtxt);
632
0
  if (used != transferred)
633
0
    return false;
634
635
0
  return true;
636
0
}
637
638
0
bool nts_client_send_request_core(uint8_t *buff, int buf_size, int *used, struct peer* peer) {
639
0
  struct  BufCtl_t buf;
640
0
  uint16_t aead = NO_AEAD;
641
642
0
  buf.next = buff;
643
0
  buf.left = buf_size;
644
645
  /* 4.1.2 Next Protocol, 0 for NTP */
646
0
  ke_append_record_uint16(&buf,
647
0
        NTS_CRITICAL+nts_next_protocol_negotiation, nts_protocol_NTP);
648
649
  /* 4.1.5 AEAD Algorithm List */
650
  // FIXME should be : separated list
651
652
0
  if ((NO_AEAD == aead) && (NULL != peer->cfg.nts_cfg.aead))
653
0
    aead = nts_string_to_aead(peer->cfg.nts_cfg.aead);
654
0
  if ((NO_AEAD == aead) && (NULL != ntsconfig.aead))
655
0
    aead = nts_string_to_aead(ntsconfig.aead);
656
0
  if (NO_AEAD == aead)
657
0
    aead = AEAD_AES_SIV_CMAC_256;
658
0
  ke_append_record_uint16(&buf, nts_algorithm_negotiation, aead);
659
660
  /* 4.1.1: End, Critical */
661
0
  ke_append_record_null(&buf, NTS_CRITICAL+nts_end_of_message);
662
663
0
  *used = buf_size-buf.left;
664
0
  if (*used >= (int)(buf_size - 10)) {
665
0
    msyslog(LOG_ERR, "ERR-NTSc: buffer overflow: %d, %ld",
666
0
      *used, (long)buf_size);
667
0
    exit(2);
668
0
  }
669
0
  return true;
670
0
}
671
672
0
bool nts_client_process_response(SSL *ssl, struct peer* peer) {
673
0
  uint8_t  buff[2048];  /* RFC 4. says SHOULD be 65K */
674
0
  int transferred;
675
0
  const char *errtxt = NULL;
676
677
0
  transferred = nts_ssl_read(ssl, buff, sizeof(buff), &errtxt);
678
0
  if (0 >= transferred)
679
0
    return false;
680
0
  msyslog(LOG_ERR, "NTSc: read %d bytes", transferred);
681
682
0
  return nts_client_process_response_core(buff, transferred, peer);
683
0
}
684
685
268
bool nts_client_process_response_core(uint8_t *buff, int transferred, struct peer* peer) {
686
268
  int idx;
687
268
  struct BufCtl_t buf;
688
689
268
  peer->nts_state.cookielen = 0;
690
268
  peer->nts_state.aead = NO_AEAD;
691
268
  peer->nts_state.keylen = 0;
692
268
  peer->nts_state.writeIdx = 0;
693
268
  peer->nts_state.readIdx = 0;
694
268
  peer->nts_state.count = 0;
695
696
268
  buf.next = buff;
697
268
  buf.left = transferred;
698
2.54k
  while (buf.left >= NTS_KE_HDR_LNG) {
699
2.47k
    uint16_t type, data, port;
700
2.47k
    bool critical = false;
701
2.47k
    int length, keylength;
702
2.47k
    char errbuf[100];
703
2.47k
#define MAX_SERVER 100
704
2.47k
    char server[MAX_SERVER];
705
706
2.47k
    type = ke_next_record(&buf, &length);
707
2.47k
    if (length > buf.left){
708
34
      msyslog(LOG_ERR, "NTSc: Chunk too big: 0x%x, %d, %d", 
709
34
        type, buf.left, length);
710
34
      return false;
711
34
    }
712
2.44k
    if (NTS_CRITICAL & type) {
713
1.09k
      critical = true;
714
1.09k
      type &= ~NTS_CRITICAL;
715
1.09k
    }
716
2.44k
    if (0) // Handy for debugging but very verbose
717
0
      msyslog(LOG_ERR, "NTSc: Record: T=%d, L=%d, C=%d", type, length, critical);
718
2.44k
    switch (type) {
719
12
        case nts_error:
720
12
      if (sizeof(data) != length) {
721
10
        msyslog(LOG_ERR, "NTSc: wrong length on error: %d", length);
722
10
        return false;
723
10
      }
724
2
      data = next_uint16(&buf);
725
2
      msyslog(LOG_ERR, "NTSc: error: %d", data);
726
2
      return false;
727
249
        case nts_next_protocol_negotiation:
728
249
      if (sizeof(data) != length) {
729
10
        msyslog(LOG_ERR, "NTSc: NPN-Wrong length: %d", length);
730
10
        return false;
731
10
      }
732
239
      data = next_uint16(&buf);
733
239
      if (data != nts_protocol_NTP) {
734
19
        msyslog(LOG_ERR, "NTSc: NPN-Bad data: %d", data);
735
19
        return false;
736
19
      }
737
220
      break;
738
239
        case nts_algorithm_negotiation:
739
239
      if (sizeof(data) != length) {
740
9
        msyslog(LOG_ERR, "NTSc: AN-Wrong length: %d", length);
741
9
        return false;
742
9
      }
743
230
      data = next_uint16(&buf);
744
230
      keylength = nts_get_key_length(data);
745
230
      if (0 == keylength) {
746
16
        msyslog(LOG_ERR, "NTSc: AN-Unsupported AEAN type: %d", data);
747
16
        return false;
748
16
      }
749
214
      peer->nts_state.aead = data;
750
214
      break;
751
896
        case nts_new_cookie:
752
896
      if (NTS_MAX_COOKIELEN < length) {
753
6
        msyslog(LOG_ERR, "NTSc: NC cookie too big: %d", length);
754
6
        return false;
755
6
      }
756
890
      if (0 == peer->nts_state.cookielen)
757
624
        peer->nts_state.cookielen = length;
758
890
      if (length != peer->nts_state.cookielen) {
759
23
        msyslog(LOG_ERR, "NTSc: Cookie length mismatch %d, %d.",
760
23
          length, peer->nts_state.cookielen);
761
23
        return false;
762
23
      }
763
867
      idx = peer->nts_state.writeIdx;
764
867
      if (NTS_MAX_COOKIES <= peer->nts_state.count) {
765
573
        msyslog(LOG_ERR, "NTSc: Extra cookie ignored.");
766
573
        break;
767
573
      }
768
294
      next_bytes(&buf, (uint8_t*)&peer->nts_state.cookies[idx], length);
769
294
      peer->nts_state.writeIdx++;
770
294
      peer->nts_state.writeIdx = peer->nts_state.writeIdx % NTS_MAX_COOKIES;
771
294
      peer->nts_state.count++;
772
294
      break;
773
384
        case nts_server_negotiation:
774
384
      if (MAX_SERVER < (length+1)) {
775
4
        msyslog(LOG_ERR, "NTSc: server string too long %d.", length);
776
4
        return false;
777
4
      }
778
380
      next_bytes(&buf, (uint8_t *)server, length);
779
380
      server[length] = '\0';
780
      /* save port in case port specified before server */
781
380
      port = SRCPORT(&sockaddr);
782
380
      if (!nts_server_lookup(server, &sockaddr, AF(&peer->srcadr)))
783
20
        return false;
784
360
      SET_PORT(&sockaddr, port);
785
360
      socktoa_r(&sockaddr, errbuf, sizeof(errbuf));
786
360
      msyslog(LOG_ERR, "NTSc: Using server %s=>%s", server, errbuf);
787
360
      break;
788
214
        case nts_port_negotiation:
789
214
      if (sizeof(port) != length) {
790
10
        msyslog(LOG_ERR, "NTSc: PN-Wrong length: %d, %d",
791
10
          length, critical);
792
10
        return false;
793
10
      }
794
204
      port = next_uint16(&buf);
795
204
      SET_PORT(&sockaddr, port);
796
204
      msyslog(LOG_ERR, "NTSc: Using port %d", port);
797
204
      break;
798
27
        case nts_end_of_message:
799
27
      if ((0 != length) || !critical) {
800
12
        msyslog(LOG_ERR, "NTSc: EOM-Wrong length or not Critical: %d, %d",
801
12
          length, critical);
802
12
        return false;
803
12
      }
804
15
      if (0 != buf.left) {
805
13
        msyslog(LOG_ERR, "NTSc: EOM not at end: %d", buf.left);
806
13
        return false;
807
13
      }
808
2
      break;
809
421
        default:
810
421
      msyslog(LOG_ERR, "NTSc: received strange type: T=%d, C=%d, L=%d",
811
421
        type, critical, length);
812
421
      if (critical) {
813
9
        return false;
814
9
      }
815
412
      buf.next += length;
816
412
      buf.left -= length;
817
412
      break;
818
2.44k
    } /* case */
819
2.44k
  }   /* while */
820
821
//  FIXME: Need to check for EOM -- read more??
822
71
  if (buf.left > 0)
823
9
    return false;
824
825
62
  if (NO_AEAD == peer->nts_state.aead) {
826
51
    msyslog(LOG_ERR, "NTSc: No AEAD algorithm.");
827
51
    return false;
828
51
  }
829
11
  if (0 == peer->nts_state.count) {
830
8
    msyslog(LOG_ERR, "NTSc: No cookies.");
831
8
    return false;
832
8
  }
833
834
3
  msyslog(LOG_ERR, "NTSc: Got %d cookies, length %d, aead=%d.",
835
3
    peer->nts_state.count, peer->nts_state.cookielen, peer->nts_state.aead);
836
3
  return true;
837
11
}
838
839
0
bool nts_set_cert_search(SSL_CTX *ctx, const char *filename) {
840
0
  struct stat statbuf;
841
0
  char errbuf[100];
842
0
  if (NULL == filename) {
843
0
    msyslog(LOG_INFO, "NTSc: Using system default root certificates.");
844
0
    SSL_CTX_set_default_verify_paths(ctx);   // Use system root certs
845
0
    return true;
846
0
  }
847
0
  if (0 == stat(filename, &statbuf)) {
848
0
    if (S_ISDIR(statbuf.st_mode)) {
849
0
      if (1 != SSL_CTX_load_verify_locations(
850
0
        ctx, NULL, filename)) {
851
0
      msyslog(LOG_INFO, "NTSc: Can't use %s as dir for root certificates.", filename);
852
0
          nts_log_ssl_error();
853
0
          return false;
854
0
      }
855
0
      msyslog(LOG_INFO, "NTSc: Using dir %s for root certificates.", filename);
856
0
      return true;
857
0
    }
858
0
    if (S_ISREG(statbuf.st_mode)) {
859
0
      if (1 != SSL_CTX_load_verify_locations(
860
0
        ctx, filename, NULL)) {
861
0
          msyslog(LOG_INFO, "NTSc: Can't use %s as file for root certificates.", filename);
862
0
          nts_log_ssl_error();
863
0
          return false;
864
0
      }
865
0
      msyslog(LOG_INFO, "NTSc: Using file %s for root certificates.", filename);
866
0
      return true;
867
0
    }
868
0
    msyslog(LOG_ERR, "NTSc: cert dir/file isn't dir or file: %s. mode 0x%x",
869
0
      filename, statbuf.st_mode);
870
0
    return false;
871
0
  }
872
0
  ntp_strerror_r(errno, errbuf, sizeof(errbuf));
873
0
  msyslog(LOG_ERR, "NTSc: can't stat cert dir/file: %s, %s",
874
0
    filename, errbuf);
875
0
  return false;
876
0
}
877
/* The -4/-6 option is used for both the NTS-KE server and the NTP server.
878
 * That will break if the KE server returns a name that returns only an
879
 * address of the other type.
880
 * We could fix that by trying again with AF_UNSPEC.
881
 */
882
380
bool nts_server_lookup(char *server, sockaddr_u *addr, int af) {
883
380
  struct addrinfo hints;
884
380
  struct addrinfo *answer = NULL;  /* init to keep oss-fuzz happy */
885
380
  int gai_rc;
886
887
380
  ZERO(hints);
888
380
  hints.ai_protocol = IPPROTO_UDP;
889
380
  hints.ai_socktype = SOCK_DGRAM;
890
380
  hints.ai_family = af;
891
892
380
  gai_rc = getaddrinfo(server, NTS_KE_PORTA, &hints, &answer);
893
380
  if (0 != gai_rc) {
894
20
    msyslog(LOG_INFO, "NTSc: DNS error trying to lookup %s: %d, %s",
895
20
      server, gai_rc, gai_strerror(gai_rc));
896
20
    return false;
897
20
  }
898
899
360
  if (NULL == answer)
900
0
    return false;
901
902
360
  if (sizeof(sockaddr_u) >= answer->ai_addrlen)
903
360
    memcpy(addr, answer->ai_addr, answer->ai_addrlen);
904
905
360
  freeaddrinfo(answer);
906
907
  return true;
908
360
}
909
910
/* end */