blob: 476f301825b25fc59fcf7b20d459663b391f93bc [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
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100199/* Connects to |host| on port |port|.
200 * Returns the socket file descriptor if successful, otherwise exits with
201 * failure.
202 */
203static int create_connection (const char *host, const char *port)
204{
205 int err, sock = -1;
206 struct addrinfo *ai = NULL, *cai = NULL;
207 struct addrinfo hints = {
208 .ai_flags = AI_ADDRCONFIG,
209 .ai_family = AF_UNSPEC,
210 .ai_socktype = SOCK_STREAM,
211 };
Pavol Markod9dd19d2020-01-17 23:32:57 +0100212 // Use INET6_ADDRSTRLEN for the buffer holding IP addresses as it will always
213 // be longer than INET_ADDRSTRLEN.
214 char addr_str_buf[INET6_ADDRSTRLEN];
215 memset (addr_str_buf, '\0', INET6_ADDRSTRLEN);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100216
217 err = getaddrinfo (host, port, &hints, &ai);
218
219 if (err != 0 || !ai)
220 die ("getaddrinfo (%s): %s\n", host, gai_strerror (err));
221
222 for (cai = ai; cai; cai = cai->ai_next)
223 {
Pavol Markod9dd19d2020-01-17 23:32:57 +0100224 addr_to_str (cai->ai_addr, addr_str_buf, INET6_ADDRSTRLEN);
225 verb ("V: attempting to connect to %s\n", addr_str_buf);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100226 sock = socket (cai->ai_family, SOCK_STREAM, 0);
227 if (sock < 0)
228 {
229 perror ("socket");
230 continue;
231 }
232
233 if (connect (sock, cai->ai_addr, cai->ai_addrlen) != 0)
234 {
235 perror ("connect");
236 close (sock);
237 sock = -1;
238 continue;
239 }
240 break;
241 }
242 freeaddrinfo (ai);
243
244 if (sock < 0)
245 die ("failed to find any remote addresses for %s:%s\n", host, port);
246
247 return sock;
248}
249
250/* Creates a BIO wrapper over the socket connection to |host|:|port|.
251 * This workaround is needed because BIO_s_connect() doesn't support IPv6.
252 */
253static BIO *BIO_create_socket (const char *host, const char *port)
254{
255 BIO *bio_socket = NULL;
256 int sockfd = create_connection (host, port);
257 if ( !(bio_socket = BIO_new_fd (sockfd, 1 /* close_flag */)))
258 die ("BIO_new_fd failed\n");
259
260 return bio_socket;
261}
262
263/* Creates an OpenSSL BIO-chain which talks to |target_host|:|target_port|
264 * using the SSL protocol. If |proxy| is set it will be used as a HTTP proxy.
265 */
266static BIO *
267make_ssl_bio (SSL_CTX *ctx, const char *target_host, const char *target_port,
268 char *proxy)
269{
270 BIO *bio_socket = NULL;
271 BIO *bio_ssl = NULL;
272 BIO *bio_proxy = NULL;
273 char *scheme = NULL;
274 char *proxy_host = NULL;
275 char *proxy_port = NULL;
276
277 if ( !(bio_ssl = BIO_new_ssl (ctx, 1)))
Will Drewryc45952f2013-09-03 13:51:24 -0500278 die ("BIO_new_ssl failed\n");
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100279
280 if (proxy)
281 {
282 verb ("V: using proxy %s\n", proxy);
283 parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
284
285 if ( !(bio_proxy = BIO_create_proxy (scheme, target_host, target_port)))
286 die ("BIO_create_proxy failed\n");
287
288 bio_socket = BIO_create_socket (proxy_host, proxy_port);
289
290 BIO_push (bio_ssl, bio_proxy);
291 BIO_push (bio_ssl, bio_socket);
292 }
293 else
294 {
295 bio_socket = BIO_create_socket (target_host, target_port);
296 BIO_push (bio_ssl, bio_socket);
297 }
298 return bio_ssl;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400299}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100300
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200301/** helper function for 'malloc' */
302static void *
303xmalloc (size_t size)
304{
305 void *ptr;
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200306 if (0 == size)
Will Drewryc45952f2013-09-03 13:51:24 -0500307 die ("xmalloc: zero size\n");
308 ptr = malloc (size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200309 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500310 die ("xmalloc: out of memory (allocating %zu bytes)\n", size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200311 return ptr;
312}
313
314
315/** helper function for 'free' */
316static void
317xfree (void *ptr)
318{
Daniel Borkmann592acc52012-07-30 14:08:02 +0200319 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500320 die ("xfree: NULL pointer given as argument\n");
321 free (ptr);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200322}
323
324
David Benjamin1aba54c2017-02-05 16:24:49 -0500325static int
326verify_with_server_time (X509_STORE_CTX *store_ctx, void *arg)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700327{
David Benjamin1aba54c2017-02-05 16:24:49 -0500328 SSL *ssl = X509_STORE_CTX_get_ex_data (
329 store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
330
331 // XXX TODO: If we want to trust the remote system for time,
332 // can we just read that time out of the remote system and if the
333 // cert verifies, decide that the time is reasonable?
334 // Such a process seems to indicate that a once valid cert would be
335 // forever valid - we stopgap that by ensuring it isn't less than
336 // the latest compiled_time and isn't above max_reasonable_time...
337 // XXX TODO: Solve eternal question about the Chicken and the Egg...
338 uint32_t compiled_time = RECENT_COMPILE_DATE;
339 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
340 uint32_t server_time;
341 verb ("V: freezing time for x509 verification\n");
342 SSL_get_server_random(ssl, (unsigned char *)&server_time,
343 sizeof (uint32_t));
344 if (compiled_time < ntohl (server_time)
345 &&
346 ntohl (server_time) < max_reasonable_time)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700347 {
David Benjamin1aba54c2017-02-05 16:24:49 -0500348 verb ("V: remote peer provided: %d, preferred over compile time: %d\n",
349 ntohl (server_time), compiled_time);
350 verb ("V: freezing time with X509_VERIFY_PARAM_set_time\n");
351 X509_STORE_CTX_set_time (
352 store_ctx, 0, (time_t) ntohl (server_time) + 86400);
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700353 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500354 else
355 {
356 die ("V: the remote server is a false ticker! server: %d compile: %d\n",
357 ntohl (server_time), compiled_time);
358 }
359
360 return X509_verify_cert (store_ctx);
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700361}
362
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700363uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700364get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700365{
366 /*
367 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
368 */
369 uint32_t key_bits;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600370 switch (EVP_PKEY_id (public_key))
Will Drewryc45952f2013-09-03 13:51:24 -0500371 {
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700372 case EVP_PKEY_RSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500373 verb ("V: key type: EVP_PKEY_RSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700374 break;
375 case EVP_PKEY_RSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500376 verb ("V: key type: EVP_PKEY_RSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700377 break;
378 case EVP_PKEY_DSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500379 verb ("V: key type: EVP_PKEY_DSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700380 break;
381 case EVP_PKEY_DSA1:
Will Drewryc45952f2013-09-03 13:51:24 -0500382 verb ("V: key type: EVP_PKEY_DSA1\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700383 break;
384 case EVP_PKEY_DSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500385 verb ("V: key type: EVP_PKEY_DSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700386 break;
387 case EVP_PKEY_DSA3:
Will Drewryc45952f2013-09-03 13:51:24 -0500388 verb ("V: key type: EVP_PKEY_DSA3\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700389 break;
390 case EVP_PKEY_DSA4:
Will Drewryc45952f2013-09-03 13:51:24 -0500391 verb ("V: key type: EVP_PKEY_DSA4\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700392 break;
393 case EVP_PKEY_DH:
Will Drewryc45952f2013-09-03 13:51:24 -0500394 verb ("V: key type: EVP_PKEY_DH\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700395 break;
396 case EVP_PKEY_EC:
Will Drewryc45952f2013-09-03 13:51:24 -0500397 verb ("V: key type: EVP_PKEY_EC\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700398 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500399 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700400 default:
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700401 die ("unknown public key type\n");
402 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500403 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600404 key_bits = EVP_PKEY_bits (public_key);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700405 verb ("V: keybits: %d\n", key_bits);
406 return key_bits;
407}
408
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700409uint32_t
Will Drewryc45952f2013-09-03 13:51:24 -0500410dns_label_count (char *label, char *delim)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700411{
412 char *label_tmp;
413 char *saveptr;
414 char *saveptr_tmp;
415 uint32_t label_count;
Will Drewryc45952f2013-09-03 13:51:24 -0500416 label_tmp = strdup (label);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700417 label_count = 0;
418 saveptr = NULL;
419 saveptr_tmp = NULL;
Will Drewryc45952f2013-09-03 13:51:24 -0500420 saveptr = strtok_r (label_tmp, delim, &saveptr);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700421 if (NULL != saveptr)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700422 {
Will Drewryc45952f2013-09-03 13:51:24 -0500423 // Did we find our first label?
424 if (saveptr[0] != delim[0])
425 {
426 label_count++;
427 verb ("V: label found; total label count: %d\n", label_count);
428 }
429 do
430 {
431 // Find all subsequent labels
432 label_count++;
433 saveptr_tmp = strtok_r (NULL, delim, &saveptr);
434 verb ("V: label found; total label count: %d\n", label_count);
435 }
436 while (NULL != saveptr_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700437 }
Will Drewryc45952f2013-09-03 13:51:24 -0500438 free (label_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700439 return label_count;
440}
441
442// first we split strings on '.'
443// then we call each split string a 'label'
444// Do not allow '*' for the top level domain label; eg never allow *.*.com
445// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
446// Do allow *.example.com
447uint32_t
448check_wildcard_match_rfc2595 (const char *orig_hostname,
Will Drewryc45952f2013-09-03 13:51:24 -0500449 const char *orig_cert_wild_card)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700450{
451 char *hostname;
452 char *hostname_to_free;
453 char *cert_wild_card;
454 char *cert_wild_card_to_free;
455 char *expected_label;
456 char *wildcard_label;
457 char *delim;
458 char *wildchar;
459 uint32_t ok;
460 uint32_t wildcard_encountered;
461 uint32_t label_count;
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700462 // First we copy the original strings
Will Drewryc45952f2013-09-03 13:51:24 -0500463 hostname = strndup (orig_hostname, strlen (orig_hostname));
464 cert_wild_card = strndup (orig_cert_wild_card, strlen (orig_cert_wild_card));
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700465 hostname_to_free = hostname;
466 cert_wild_card_to_free = cert_wild_card;
Will Drewryc45952f2013-09-03 13:51:24 -0500467 delim = strdup (".");
468 wildchar = strdup ("*");
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700469 verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
Will Drewryc45952f2013-09-03 13:51:24 -0500470 hostname, cert_wild_card);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700471 // By default we have not processed any labels
Will Drewryc45952f2013-09-03 13:51:24 -0500472 label_count = dns_label_count (cert_wild_card, delim);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700473 // By default we have no match
474 ok = 0;
475 wildcard_encountered = 0;
476 // First - do we have labels? If not, we refuse to even try to match
Will Drewryc45952f2013-09-03 13:51:24 -0500477 if ( (NULL != strpbrk (cert_wild_card, delim)) &&
478 (NULL != strpbrk (hostname, delim)) &&
479 (label_count <= ( (uint32_t) RFC2595_MIN_LABEL_COUNT)))
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700480 {
Will Drewryc45952f2013-09-03 13:51:24 -0500481 if (wildchar[0] == cert_wild_card[0])
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700482 {
Will Drewryc45952f2013-09-03 13:51:24 -0500483 verb ("V: Found wildcard in at start of provided certificate name\n");
484 do
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700485 {
Will Drewryc45952f2013-09-03 13:51:24 -0500486 // Skip over the bytes between the first char and until the next label
487 wildcard_label = strsep (&cert_wild_card, delim);
488 expected_label = strsep (&hostname, delim);
489 if (NULL != wildcard_label &&
490 NULL != expected_label &&
491 NULL != hostname &&
492 NULL != cert_wild_card)
493 {
494 // Now we only consider this wildcard valid if the rest of the
495 // hostnames match verbatim
496 verb ("V: Attempting match of '%s' against '%s'\n",
497 expected_label, wildcard_label);
498 // This is the case where we have a label that begins with wildcard
499 // Furthermore, we only allow this for the first label
500 if (wildcard_label[0] == wildchar[0] &&
501 0 == wildcard_encountered && 0 == ok)
502 {
503 verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
504 wildcard_encountered = 1;
505 }
506 else
507 {
508 verb ("V: Attempting match of '%s' against '%s'\n",
509 hostname, cert_wild_card);
510 if (0 == strcasecmp (expected_label, wildcard_label) &&
511 label_count >= ( (uint32_t) RFC2595_MIN_LABEL_COUNT))
512 {
513 ok = 1;
514 verb ("V: remaining labels match!\n");
515 break;
516 }
517 else
518 {
519 ok = 0;
520 verb ("V: remaining labels do not match!\n");
521 break;
522 }
523 }
524 }
525 else
526 {
527 // We hit this case when we have a mismatched number of labels
528 verb ("V: NULL label; no wildcard here\n");
529 break;
530 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700531 }
Will Drewryc45952f2013-09-03 13:51:24 -0500532 while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700533 }
Will Drewryc45952f2013-09-03 13:51:24 -0500534 else
535 {
536 verb ("V: Not a RFC 2595 wildcard\n");
537 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700538 }
Will Drewryc45952f2013-09-03 13:51:24 -0500539 else
540 {
541 verb ("V: Not a valid wildcard certificate\n");
542 ok = 0;
543 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700544 // Free our copies
Will Drewryc45952f2013-09-03 13:51:24 -0500545 free (wildchar);
546 free (delim);
547 free (hostname_to_free);
548 free (cert_wild_card_to_free);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700549 if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
Will Drewryc45952f2013-09-03 13:51:24 -0500550 {
551 verb ("V: wildcard match of %s against %s\n",
552 orig_hostname, orig_cert_wild_card);
553 return (wildcard_encountered & ok);
554 }
555 else
556 {
557 verb ("V: wildcard match failure of %s against %s\n",
558 orig_hostname, orig_cert_wild_card);
559 return 0;
560 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700561}
562
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700563/**
564 This extracts the first commonName and checks it against hostname.
565*/
566uint32_t
567check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700568{
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200569 int ok = 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700570 uint32_t ret;
571 char *cn_buf;
572 X509 *certificate;
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700573 X509_NAME *xname;
Will Drewryc45952f2013-09-03 13:51:24 -0500574 cn_buf = xmalloc (TLSDATE_HOST_NAME_MAX + 1);
575 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700576 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500577 {
578 die ("Unable to extract certificate\n");
579 }
580 memset (cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
581 xname = X509_get_subject_name (certificate);
582 ret = X509_NAME_get_text_by_NID (xname, NID_commonName,
583 cn_buf, TLSDATE_HOST_NAME_MAX);
584 if (-1 == ret && ret != strlen (hostname))
585 {
586 die ("Unable to extract commonName\n");
587 }
588 if (strcasecmp (cn_buf, hostname))
589 {
590 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
591 hostname, cn_buf);
592 }
593 else
594 {
595 verb ("V: commonName matched: %s\n", cn_buf);
596 ok = 1;
597 }
598 X509_NAME_free (xname);
599 X509_free (certificate);
600 xfree (cn_buf);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200601 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700602}
603
604/**
605 Search for a hostname match in the SubjectAlternativeNames.
606*/
607uint32_t
608check_san (SSL *ssl, const char *hostname)
609{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700610 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700611 int extcount, ok = 0;
612 /* What an OpenSSL mess ... */
Will Drewryc45952f2013-09-03 13:51:24 -0500613 if (NULL == (cert = SSL_get_peer_certificate (ssl)))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700614 {
Will Drewryc45952f2013-09-03 13:51:24 -0500615 die ("Getting certificate failed\n");
616 }
617 if ( (extcount = X509_get_ext_count (cert)) > 0)
618 {
619 int i;
620 for (i = 0; i < extcount; ++i)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700621 {
Will Drewryc45952f2013-09-03 13:51:24 -0500622 const char *extstr;
623 X509_EXTENSION *ext;
624 ext = X509_get_ext (cert, i);
625 extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext)));
626 if (!strcmp (extstr, "subjectAltName"))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700627 {
Will Drewryc45952f2013-09-03 13:51:24 -0500628 int j;
629 void *extvalstr;
Will Drewryc45952f2013-09-03 13:51:24 -0500630 STACK_OF (CONF_VALUE) *val;
631 CONF_VALUE *nval;
632#if OPENSSL_VERSION_NUMBER >= 0x10000000L
633 const
634#endif
635 X509V3_EXT_METHOD *method;
636 if (! (method = X509V3_EXT_get (ext)))
637 {
638 break;
639 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600640 extvalstr = X509V3_EXT_d2i(ext);
Will Drewryc45952f2013-09-03 13:51:24 -0500641 if (!extvalstr)
642 {
643 break;
644 }
645 if (method->i2v)
646 {
647 val = method->i2v (method, extvalstr, NULL);
648 for (j = 0; j < sk_CONF_VALUE_num (val); ++j)
649 {
650 nval = sk_CONF_VALUE_value (val, j);
651 if ( (!strcasecmp (nval->name, "DNS") &&
652 !strcasecmp (nval->value, hostname)) ||
653 (!strcasecmp (nval->name, "iPAddress") &&
654 !strcasecmp (nval->value, hostname)))
655 {
656 verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
657 ok = 1;
658 break;
659 }
660 // Attempt to match subjectAltName DNS names
661 if (!strcasecmp (nval->name, "DNS"))
662 {
663 ok = check_wildcard_match_rfc2595 (hostname, nval->value);
664 if (ok)
665 {
666 break;
667 }
668 }
669 verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
670 }
671 }
672 }
673 else
674 {
675 verb ("V: found non subjectAltName extension\n");
676 }
677 if (ok)
678 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700679 break;
680 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700681 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700682 }
Will Drewryc45952f2013-09-03 13:51:24 -0500683 else
684 {
685 verb ("V: no X509_EXTENSION field(s) found\n");
686 }
687 X509_free (cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700688 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700689}
690
691uint32_t
692check_name (SSL *ssl, const char *hostname)
693{
694 uint32_t ret;
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700695 ret = 0;
Will Drewryc45952f2013-09-03 13:51:24 -0500696 ret = check_cn (ssl, hostname);
697 ret += check_san (ssl, hostname);
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700698 if (0 != ret && 0 < ret)
Will Drewryc45952f2013-09-03 13:51:24 -0500699 {
700 verb ("V: hostname verification passed\n");
701 }
702 else
703 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100704 die ("hostname verification failed for host %s!\n", g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500705 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700706 return ret;
707}
708
709uint32_t
710verify_signature (SSL *ssl, const char *hostname)
711{
712 long ssl_verify_result;
713 X509 *certificate;
Will Drewryc45952f2013-09-03 13:51:24 -0500714 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700715 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500716 {
717 die ("Getting certificate failed\n");
718 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700719 // In theory, we verify that the cert is valid
Will Drewryc45952f2013-09-03 13:51:24 -0500720 ssl_verify_result = SSL_get_verify_result (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700721 switch (ssl_verify_result)
Will Drewryc45952f2013-09-03 13:51:24 -0500722 {
723 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
724 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
725 die ("certificate is self signed\n");
726 case X509_V_OK:
727 verb ("V: certificate verification passed\n");
728 break;
729 default:
730 die ("certification verification error: %ld\n",
731 ssl_verify_result);
732 }
733 return 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700734}
735
736void
737check_key_length (SSL *ssl)
738{
739 uint32_t key_bits;
740 X509 *certificate;
741 EVP_PKEY *public_key;
742 certificate = SSL_get_peer_certificate (ssl);
A soldier31056a62012-08-16 01:10:57 -0700743 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500744 {
745 die ("Getting certificate failed\n");
746 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700747 public_key = X509_get_pubkey (certificate);
748 if (NULL == public_key)
Will Drewryc45952f2013-09-03 13:51:24 -0500749 {
750 die ("public key extraction failure\n");
751 }
752 else
753 {
754 verb ("V: public key is ready for inspection\n");
755 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700756 key_bits = get_certificate_keybits (public_key);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600757 if (MIN_PUB_KEY_LEN >= key_bits && EVP_PKEY_id(public_key) != EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500758 {
759 die ("Unsafe public key size: %d bits\n", key_bits);
760 }
761 else
762 {
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600763 if (EVP_PKEY_id(public_key) == EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500764 if (key_bits >= MIN_ECC_PUB_KEY_LEN
765 && key_bits <= MAX_ECC_PUB_KEY_LEN)
766 {
767 verb ("V: ECC key length appears safe\n");
768 }
769 else
770 {
771 die ("Unsafe ECC key size: %d bits\n", key_bits);
772 }
773 else
774 {
775 verb ("V: key length appears safe\n");
776 }
777 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700778 EVP_PKEY_free (public_key);
779}
780
781void
782inspect_key (SSL *ssl, const char *hostname)
783{
Will Drewryc45952f2013-09-03 13:51:24 -0500784 verify_signature (ssl, hostname);
785 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700786}
787
Christian Grothoff88b422b2012-02-14 00:35:09 +0100788/**
789 * Run SSL handshake and store the resulting time value in the
790 * 'time_map'.
791 *
792 * @param time_map where to store the current time
793 */
794static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400795run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100796{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100797 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100798 SSL_CTX *ctx;
799 SSL *ssl;
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800800 struct stat statbuf;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100801 SSL_load_error_strings();
802 SSL_library_init();
Christian Grothoff90e9f832012-02-07 11:16:47 +0100803 ctx = NULL;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600804
Mattias Nissler3da9da42020-02-13 11:27:41 +0100805 /*
806 * Some of the XYZ_method() calls below are marked deprecated. We still want
807 * to use them for compatibility reasons, so silence the warnings or they'll
808 * break the build.
809 */
810#pragma GCC diagnostic push
811#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
812
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100813 if (0 == strcmp ("sslv23", g_protocol))
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800814 {
Will Drewryc45952f2013-09-03 13:51:24 -0500815 verb ("V: using SSLv23_client_method()\n");
816 ctx = SSL_CTX_new (SSLv23_client_method());
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800817 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100818#ifndef OPENSSL_NO_SSL3_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100819 else if (0 == strcmp ("sslv3", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500820 {
821 verb ("V: using SSLv3_client_method()\n");
822 ctx = SSL_CTX_new (SSLv3_client_method());
823 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100824#endif
825#ifndef OPENSSL_NO_TLS1_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100826 else if (0 == strcmp ("tlsv1", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500827 {
828 verb ("V: using TLSv1_client_method()\n");
829 ctx = SSL_CTX_new (TLSv1_client_method());
830 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100831#endif
832#ifndef OPENSSL_NO_TLS1_1_METHOD
833 else if (0 == strcmp ("tlsv11", g_protocol))
834 {
835 verb ("V: using TLSv1_1_client_method()\n");
836 ctx = SSL_CTX_new (TLSv1_1_client_method());
837 }
838#endif
839#ifndef OPENSSL_NO_TLS1_2_METHOD
840 else if (0 == strcmp ("tlsv12", g_protocol))
841 {
842 verb ("V: using TLSv1_2_client_method()\n");
843 ctx = SSL_CTX_new (TLSv1_2_client_method());
844 }
845#endif
Will Drewryc45952f2013-09-03 13:51:24 -0500846 else
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100847 die ("Unsupported protocol `%s'\n", g_protocol);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600848
Mattias Nissler3da9da42020-02-13 11:27:41 +0100849#pragma GCC diagnostic pop
850
Will Drewryc45952f2013-09-03 13:51:24 -0500851 if (ctx == NULL)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100852 die ("OpenSSL failed to support protocol `%s'\n", g_protocol);
853 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500854 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100855 if (-1 == stat (g_ca_cert_container, &statbuf))
Will Drewryc45952f2013-09-03 13:51:24 -0500856 {
857 die ("Unable to stat CA certficate container\n");
858 }
859 else
860 {
861 switch (statbuf.st_mode & S_IFMT)
862 {
863 case S_IFREG:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100864 if (1 != SSL_CTX_load_verify_locations(
865 ctx, g_ca_cert_container, NULL))
866 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500867 break;
868 case S_IFDIR:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100869 if (1 != SSL_CTX_load_verify_locations(
870 ctx, NULL, g_ca_cert_container))
871 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500872 break;
873 default:
874 die ("Unable to load CA certficate container\n");
875 }
876 }
877 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500878
879 if (time_is_an_illusion)
880 {
881 SSL_CTX_set_cert_verify_callback (ctx, verify_with_server_time, NULL);
882 }
883
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100884 verb ("V: setting up connection to %s:%s\n", g_host, g_port);
885 if (NULL == (s_bio = make_ssl_bio(ctx, g_host, g_port, g_proxy)))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100886 die ("SSL BIO setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500887 BIO_get_ssl (s_bio, &ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100888 if (NULL == ssl)
889 die ("SSL setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500890 SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100891 SSL_set_tlsext_host_name (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500892 if (NULL == BIO_new_fp (stdout, BIO_NOCLOSE))
893 die ("BIO_new_fp returned error, possibly: %s", strerror (errno));
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800894 // This should run in seccomp
895 // eg: prctl(PR_SET_SECCOMP, 1);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100896 verb ("V: BIO_do_connect\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500897 if (1 != BIO_do_connect (s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800898 die ("SSL connection failed\n");
Pavol Markod9dd19d2020-01-17 23:32:57 +0100899 verb ("V: BIO_do_handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500900 if (1 != BIO_do_handshake (s_bio))
Philipp Winterd96af622012-02-15 22:15:50 +0100901 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100902 // Verify the peer certificate against the CA certs on the local system
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100903 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500904 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100905 inspect_key (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500906 }
907 else
908 {
909 verb ("V: Certificate verification skipped!\n");
910 }
911 check_key_length (ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100912 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700913 // ssl->s3->server_random is an unsigned char of 32 bits
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600914 SSL_get_server_random(ssl, (unsigned char *)time_map, sizeof(uint32_t));
Will Drewryc45952f2013-09-03 13:51:24 -0500915 SSL_free (ssl);
916 SSL_CTX_free (ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100917}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100918
Christian Grothoff191cd982012-02-14 00:48:45 +0100919/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100920
Christian Grothoff88b422b2012-02-14 00:35:09 +0100921int
Will Drewryc45952f2013-09-03 13:51:24 -0500922main (int argc, char **argv)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100923{
924 uint32_t *time_map;
David Goulet0809df12012-07-31 23:27:34 -0400925 struct tlsdate_time start_time, end_time, warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100926 int status;
927 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100928 long long rt_time_ms;
929 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200930 int setclock;
931 int showtime;
Will Drewry72706752013-09-13 15:57:10 -0500932 int showtime_raw;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400933 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400934 int leap;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400935 if (argc != 12)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100936 return 1;
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100937 g_host = argv[1];
938 g_port = argv[2];
939 validate_port(g_port);
940 g_protocol = argv[3];
941 g_ca_cert_container = argv[6];
942 g_ca_racket = (0 != strcmp ("unchecked", argv[4]));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100943 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200944 setclock = (0 == strcmp ("setclock", argv[7]));
945 showtime = (0 == strcmp ("showtime", argv[8]));
Will Drewry72706752013-09-13 15:57:10 -0500946 showtime_raw = (0 == strcmp ("showtime=raw", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400947 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400948 leap = (0 == strcmp ("leapaway", argv[10]));
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100949 g_proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
Will Drewryc45952f2013-09-03 13:51:24 -0500950 clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400951 if (timewarp)
Will Drewryc45952f2013-09-03 13:51:24 -0500952 {
953 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
954 (unsigned long) CLOCK_SEC (&warp_time),
955 (unsigned long) CLOCK_USEC (&warp_time));
956 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200957 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400958 if (0 == setclock && 0 == timewarp)
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400959 {
Will Drewryc45952f2013-09-03 13:51:24 -0500960 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400961 }
Will Drewryc45952f2013-09-03 13:51:24 -0500962 time_map = mmap (NULL, sizeof (uint32_t),
963 PROT_READ | PROT_WRITE,
964 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
965 if (MAP_FAILED == time_map)
966 {
967 fprintf (stderr, "mmap failed: %s\n",
968 strerror (errno));
969 return 1;
970 }
971 /* Get the current time from the system clock. */
972 if (0 != clock_get_real_time (&start_time))
973 {
974 die ("Failed to read current time of day: %s\n", strerror (errno));
975 }
976 verb ("V: time is currently %lu.%06lu\n",
977 (unsigned long) CLOCK_SEC (&start_time),
978 (unsigned long) CLOCK_NSEC (&start_time));
979 if ( ( (unsigned long) CLOCK_SEC (&start_time)) < ( (unsigned long) CLOCK_SEC (&warp_time)))
980 {
981 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
982 if (timewarp)
983 {
984 verb ("V: Attempting to warp local clock into the future\n");
985 if (0 != clock_set_real_time (&warp_time))
986 {
987 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
988 strerror (errno),
989 (unsigned long) CLOCK_SEC (&warp_time),
990 (unsigned long) CLOCK_SEC (&warp_time));
991 }
992 if (0 != clock_get_real_time (&start_time))
993 {
994 die ("Failed to read current time of day: %s\n", strerror (errno));
995 }
996 verb ("V: time is currently %lu.%06lu\n",
997 (unsigned long) CLOCK_SEC (&start_time),
998 (unsigned long) CLOCK_NSEC (&start_time));
999 verb ("V: It's just a step to the left...\n");
1000 }
1001 }
1002 else
1003 {
1004 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
1005 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001006 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001007 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +01001008 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001009 ssl_child = fork ();
1010 if (-1 == ssl_child)
1011 die ("fork failed: %s\n", strerror (errno));
1012 if (0 == ssl_child)
Will Drewryc45952f2013-09-03 13:51:24 -05001013 {
1014 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
1015 run_ssl (time_map, leap);
1016 (void) munmap (time_map, sizeof (uint32_t));
1017 _exit (0);
1018 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001019 if (ssl_child != waitpid (ssl_child, &status, 0))
1020 die ("waitpid failed: %s\n", strerror (errno));
Will Drewryc45952f2013-09-03 13:51:24 -05001021 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
Christian Grothoff191cd982012-02-14 00:48:45 +01001022 die ("child process failed in SSL handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -05001023 if (0 != clock_get_real_time (&end_time))
Christian Grothoff88b422b2012-02-14 00:35:09 +01001024 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +01001025 /* calculate RTT */
Will Drewryc45952f2013-09-03 13:51:24 -05001026 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 +01001027 if (rt_time_ms < 0)
1028 rt_time_ms = 0; /* non-linear time... */
1029 server_time_s = ntohl (*time_map);
1030 munmap (time_map, sizeof (uint32_t));
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001031 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Will Drewryc45952f2013-09-03 13:51:24 -05001032 (unsigned int) server_time_s,
1033 CLOCK_SEC (&start_time) - server_time_s,
1034 rt_time_ms);
Philipp Winterb3ca5772012-02-16 11:56:11 +01001035 /* warning if the handshake took too long */
Will Drewryc45952f2013-09-03 13:51:24 -05001036 if (rt_time_ms > TLS_RTT_THRESHOLD)
1037 {
1038 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
1039 "server or run it again\n", TLS_RTT_THRESHOLD);
1040 }
Will Drewry72706752013-09-13 15:57:10 -05001041 if (showtime_raw)
Will Drewryc45952f2013-09-03 13:51:24 -05001042 {
1043 fwrite (&server_time_s, sizeof (server_time_s), 1, stdout);
1044 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001045 if (showtime)
Will Drewryc45952f2013-09-03 13:51:24 -05001046 {
1047 struct tm ltm;
1048 time_t tim = server_time_s;
1049 char buf[256];
1050 localtime_r (&tim, &ltm);
1051 if (0 == strftime (buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
1052 {
1053 die ("strftime returned 0\n");
1054 }
1055 fprintf (stdout, "%s\n", buf);
1056 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001057 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001058 if (setclock)
Will Drewryc45952f2013-09-03 13:51:24 -05001059 {
1060 struct tlsdate_time server_time;
1061 clock_init_time (&server_time, server_time_s + (rt_time_ms / 2 / 1000),
1062 (rt_time_ms / 2) % 1000);
1063 // We should never receive a time that is before the time we were last
1064 // compiled; we subscribe to the linear theory of time for this program
1065 // and this program alone!
1066 if (CLOCK_SEC (&server_time) >= MAX_REASONABLE_TIME)
1067 die ("remote server is a false ticker from the future!\n");
1068 if (CLOCK_SEC (&server_time) <= RECENT_COMPILE_DATE)
1069 die ("remote server is a false ticker!\n");
1070 if (0 != clock_set_real_time (&server_time))
1071 die ("setting time failed: %s (Difference from server is about %d)\n",
1072 strerror (errno),
1073 CLOCK_SEC (&start_time) - server_time_s);
1074 verb ("V: setting time succeeded\n");
1075 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001076 return 0;
1077}