Coverage Report

Created: 2026-09-14 06:46

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