blob: ca90e91a2d2c41b262209e87a22707db727526ff [file] [log] [blame]
Christian Grothoff90e9f832012-02-07 11:16:47 +01001/* Copyright (c) 2012, Jacob Appelbaum.
Jacob Appelbaum63e548e2012-07-29 16:25:30 -07002 * Copyright (c) 2012, The Tor Project, Inc.
3 * Copyright (c) 2012, Christian Grothoff. */
Christian Grothoff90e9f832012-02-07 11:16:47 +01004/* See LICENSE for licensing information */
5/*
6 This file contains the license for tlsdate,
7 a free software project to set your system clock securely.
8
9 It also lists the licenses for other components used by tlsdate.
10
11 For more information about tlsdate, see https://github.com/ioerror/tlsdate
12
13 If you got this file as a part of a larger bundle,
14 there may be other license terms that you should be aware of.
15
16===============================================================================
17tlsdate is distributed under this license:
18
19Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
20Copyright (c) 2011-2012, The Tor Project, Inc.
21
22Redistribution and use in source and binary forms, with or without
23modification, are permitted provided that the following conditions are
24met:
25
26 * Redistributions of source code must retain the above copyright
27notice, this list of conditions and the following disclaimer.
28
29 * Redistributions in binary form must reproduce the above
30copyright notice, this list of conditions and the following disclaimer
31in the documentation and/or other materials provided with the
32distribution.
33
34 * Neither the names of the copyright owners nor the names of its
35contributors may be used to endorse or promote products derived from
36this software without specific prior written permission.
37
38THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49===============================================================================
50If you got tlsdate as a static binary with OpenSSL included, then you should
51know:
52
53 "This product includes software developed by the OpenSSL Project for use in
54 the OpenSSL Toolkit (http://www.openssl.org/)"
55
56===============================================================================
57*/
58
59/**
Christian Grothoffe267c352012-02-14 01:10:54 +010060 * \file tlsdate-helper.c
61 * \brief Helper program that does the actual work of setting the system clock.
Christian Grothoff90e9f832012-02-07 11:16:47 +010062 **/
63
64/*
65 * tlsdate is a tool for setting the system clock by hand or by communication
66 * with the network. It does not set the RTC. It is designed to be as secure as
67 * TLS (RFC 2246) but of course the security of TLS is often reduced to
68 * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
69 * your local CA root store - so any of these companies could assist in a MITM
70 * attack against you and you'd be screwed.
71
72 * This tool is designed to be run by hand or as a system daemon. It must be
73 * run as root or otherwise have the proper caps; it will not be able to set
74 * the system time without running as root or another privileged user.
75 */
76
Brian Akerb12abad2012-10-16 01:25:00 -040077#include "config.h"
Andreea Costinas6d6944a2019-03-27 15:29:09 +010078
Daniel Kurtza2d82d52019-06-07 15:26:54 -060079#include "src/openssl_compat.h"
Brian Akerb12abad2012-10-16 01:25:00 -040080#include "src/tlsdate-helper.h"
Christian Grothoff90e9f832012-02-07 11:16:47 +010081
Andreea Costinas6d6944a2019-03-27 15:29:09 +010082#include <errno.h>
83#include <netdb.h>
84#include <stdlib.h>
85#include <sys/types.h>
86#include <sys/socket.h>
87
Jacob Appelbaumfa765302013-01-18 15:47:47 +010088#include "src/proxy-bio.h"
Ben Chancc6af4b2019-04-11 14:13:08 -070089#include "src/util.h"
Brian Akerb12abad2012-10-16 01:25:00 -040090#include "src/compat/clock.h"
Elly Jones9ae3aa62012-06-20 15:32:46 -040091
Andreea Costinas6d6944a2019-03-27 15:29:09 +010092static int g_ca_racket;
93
94static const char *g_ca_cert_container;
95
96// Target host to connect to.
97static const char *g_host;
98
99// Port to connect to on the target host.
100static const char *g_port;
101
102// The SSL/TLS protocol used
103static const char *g_protocol;
104
105// Proxy with format scheme://proxy_host:proxy_port.
106static char *g_proxy;
107
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400108static void
Will Drewryc45952f2013-09-03 13:51:24 -0500109validate_proxy_scheme (const char *scheme)
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400110{
Will Drewryc45952f2013-09-03 13:51:24 -0500111 if (!strcmp (scheme, "http"))
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400112 return;
Will Drewryc45952f2013-09-03 13:51:24 -0500113 if (!strcmp (scheme, "socks4"))
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400114 return;
Will Drewryc45952f2013-09-03 13:51:24 -0500115 if (!strcmp (scheme, "socks5"))
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400116 return;
Will Drewryc45952f2013-09-03 13:51:24 -0500117 die ("invalid proxy scheme\n");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400118}
119
120static void
Will Drewryc45952f2013-09-03 13:51:24 -0500121validate_proxy_host (const char *host)
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400122{
123 const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
124 "abcdefghijklmnopqrstuvwxyz"
125 "0123456789"
126 ".-";
Will Drewryc45952f2013-09-03 13:51:24 -0500127 if (strspn (host, kValid) != strlen (host))
128 die ("invalid char in host\n");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400129}
130
131static void
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100132validate_port (const char *port)
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400133{
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100134 if (!port)
135 return;
136 char *end;
137 const int kBase = 10;
138 unsigned long value = strtoul(port, &end, kBase);
139 if (errno != 0 || value > SHRT_MAX || value == 0 || *end != '\0')
140 die("invalid port %s\n", port);
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400141}
142
143static void
Will Drewryc45952f2013-09-03 13:51:24 -0500144parse_proxy_uri (char *proxy, char **scheme, char **host, char **port)
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400145{
146 /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
147 *scheme = proxy;
Will Drewryc45952f2013-09-03 13:51:24 -0500148 proxy = strstr (proxy, "://");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400149 if (!proxy)
Will Drewryc45952f2013-09-03 13:51:24 -0500150 die ("malformed proxy URI\n");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400151 *proxy = '\0'; /* terminate scheme string */
Will Drewryc45952f2013-09-03 13:51:24 -0500152 proxy += strlen ("://");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400153 *host = proxy;
Will Drewryc45952f2013-09-03 13:51:24 -0500154 proxy = strchr (proxy, ':');
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400155 if (!proxy)
Will Drewryc45952f2013-09-03 13:51:24 -0500156 die ("malformed proxy URI\n");
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400157 *proxy++ = '\0';
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400158 *port = proxy;
Will Drewryc45952f2013-09-03 13:51:24 -0500159 validate_proxy_scheme (*scheme);
160 validate_proxy_host (*host);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100161 validate_port (*port);
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400162}
163
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100164/* Returns a BIO that talks through a HTTP proxy using the CONNECT command.
165 * The created BIO will ask the proxy to CONNECT to |target_host|:|target_port|
166 * using |scheme|.
167 */
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400168static BIO *
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100169BIO_create_proxy (const char *scheme, const char *target_host,
170 const char *target_port)
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400171{
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100172 BIO *bio_proxy = BIO_new_proxy ();
173 BIO_proxy_set_type (bio_proxy, scheme);
174 BIO_proxy_set_target_host (bio_proxy, target_host);
175 BIO_proxy_set_target_port (bio_proxy, atoi (target_port));
176 return bio_proxy;
177}
178
Pavol Markod9dd19d2020-01-17 23:32:57 +0100179static void
180addr_to_str (const struct sockaddr *addr, char* dest,
181 socklen_t size)
182{
183 struct sockaddr_in* addr_ipv4 = NULL;
184 struct sockaddr_in6* addr_ipv6 = NULL;
185 memset (dest, '\0', size);
186 if (addr->sa_family == AF_INET) {
187 addr_ipv4 = (struct sockaddr_in*)addr;
188 inet_ntop (AF_INET, &addr_ipv4->sin_addr, dest, size);
189 return;
190 }
191 if (addr->sa_family == AF_INET6) {
192 addr_ipv6 = (struct sockaddr_in6*)addr;
193 inet_ntop (AF_INET6, &addr_ipv6->sin6_addr, dest, size);
194 return;
195 }
196 verb ("V: unknown sa_family %hu\n", addr->sa_family);
197}
198
Michael Ershov2012e5b2021-03-25 13:18:13 +0100199static int
200get_addrinfo_length (struct addrinfo *addr_infos) {
201 int result = 0;
202 for (struct addrinfo *iter = addr_infos; iter; iter = iter->ai_next) {
203 ++result;
204 }
205 return result;
206}
207
208static struct addrinfo *
209get_addrinfo_element (struct addrinfo *addr_infos, int index) {
210 int current_index = 0;
211 for (struct addrinfo *iter = addr_infos; iter; iter = iter->ai_next) {
212 if (current_index == index) {
213 return iter;
214 }
215 ++current_index;
216 }
217 return NULL;
218}
219
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100220/* Connects to |host| on port |port|.
221 * Returns the socket file descriptor if successful, otherwise exits with
222 * failure.
223 */
Michael Ershov2012e5b2021-03-25 13:18:13 +0100224static int
225create_connection (const char *host, const char *port)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100226{
Michael Ershov2012e5b2021-03-25 13:18:13 +0100227 int sock = -1;
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100228 struct addrinfo hints = {
229 .ai_flags = AI_ADDRCONFIG,
230 .ai_family = AF_UNSPEC,
231 .ai_socktype = SOCK_STREAM,
232 };
Pavol Markod9dd19d2020-01-17 23:32:57 +0100233 // Use INET6_ADDRSTRLEN for the buffer holding IP addresses as it will always
234 // be longer than INET_ADDRSTRLEN.
235 char addr_str_buf[INET6_ADDRSTRLEN];
236 memset (addr_str_buf, '\0', INET6_ADDRSTRLEN);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100237
Michael Ershov2012e5b2021-03-25 13:18:13 +0100238 struct addrinfo *addr_infos = NULL;
239 int err = getaddrinfo (host, port, &hints, &addr_infos);
240 if (err != 0 || !addr_infos)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100241 die ("getaddrinfo (%s): %s\n", host, gai_strerror (err));
242
Michael Ershov5fb1b3b2021-04-30 13:47:40 +0200243 // tlsdate is killed by a supervisor if it takes too long to finish. So it
244 // may not have time to try all the addresses. Selecting the start point
245 // randomly makes it try different addresses during different attempts, that
246 // is useful when some addresses are not accessible (e.g. first ones).
Michael Ershov2012e5b2021-03-25 13:18:13 +0100247 int list_length = get_addrinfo_length (addr_infos);
Michael Ershov5fb1b3b2021-04-30 13:47:40 +0200248 int start_index = random () % list_length;
249
Michael Ershov2012e5b2021-03-25 13:18:13 +0100250 for (int i = 0; i < list_length; ++i)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100251 {
Michael Ershov2012e5b2021-03-25 13:18:13 +0100252 struct addrinfo *current_addr_info =
Michael Ershov5fb1b3b2021-04-30 13:47:40 +0200253 get_addrinfo_element (addr_infos, (start_index + i) % list_length);
Michael Ershov2012e5b2021-03-25 13:18:13 +0100254 if (!current_addr_info) {
255 die ("attempted to use NULL addrinfo");
256 }
257
258 addr_to_str (current_addr_info->ai_addr, addr_str_buf, INET6_ADDRSTRLEN);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100259 verb ("V: attempting to connect to %s\n", addr_str_buf);
Michael Ershov2012e5b2021-03-25 13:18:13 +0100260 sock = socket (current_addr_info->ai_family, SOCK_STREAM, 0);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100261 if (sock < 0)
262 {
263 perror ("socket");
264 continue;
265 }
266
Michael Ershov2012e5b2021-03-25 13:18:13 +0100267 if (connect (sock, current_addr_info->ai_addr,
268 current_addr_info->ai_addrlen) != 0)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100269 {
270 perror ("connect");
271 close (sock);
272 sock = -1;
273 continue;
274 }
275 break;
276 }
Michael Ershov2012e5b2021-03-25 13:18:13 +0100277 freeaddrinfo (addr_infos);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100278
279 if (sock < 0)
280 die ("failed to find any remote addresses for %s:%s\n", host, port);
281
282 return sock;
283}
284
285/* Creates a BIO wrapper over the socket connection to |host|:|port|.
286 * This workaround is needed because BIO_s_connect() doesn't support IPv6.
287 */
288static BIO *BIO_create_socket (const char *host, const char *port)
289{
290 BIO *bio_socket = NULL;
291 int sockfd = create_connection (host, port);
292 if ( !(bio_socket = BIO_new_fd (sockfd, 1 /* close_flag */)))
293 die ("BIO_new_fd failed\n");
294
295 return bio_socket;
296}
297
298/* Creates an OpenSSL BIO-chain which talks to |target_host|:|target_port|
299 * using the SSL protocol. If |proxy| is set it will be used as a HTTP proxy.
300 */
301static BIO *
302make_ssl_bio (SSL_CTX *ctx, const char *target_host, const char *target_port,
303 char *proxy)
304{
305 BIO *bio_socket = NULL;
306 BIO *bio_ssl = NULL;
307 BIO *bio_proxy = NULL;
308 char *scheme = NULL;
309 char *proxy_host = NULL;
310 char *proxy_port = NULL;
311
312 if ( !(bio_ssl = BIO_new_ssl (ctx, 1)))
Will Drewryc45952f2013-09-03 13:51:24 -0500313 die ("BIO_new_ssl failed\n");
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100314
315 if (proxy)
316 {
317 verb ("V: using proxy %s\n", proxy);
318 parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
319
320 if ( !(bio_proxy = BIO_create_proxy (scheme, target_host, target_port)))
321 die ("BIO_create_proxy failed\n");
322
323 bio_socket = BIO_create_socket (proxy_host, proxy_port);
324
325 BIO_push (bio_ssl, bio_proxy);
326 BIO_push (bio_ssl, bio_socket);
327 }
328 else
329 {
330 bio_socket = BIO_create_socket (target_host, target_port);
331 BIO_push (bio_ssl, bio_socket);
332 }
333 return bio_ssl;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400334}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100335
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200336/** helper function for 'malloc' */
337static void *
338xmalloc (size_t size)
339{
340 void *ptr;
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200341 if (0 == size)
Will Drewryc45952f2013-09-03 13:51:24 -0500342 die ("xmalloc: zero size\n");
343 ptr = malloc (size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200344 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500345 die ("xmalloc: out of memory (allocating %zu bytes)\n", size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200346 return ptr;
347}
348
349
350/** helper function for 'free' */
351static void
352xfree (void *ptr)
353{
Daniel Borkmann592acc52012-07-30 14:08:02 +0200354 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500355 die ("xfree: NULL pointer given as argument\n");
356 free (ptr);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200357}
358
359
David Benjamin1aba54c2017-02-05 16:24:49 -0500360static int
361verify_with_server_time (X509_STORE_CTX *store_ctx, void *arg)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700362{
David Benjamin1aba54c2017-02-05 16:24:49 -0500363 SSL *ssl = X509_STORE_CTX_get_ex_data (
364 store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
365
366 // XXX TODO: If we want to trust the remote system for time,
367 // can we just read that time out of the remote system and if the
368 // cert verifies, decide that the time is reasonable?
369 // Such a process seems to indicate that a once valid cert would be
370 // forever valid - we stopgap that by ensuring it isn't less than
371 // the latest compiled_time and isn't above max_reasonable_time...
372 // XXX TODO: Solve eternal question about the Chicken and the Egg...
373 uint32_t compiled_time = RECENT_COMPILE_DATE;
374 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
375 uint32_t server_time;
376 verb ("V: freezing time for x509 verification\n");
377 SSL_get_server_random(ssl, (unsigned char *)&server_time,
378 sizeof (uint32_t));
379 if (compiled_time < ntohl (server_time)
380 &&
381 ntohl (server_time) < max_reasonable_time)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700382 {
David Benjamin1aba54c2017-02-05 16:24:49 -0500383 verb ("V: remote peer provided: %d, preferred over compile time: %d\n",
384 ntohl (server_time), compiled_time);
385 verb ("V: freezing time with X509_VERIFY_PARAM_set_time\n");
386 X509_STORE_CTX_set_time (
387 store_ctx, 0, (time_t) ntohl (server_time) + 86400);
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700388 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500389 else
390 {
391 die ("V: the remote server is a false ticker! server: %d compile: %d\n",
392 ntohl (server_time), compiled_time);
393 }
394
395 return X509_verify_cert (store_ctx);
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700396}
397
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700398uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700399get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700400{
401 /*
402 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
403 */
404 uint32_t key_bits;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600405 switch (EVP_PKEY_id (public_key))
Will Drewryc45952f2013-09-03 13:51:24 -0500406 {
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700407 case EVP_PKEY_RSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500408 verb ("V: key type: EVP_PKEY_RSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700409 break;
410 case EVP_PKEY_RSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500411 verb ("V: key type: EVP_PKEY_RSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700412 break;
413 case EVP_PKEY_DSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500414 verb ("V: key type: EVP_PKEY_DSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700415 break;
416 case EVP_PKEY_DSA1:
Will Drewryc45952f2013-09-03 13:51:24 -0500417 verb ("V: key type: EVP_PKEY_DSA1\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700418 break;
419 case EVP_PKEY_DSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500420 verb ("V: key type: EVP_PKEY_DSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700421 break;
422 case EVP_PKEY_DSA3:
Will Drewryc45952f2013-09-03 13:51:24 -0500423 verb ("V: key type: EVP_PKEY_DSA3\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700424 break;
425 case EVP_PKEY_DSA4:
Will Drewryc45952f2013-09-03 13:51:24 -0500426 verb ("V: key type: EVP_PKEY_DSA4\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700427 break;
428 case EVP_PKEY_DH:
Will Drewryc45952f2013-09-03 13:51:24 -0500429 verb ("V: key type: EVP_PKEY_DH\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700430 break;
431 case EVP_PKEY_EC:
Will Drewryc45952f2013-09-03 13:51:24 -0500432 verb ("V: key type: EVP_PKEY_EC\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700433 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500434 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700435 default:
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700436 die ("unknown public key type\n");
437 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500438 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600439 key_bits = EVP_PKEY_bits (public_key);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700440 verb ("V: keybits: %d\n", key_bits);
441 return key_bits;
442}
443
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700444uint32_t
Will Drewryc45952f2013-09-03 13:51:24 -0500445dns_label_count (char *label, char *delim)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700446{
447 char *label_tmp;
448 char *saveptr;
449 char *saveptr_tmp;
450 uint32_t label_count;
Will Drewryc45952f2013-09-03 13:51:24 -0500451 label_tmp = strdup (label);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700452 label_count = 0;
453 saveptr = NULL;
454 saveptr_tmp = NULL;
Will Drewryc45952f2013-09-03 13:51:24 -0500455 saveptr = strtok_r (label_tmp, delim, &saveptr);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700456 if (NULL != saveptr)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700457 {
Will Drewryc45952f2013-09-03 13:51:24 -0500458 // Did we find our first label?
459 if (saveptr[0] != delim[0])
460 {
461 label_count++;
462 verb ("V: label found; total label count: %d\n", label_count);
463 }
464 do
465 {
466 // Find all subsequent labels
467 label_count++;
468 saveptr_tmp = strtok_r (NULL, delim, &saveptr);
469 verb ("V: label found; total label count: %d\n", label_count);
470 }
471 while (NULL != saveptr_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700472 }
Will Drewryc45952f2013-09-03 13:51:24 -0500473 free (label_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700474 return label_count;
475}
476
477// first we split strings on '.'
478// then we call each split string a 'label'
479// Do not allow '*' for the top level domain label; eg never allow *.*.com
480// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
481// Do allow *.example.com
482uint32_t
483check_wildcard_match_rfc2595 (const char *orig_hostname,
Will Drewryc45952f2013-09-03 13:51:24 -0500484 const char *orig_cert_wild_card)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700485{
486 char *hostname;
487 char *hostname_to_free;
488 char *cert_wild_card;
489 char *cert_wild_card_to_free;
490 char *expected_label;
491 char *wildcard_label;
492 char *delim;
493 char *wildchar;
494 uint32_t ok;
495 uint32_t wildcard_encountered;
496 uint32_t label_count;
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700497 // First we copy the original strings
Will Drewryc45952f2013-09-03 13:51:24 -0500498 hostname = strndup (orig_hostname, strlen (orig_hostname));
499 cert_wild_card = strndup (orig_cert_wild_card, strlen (orig_cert_wild_card));
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700500 hostname_to_free = hostname;
501 cert_wild_card_to_free = cert_wild_card;
Will Drewryc45952f2013-09-03 13:51:24 -0500502 delim = strdup (".");
503 wildchar = strdup ("*");
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700504 verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
Will Drewryc45952f2013-09-03 13:51:24 -0500505 hostname, cert_wild_card);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700506 // By default we have not processed any labels
Will Drewryc45952f2013-09-03 13:51:24 -0500507 label_count = dns_label_count (cert_wild_card, delim);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700508 // By default we have no match
509 ok = 0;
510 wildcard_encountered = 0;
511 // First - do we have labels? If not, we refuse to even try to match
Will Drewryc45952f2013-09-03 13:51:24 -0500512 if ( (NULL != strpbrk (cert_wild_card, delim)) &&
513 (NULL != strpbrk (hostname, delim)) &&
514 (label_count <= ( (uint32_t) RFC2595_MIN_LABEL_COUNT)))
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700515 {
Will Drewryc45952f2013-09-03 13:51:24 -0500516 if (wildchar[0] == cert_wild_card[0])
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700517 {
Will Drewryc45952f2013-09-03 13:51:24 -0500518 verb ("V: Found wildcard in at start of provided certificate name\n");
519 do
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700520 {
Will Drewryc45952f2013-09-03 13:51:24 -0500521 // Skip over the bytes between the first char and until the next label
522 wildcard_label = strsep (&cert_wild_card, delim);
523 expected_label = strsep (&hostname, delim);
524 if (NULL != wildcard_label &&
525 NULL != expected_label &&
526 NULL != hostname &&
527 NULL != cert_wild_card)
528 {
529 // Now we only consider this wildcard valid if the rest of the
530 // hostnames match verbatim
531 verb ("V: Attempting match of '%s' against '%s'\n",
532 expected_label, wildcard_label);
533 // This is the case where we have a label that begins with wildcard
534 // Furthermore, we only allow this for the first label
535 if (wildcard_label[0] == wildchar[0] &&
536 0 == wildcard_encountered && 0 == ok)
537 {
538 verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
539 wildcard_encountered = 1;
540 }
541 else
542 {
543 verb ("V: Attempting match of '%s' against '%s'\n",
544 hostname, cert_wild_card);
545 if (0 == strcasecmp (expected_label, wildcard_label) &&
546 label_count >= ( (uint32_t) RFC2595_MIN_LABEL_COUNT))
547 {
548 ok = 1;
549 verb ("V: remaining labels match!\n");
550 break;
551 }
552 else
553 {
554 ok = 0;
555 verb ("V: remaining labels do not match!\n");
556 break;
557 }
558 }
559 }
560 else
561 {
562 // We hit this case when we have a mismatched number of labels
563 verb ("V: NULL label; no wildcard here\n");
564 break;
565 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700566 }
Will Drewryc45952f2013-09-03 13:51:24 -0500567 while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700568 }
Will Drewryc45952f2013-09-03 13:51:24 -0500569 else
570 {
571 verb ("V: Not a RFC 2595 wildcard\n");
572 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700573 }
Will Drewryc45952f2013-09-03 13:51:24 -0500574 else
575 {
576 verb ("V: Not a valid wildcard certificate\n");
577 ok = 0;
578 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700579 // Free our copies
Will Drewryc45952f2013-09-03 13:51:24 -0500580 free (wildchar);
581 free (delim);
582 free (hostname_to_free);
583 free (cert_wild_card_to_free);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700584 if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
Will Drewryc45952f2013-09-03 13:51:24 -0500585 {
586 verb ("V: wildcard match of %s against %s\n",
587 orig_hostname, orig_cert_wild_card);
588 return (wildcard_encountered & ok);
589 }
590 else
591 {
592 verb ("V: wildcard match failure of %s against %s\n",
593 orig_hostname, orig_cert_wild_card);
594 return 0;
595 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700596}
597
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700598/**
599 This extracts the first commonName and checks it against hostname.
600*/
601uint32_t
602check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700603{
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200604 int ok = 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700605 uint32_t ret;
606 char *cn_buf;
607 X509 *certificate;
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700608 X509_NAME *xname;
Will Drewryc45952f2013-09-03 13:51:24 -0500609 cn_buf = xmalloc (TLSDATE_HOST_NAME_MAX + 1);
610 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700611 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500612 {
613 die ("Unable to extract certificate\n");
614 }
615 memset (cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
616 xname = X509_get_subject_name (certificate);
617 ret = X509_NAME_get_text_by_NID (xname, NID_commonName,
618 cn_buf, TLSDATE_HOST_NAME_MAX);
619 if (-1 == ret && ret != strlen (hostname))
620 {
621 die ("Unable to extract commonName\n");
622 }
623 if (strcasecmp (cn_buf, hostname))
624 {
625 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
626 hostname, cn_buf);
627 }
628 else
629 {
630 verb ("V: commonName matched: %s\n", cn_buf);
631 ok = 1;
632 }
633 X509_NAME_free (xname);
634 X509_free (certificate);
635 xfree (cn_buf);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200636 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700637}
638
639/**
640 Search for a hostname match in the SubjectAlternativeNames.
641*/
642uint32_t
643check_san (SSL *ssl, const char *hostname)
644{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700645 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700646 int extcount, ok = 0;
647 /* What an OpenSSL mess ... */
Will Drewryc45952f2013-09-03 13:51:24 -0500648 if (NULL == (cert = SSL_get_peer_certificate (ssl)))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700649 {
Will Drewryc45952f2013-09-03 13:51:24 -0500650 die ("Getting certificate failed\n");
651 }
652 if ( (extcount = X509_get_ext_count (cert)) > 0)
653 {
654 int i;
655 for (i = 0; i < extcount; ++i)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700656 {
Will Drewryc45952f2013-09-03 13:51:24 -0500657 const char *extstr;
658 X509_EXTENSION *ext;
659 ext = X509_get_ext (cert, i);
660 extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext)));
661 if (!strcmp (extstr, "subjectAltName"))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700662 {
Will Drewryc45952f2013-09-03 13:51:24 -0500663 int j;
664 void *extvalstr;
Will Drewryc45952f2013-09-03 13:51:24 -0500665 STACK_OF (CONF_VALUE) *val;
666 CONF_VALUE *nval;
667#if OPENSSL_VERSION_NUMBER >= 0x10000000L
668 const
669#endif
670 X509V3_EXT_METHOD *method;
671 if (! (method = X509V3_EXT_get (ext)))
672 {
673 break;
674 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600675 extvalstr = X509V3_EXT_d2i(ext);
Will Drewryc45952f2013-09-03 13:51:24 -0500676 if (!extvalstr)
677 {
678 break;
679 }
680 if (method->i2v)
681 {
682 val = method->i2v (method, extvalstr, NULL);
683 for (j = 0; j < sk_CONF_VALUE_num (val); ++j)
684 {
685 nval = sk_CONF_VALUE_value (val, j);
686 if ( (!strcasecmp (nval->name, "DNS") &&
687 !strcasecmp (nval->value, hostname)) ||
688 (!strcasecmp (nval->name, "iPAddress") &&
689 !strcasecmp (nval->value, hostname)))
690 {
691 verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
692 ok = 1;
693 break;
694 }
695 // Attempt to match subjectAltName DNS names
696 if (!strcasecmp (nval->name, "DNS"))
697 {
698 ok = check_wildcard_match_rfc2595 (hostname, nval->value);
699 if (ok)
700 {
701 break;
702 }
703 }
704 verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
705 }
706 }
707 }
708 else
709 {
710 verb ("V: found non subjectAltName extension\n");
711 }
712 if (ok)
713 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700714 break;
715 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700716 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700717 }
Will Drewryc45952f2013-09-03 13:51:24 -0500718 else
719 {
720 verb ("V: no X509_EXTENSION field(s) found\n");
721 }
722 X509_free (cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700723 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700724}
725
726uint32_t
727check_name (SSL *ssl, const char *hostname)
728{
729 uint32_t ret;
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700730 ret = 0;
Will Drewryc45952f2013-09-03 13:51:24 -0500731 ret = check_cn (ssl, hostname);
732 ret += check_san (ssl, hostname);
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700733 if (0 != ret && 0 < ret)
Will Drewryc45952f2013-09-03 13:51:24 -0500734 {
735 verb ("V: hostname verification passed\n");
736 }
737 else
738 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100739 die ("hostname verification failed for host %s!\n", g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500740 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700741 return ret;
742}
743
744uint32_t
745verify_signature (SSL *ssl, const char *hostname)
746{
747 long ssl_verify_result;
748 X509 *certificate;
Will Drewryc45952f2013-09-03 13:51:24 -0500749 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700750 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500751 {
752 die ("Getting certificate failed\n");
753 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700754 // In theory, we verify that the cert is valid
Will Drewryc45952f2013-09-03 13:51:24 -0500755 ssl_verify_result = SSL_get_verify_result (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700756 switch (ssl_verify_result)
Will Drewryc45952f2013-09-03 13:51:24 -0500757 {
758 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
759 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
760 die ("certificate is self signed\n");
761 case X509_V_OK:
762 verb ("V: certificate verification passed\n");
763 break;
764 default:
765 die ("certification verification error: %ld\n",
766 ssl_verify_result);
767 }
768 return 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700769}
770
771void
772check_key_length (SSL *ssl)
773{
774 uint32_t key_bits;
775 X509 *certificate;
776 EVP_PKEY *public_key;
777 certificate = SSL_get_peer_certificate (ssl);
A soldier31056a62012-08-16 01:10:57 -0700778 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500779 {
780 die ("Getting certificate failed\n");
781 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700782 public_key = X509_get_pubkey (certificate);
783 if (NULL == public_key)
Will Drewryc45952f2013-09-03 13:51:24 -0500784 {
785 die ("public key extraction failure\n");
786 }
787 else
788 {
789 verb ("V: public key is ready for inspection\n");
790 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700791 key_bits = get_certificate_keybits (public_key);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600792 if (MIN_PUB_KEY_LEN >= key_bits && EVP_PKEY_id(public_key) != EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500793 {
794 die ("Unsafe public key size: %d bits\n", key_bits);
795 }
796 else
797 {
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600798 if (EVP_PKEY_id(public_key) == EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500799 if (key_bits >= MIN_ECC_PUB_KEY_LEN
800 && key_bits <= MAX_ECC_PUB_KEY_LEN)
801 {
802 verb ("V: ECC key length appears safe\n");
803 }
804 else
805 {
806 die ("Unsafe ECC key size: %d bits\n", key_bits);
807 }
808 else
809 {
810 verb ("V: key length appears safe\n");
811 }
812 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700813 EVP_PKEY_free (public_key);
814}
815
816void
817inspect_key (SSL *ssl, const char *hostname)
818{
Will Drewryc45952f2013-09-03 13:51:24 -0500819 verify_signature (ssl, hostname);
820 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700821}
822
Christian Grothoff88b422b2012-02-14 00:35:09 +0100823/**
824 * Run SSL handshake and store the resulting time value in the
825 * 'time_map'.
826 *
827 * @param time_map where to store the current time
828 */
829static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400830run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100831{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100832 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100833 SSL_CTX *ctx;
834 SSL *ssl;
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800835 struct stat statbuf;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100836 SSL_load_error_strings();
837 SSL_library_init();
Christian Grothoff90e9f832012-02-07 11:16:47 +0100838 ctx = NULL;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600839
Mattias Nissler3da9da42020-02-13 11:27:41 +0100840 /*
841 * Some of the XYZ_method() calls below are marked deprecated. We still want
842 * to use them for compatibility reasons, so silence the warnings or they'll
843 * break the build.
844 */
845#pragma GCC diagnostic push
846#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
847
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100848 if (0 == strcmp ("sslv23", g_protocol))
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800849 {
Will Drewryc45952f2013-09-03 13:51:24 -0500850 verb ("V: using SSLv23_client_method()\n");
851 ctx = SSL_CTX_new (SSLv23_client_method());
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800852 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100853#ifndef OPENSSL_NO_SSL3_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100854 else if (0 == strcmp ("sslv3", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500855 {
856 verb ("V: using SSLv3_client_method()\n");
857 ctx = SSL_CTX_new (SSLv3_client_method());
858 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100859#endif
860#ifndef OPENSSL_NO_TLS1_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100861 else if (0 == strcmp ("tlsv1", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500862 {
863 verb ("V: using TLSv1_client_method()\n");
864 ctx = SSL_CTX_new (TLSv1_client_method());
865 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100866#endif
867#ifndef OPENSSL_NO_TLS1_1_METHOD
868 else if (0 == strcmp ("tlsv11", g_protocol))
869 {
870 verb ("V: using TLSv1_1_client_method()\n");
871 ctx = SSL_CTX_new (TLSv1_1_client_method());
872 }
873#endif
874#ifndef OPENSSL_NO_TLS1_2_METHOD
875 else if (0 == strcmp ("tlsv12", g_protocol))
876 {
877 verb ("V: using TLSv1_2_client_method()\n");
878 ctx = SSL_CTX_new (TLSv1_2_client_method());
879 }
880#endif
Will Drewryc45952f2013-09-03 13:51:24 -0500881 else
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100882 die ("Unsupported protocol `%s'\n", g_protocol);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600883
Mattias Nissler3da9da42020-02-13 11:27:41 +0100884#pragma GCC diagnostic pop
885
Will Drewryc45952f2013-09-03 13:51:24 -0500886 if (ctx == NULL)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100887 die ("OpenSSL failed to support protocol `%s'\n", g_protocol);
888 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500889 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100890 if (-1 == stat (g_ca_cert_container, &statbuf))
Will Drewryc45952f2013-09-03 13:51:24 -0500891 {
892 die ("Unable to stat CA certficate container\n");
893 }
894 else
895 {
896 switch (statbuf.st_mode & S_IFMT)
897 {
898 case S_IFREG:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100899 if (1 != SSL_CTX_load_verify_locations(
900 ctx, g_ca_cert_container, NULL))
901 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500902 break;
903 case S_IFDIR:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100904 if (1 != SSL_CTX_load_verify_locations(
905 ctx, NULL, g_ca_cert_container))
906 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500907 break;
908 default:
909 die ("Unable to load CA certficate container\n");
910 }
911 }
912 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500913
914 if (time_is_an_illusion)
915 {
916 SSL_CTX_set_cert_verify_callback (ctx, verify_with_server_time, NULL);
917 }
918
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100919 verb ("V: setting up connection to %s:%s\n", g_host, g_port);
920 if (NULL == (s_bio = make_ssl_bio(ctx, g_host, g_port, g_proxy)))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100921 die ("SSL BIO setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500922 BIO_get_ssl (s_bio, &ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100923 if (NULL == ssl)
924 die ("SSL setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500925 SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100926 SSL_set_tlsext_host_name (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500927 if (NULL == BIO_new_fp (stdout, BIO_NOCLOSE))
928 die ("BIO_new_fp returned error, possibly: %s", strerror (errno));
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800929 // This should run in seccomp
930 // eg: prctl(PR_SET_SECCOMP, 1);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100931 verb ("V: BIO_do_connect\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500932 if (1 != BIO_do_connect (s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800933 die ("SSL connection failed\n");
Pavol Markod9dd19d2020-01-17 23:32:57 +0100934 verb ("V: BIO_do_handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500935 if (1 != BIO_do_handshake (s_bio))
Philipp Winterd96af622012-02-15 22:15:50 +0100936 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100937 // Verify the peer certificate against the CA certs on the local system
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100938 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500939 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100940 inspect_key (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500941 }
942 else
943 {
944 verb ("V: Certificate verification skipped!\n");
945 }
946 check_key_length (ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100947 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700948 // ssl->s3->server_random is an unsigned char of 32 bits
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600949 SSL_get_server_random(ssl, (unsigned char *)time_map, sizeof(uint32_t));
Will Drewryc45952f2013-09-03 13:51:24 -0500950 SSL_free (ssl);
951 SSL_CTX_free (ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100952}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100953
Christian Grothoff191cd982012-02-14 00:48:45 +0100954/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100955
Christian Grothoff88b422b2012-02-14 00:35:09 +0100956int
Will Drewryc45952f2013-09-03 13:51:24 -0500957main (int argc, char **argv)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100958{
959 uint32_t *time_map;
David Goulet0809df12012-07-31 23:27:34 -0400960 struct tlsdate_time start_time, end_time, warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100961 int status;
962 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100963 long long rt_time_ms;
964 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200965 int setclock;
966 int showtime;
Will Drewry72706752013-09-13 15:57:10 -0500967 int showtime_raw;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400968 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400969 int leap;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400970 if (argc != 12)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100971 return 1;
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100972 g_host = argv[1];
973 g_port = argv[2];
974 validate_port(g_port);
975 g_protocol = argv[3];
976 g_ca_cert_container = argv[6];
977 g_ca_racket = (0 != strcmp ("unchecked", argv[4]));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100978 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200979 setclock = (0 == strcmp ("setclock", argv[7]));
980 showtime = (0 == strcmp ("showtime", argv[8]));
Will Drewry72706752013-09-13 15:57:10 -0500981 showtime_raw = (0 == strcmp ("showtime=raw", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400982 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400983 leap = (0 == strcmp ("leapaway", argv[10]));
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100984 g_proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
Michael Ershov2012e5b2021-03-25 13:18:13 +0100985 srandom(time(NULL));
Will Drewryc45952f2013-09-03 13:51:24 -0500986 clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400987 if (timewarp)
Will Drewryc45952f2013-09-03 13:51:24 -0500988 {
989 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
990 (unsigned long) CLOCK_SEC (&warp_time),
991 (unsigned long) CLOCK_USEC (&warp_time));
992 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200993 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400994 if (0 == setclock && 0 == timewarp)
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400995 {
Will Drewryc45952f2013-09-03 13:51:24 -0500996 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400997 }
Will Drewryc45952f2013-09-03 13:51:24 -0500998 time_map = mmap (NULL, sizeof (uint32_t),
999 PROT_READ | PROT_WRITE,
1000 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
1001 if (MAP_FAILED == time_map)
1002 {
1003 fprintf (stderr, "mmap failed: %s\n",
1004 strerror (errno));
1005 return 1;
1006 }
1007 /* Get the current time from the system clock. */
1008 if (0 != clock_get_real_time (&start_time))
1009 {
1010 die ("Failed to read current time of day: %s\n", strerror (errno));
1011 }
1012 verb ("V: time is currently %lu.%06lu\n",
1013 (unsigned long) CLOCK_SEC (&start_time),
1014 (unsigned long) CLOCK_NSEC (&start_time));
1015 if ( ( (unsigned long) CLOCK_SEC (&start_time)) < ( (unsigned long) CLOCK_SEC (&warp_time)))
1016 {
1017 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
1018 if (timewarp)
1019 {
1020 verb ("V: Attempting to warp local clock into the future\n");
1021 if (0 != clock_set_real_time (&warp_time))
1022 {
1023 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
1024 strerror (errno),
1025 (unsigned long) CLOCK_SEC (&warp_time),
1026 (unsigned long) CLOCK_SEC (&warp_time));
1027 }
1028 if (0 != clock_get_real_time (&start_time))
1029 {
1030 die ("Failed to read current time of day: %s\n", strerror (errno));
1031 }
1032 verb ("V: time is currently %lu.%06lu\n",
1033 (unsigned long) CLOCK_SEC (&start_time),
1034 (unsigned long) CLOCK_NSEC (&start_time));
1035 verb ("V: It's just a step to the left...\n");
1036 }
1037 }
1038 else
1039 {
1040 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
1041 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001042 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001043 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +01001044 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001045 ssl_child = fork ();
1046 if (-1 == ssl_child)
1047 die ("fork failed: %s\n", strerror (errno));
1048 if (0 == ssl_child)
Will Drewryc45952f2013-09-03 13:51:24 -05001049 {
1050 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
1051 run_ssl (time_map, leap);
1052 (void) munmap (time_map, sizeof (uint32_t));
1053 _exit (0);
1054 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001055 if (ssl_child != waitpid (ssl_child, &status, 0))
1056 die ("waitpid failed: %s\n", strerror (errno));
Will Drewryc45952f2013-09-03 13:51:24 -05001057 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
Christian Grothoff191cd982012-02-14 00:48:45 +01001058 die ("child process failed in SSL handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -05001059 if (0 != clock_get_real_time (&end_time))
Christian Grothoff88b422b2012-02-14 00:35:09 +01001060 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +01001061 /* calculate RTT */
Will Drewryc45952f2013-09-03 13:51:24 -05001062 rt_time_ms = (CLOCK_SEC (&end_time) - CLOCK_SEC (&start_time)) * 1000 + (CLOCK_USEC (&end_time) - CLOCK_USEC (&start_time)) / 1000;
Christian Grothoffe267c352012-02-14 01:10:54 +01001063 if (rt_time_ms < 0)
1064 rt_time_ms = 0; /* non-linear time... */
1065 server_time_s = ntohl (*time_map);
1066 munmap (time_map, sizeof (uint32_t));
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001067 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Will Drewryc45952f2013-09-03 13:51:24 -05001068 (unsigned int) server_time_s,
1069 CLOCK_SEC (&start_time) - server_time_s,
1070 rt_time_ms);
Philipp Winterb3ca5772012-02-16 11:56:11 +01001071 /* warning if the handshake took too long */
Will Drewryc45952f2013-09-03 13:51:24 -05001072 if (rt_time_ms > TLS_RTT_THRESHOLD)
1073 {
1074 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
1075 "server or run it again\n", TLS_RTT_THRESHOLD);
1076 }
Will Drewry72706752013-09-13 15:57:10 -05001077 if (showtime_raw)
Will Drewryc45952f2013-09-03 13:51:24 -05001078 {
1079 fwrite (&server_time_s, sizeof (server_time_s), 1, stdout);
1080 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001081 if (showtime)
Will Drewryc45952f2013-09-03 13:51:24 -05001082 {
1083 struct tm ltm;
1084 time_t tim = server_time_s;
1085 char buf[256];
1086 localtime_r (&tim, &ltm);
1087 if (0 == strftime (buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
1088 {
1089 die ("strftime returned 0\n");
1090 }
1091 fprintf (stdout, "%s\n", buf);
1092 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001093 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001094 if (setclock)
Will Drewryc45952f2013-09-03 13:51:24 -05001095 {
1096 struct tlsdate_time server_time;
1097 clock_init_time (&server_time, server_time_s + (rt_time_ms / 2 / 1000),
1098 (rt_time_ms / 2) % 1000);
1099 // We should never receive a time that is before the time we were last
1100 // compiled; we subscribe to the linear theory of time for this program
1101 // and this program alone!
1102 if (CLOCK_SEC (&server_time) >= MAX_REASONABLE_TIME)
1103 die ("remote server is a false ticker from the future!\n");
1104 if (CLOCK_SEC (&server_time) <= RECENT_COMPILE_DATE)
1105 die ("remote server is a false ticker!\n");
1106 if (0 != clock_set_real_time (&server_time))
1107 die ("setting time failed: %s (Difference from server is about %d)\n",
1108 strerror (errno),
1109 CLOCK_SEC (&start_time) - server_time_s);
1110 verb ("V: setting time succeeded\n");
1111 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001112 return 0;
1113}