Coverage Report

Created: 2026-04-12 06:54

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