blob: 7db5e3ccca30a4f4b5196239d1dee39ac927a814 [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 Ershov2012e5b2021-03-25 13:18:13 +0100243 int list_length = get_addrinfo_length (addr_infos);
244 for (int i = 0; i < list_length; ++i)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100245 {
Michael Ershov2012e5b2021-03-25 13:18:13 +0100246 // tlsdate is killed by a supervisor if it takes too long to finish. So it
247 // may not have time to try all the addresses. Selecting randomly makes
248 // it try different addresses during different attempts, that is usefull
249 // when some addresses are not accessible (e.g. first ones).
250 struct addrinfo *current_addr_info =
251 get_addrinfo_element (addr_infos, random () % list_length);
252 if (!current_addr_info) {
253 die ("attempted to use NULL addrinfo");
254 }
255
256 addr_to_str (current_addr_info->ai_addr, addr_str_buf, INET6_ADDRSTRLEN);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100257 verb ("V: attempting to connect to %s\n", addr_str_buf);
Michael Ershov2012e5b2021-03-25 13:18:13 +0100258 sock = socket (current_addr_info->ai_family, SOCK_STREAM, 0);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100259 if (sock < 0)
260 {
261 perror ("socket");
262 continue;
263 }
264
Michael Ershov2012e5b2021-03-25 13:18:13 +0100265 if (connect (sock, current_addr_info->ai_addr,
266 current_addr_info->ai_addrlen) != 0)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100267 {
268 perror ("connect");
269 close (sock);
270 sock = -1;
271 continue;
272 }
273 break;
274 }
Michael Ershov2012e5b2021-03-25 13:18:13 +0100275 freeaddrinfo (addr_infos);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100276
277 if (sock < 0)
278 die ("failed to find any remote addresses for %s:%s\n", host, port);
279
280 return sock;
281}
282
283/* Creates a BIO wrapper over the socket connection to |host|:|port|.
284 * This workaround is needed because BIO_s_connect() doesn't support IPv6.
285 */
286static BIO *BIO_create_socket (const char *host, const char *port)
287{
288 BIO *bio_socket = NULL;
289 int sockfd = create_connection (host, port);
290 if ( !(bio_socket = BIO_new_fd (sockfd, 1 /* close_flag */)))
291 die ("BIO_new_fd failed\n");
292
293 return bio_socket;
294}
295
296/* Creates an OpenSSL BIO-chain which talks to |target_host|:|target_port|
297 * using the SSL protocol. If |proxy| is set it will be used as a HTTP proxy.
298 */
299static BIO *
300make_ssl_bio (SSL_CTX *ctx, const char *target_host, const char *target_port,
301 char *proxy)
302{
303 BIO *bio_socket = NULL;
304 BIO *bio_ssl = NULL;
305 BIO *bio_proxy = NULL;
306 char *scheme = NULL;
307 char *proxy_host = NULL;
308 char *proxy_port = NULL;
309
310 if ( !(bio_ssl = BIO_new_ssl (ctx, 1)))
Will Drewryc45952f2013-09-03 13:51:24 -0500311 die ("BIO_new_ssl failed\n");
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100312
313 if (proxy)
314 {
315 verb ("V: using proxy %s\n", proxy);
316 parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
317
318 if ( !(bio_proxy = BIO_create_proxy (scheme, target_host, target_port)))
319 die ("BIO_create_proxy failed\n");
320
321 bio_socket = BIO_create_socket (proxy_host, proxy_port);
322
323 BIO_push (bio_ssl, bio_proxy);
324 BIO_push (bio_ssl, bio_socket);
325 }
326 else
327 {
328 bio_socket = BIO_create_socket (target_host, target_port);
329 BIO_push (bio_ssl, bio_socket);
330 }
331 return bio_ssl;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400332}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100333
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200334/** helper function for 'malloc' */
335static void *
336xmalloc (size_t size)
337{
338 void *ptr;
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200339 if (0 == size)
Will Drewryc45952f2013-09-03 13:51:24 -0500340 die ("xmalloc: zero size\n");
341 ptr = malloc (size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200342 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500343 die ("xmalloc: out of memory (allocating %zu bytes)\n", size);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200344 return ptr;
345}
346
347
348/** helper function for 'free' */
349static void
350xfree (void *ptr)
351{
Daniel Borkmann592acc52012-07-30 14:08:02 +0200352 if (NULL == ptr)
Will Drewryc45952f2013-09-03 13:51:24 -0500353 die ("xfree: NULL pointer given as argument\n");
354 free (ptr);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200355}
356
357
David Benjamin1aba54c2017-02-05 16:24:49 -0500358static int
359verify_with_server_time (X509_STORE_CTX *store_ctx, void *arg)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700360{
David Benjamin1aba54c2017-02-05 16:24:49 -0500361 SSL *ssl = X509_STORE_CTX_get_ex_data (
362 store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
363
364 // XXX TODO: If we want to trust the remote system for time,
365 // can we just read that time out of the remote system and if the
366 // cert verifies, decide that the time is reasonable?
367 // Such a process seems to indicate that a once valid cert would be
368 // forever valid - we stopgap that by ensuring it isn't less than
369 // the latest compiled_time and isn't above max_reasonable_time...
370 // XXX TODO: Solve eternal question about the Chicken and the Egg...
371 uint32_t compiled_time = RECENT_COMPILE_DATE;
372 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
373 uint32_t server_time;
374 verb ("V: freezing time for x509 verification\n");
375 SSL_get_server_random(ssl, (unsigned char *)&server_time,
376 sizeof (uint32_t));
377 if (compiled_time < ntohl (server_time)
378 &&
379 ntohl (server_time) < max_reasonable_time)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700380 {
David Benjamin1aba54c2017-02-05 16:24:49 -0500381 verb ("V: remote peer provided: %d, preferred over compile time: %d\n",
382 ntohl (server_time), compiled_time);
383 verb ("V: freezing time with X509_VERIFY_PARAM_set_time\n");
384 X509_STORE_CTX_set_time (
385 store_ctx, 0, (time_t) ntohl (server_time) + 86400);
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700386 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500387 else
388 {
389 die ("V: the remote server is a false ticker! server: %d compile: %d\n",
390 ntohl (server_time), compiled_time);
391 }
392
393 return X509_verify_cert (store_ctx);
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700394}
395
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700396uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700397get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700398{
399 /*
400 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
401 */
402 uint32_t key_bits;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600403 switch (EVP_PKEY_id (public_key))
Will Drewryc45952f2013-09-03 13:51:24 -0500404 {
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700405 case EVP_PKEY_RSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500406 verb ("V: key type: EVP_PKEY_RSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700407 break;
408 case EVP_PKEY_RSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500409 verb ("V: key type: EVP_PKEY_RSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700410 break;
411 case EVP_PKEY_DSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500412 verb ("V: key type: EVP_PKEY_DSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700413 break;
414 case EVP_PKEY_DSA1:
Will Drewryc45952f2013-09-03 13:51:24 -0500415 verb ("V: key type: EVP_PKEY_DSA1\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700416 break;
417 case EVP_PKEY_DSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500418 verb ("V: key type: EVP_PKEY_DSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700419 break;
420 case EVP_PKEY_DSA3:
Will Drewryc45952f2013-09-03 13:51:24 -0500421 verb ("V: key type: EVP_PKEY_DSA3\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700422 break;
423 case EVP_PKEY_DSA4:
Will Drewryc45952f2013-09-03 13:51:24 -0500424 verb ("V: key type: EVP_PKEY_DSA4\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700425 break;
426 case EVP_PKEY_DH:
Will Drewryc45952f2013-09-03 13:51:24 -0500427 verb ("V: key type: EVP_PKEY_DH\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700428 break;
429 case EVP_PKEY_EC:
Will Drewryc45952f2013-09-03 13:51:24 -0500430 verb ("V: key type: EVP_PKEY_EC\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700431 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500432 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700433 default:
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700434 die ("unknown public key type\n");
435 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500436 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600437 key_bits = EVP_PKEY_bits (public_key);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700438 verb ("V: keybits: %d\n", key_bits);
439 return key_bits;
440}
441
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700442uint32_t
Will Drewryc45952f2013-09-03 13:51:24 -0500443dns_label_count (char *label, char *delim)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700444{
445 char *label_tmp;
446 char *saveptr;
447 char *saveptr_tmp;
448 uint32_t label_count;
Will Drewryc45952f2013-09-03 13:51:24 -0500449 label_tmp = strdup (label);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700450 label_count = 0;
451 saveptr = NULL;
452 saveptr_tmp = NULL;
Will Drewryc45952f2013-09-03 13:51:24 -0500453 saveptr = strtok_r (label_tmp, delim, &saveptr);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700454 if (NULL != saveptr)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700455 {
Will Drewryc45952f2013-09-03 13:51:24 -0500456 // Did we find our first label?
457 if (saveptr[0] != delim[0])
458 {
459 label_count++;
460 verb ("V: label found; total label count: %d\n", label_count);
461 }
462 do
463 {
464 // Find all subsequent labels
465 label_count++;
466 saveptr_tmp = strtok_r (NULL, delim, &saveptr);
467 verb ("V: label found; total label count: %d\n", label_count);
468 }
469 while (NULL != saveptr_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700470 }
Will Drewryc45952f2013-09-03 13:51:24 -0500471 free (label_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700472 return label_count;
473}
474
475// first we split strings on '.'
476// then we call each split string a 'label'
477// Do not allow '*' for the top level domain label; eg never allow *.*.com
478// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
479// Do allow *.example.com
480uint32_t
481check_wildcard_match_rfc2595 (const char *orig_hostname,
Will Drewryc45952f2013-09-03 13:51:24 -0500482 const char *orig_cert_wild_card)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700483{
484 char *hostname;
485 char *hostname_to_free;
486 char *cert_wild_card;
487 char *cert_wild_card_to_free;
488 char *expected_label;
489 char *wildcard_label;
490 char *delim;
491 char *wildchar;
492 uint32_t ok;
493 uint32_t wildcard_encountered;
494 uint32_t label_count;
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700495 // First we copy the original strings
Will Drewryc45952f2013-09-03 13:51:24 -0500496 hostname = strndup (orig_hostname, strlen (orig_hostname));
497 cert_wild_card = strndup (orig_cert_wild_card, strlen (orig_cert_wild_card));
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700498 hostname_to_free = hostname;
499 cert_wild_card_to_free = cert_wild_card;
Will Drewryc45952f2013-09-03 13:51:24 -0500500 delim = strdup (".");
501 wildchar = strdup ("*");
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700502 verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
Will Drewryc45952f2013-09-03 13:51:24 -0500503 hostname, cert_wild_card);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700504 // By default we have not processed any labels
Will Drewryc45952f2013-09-03 13:51:24 -0500505 label_count = dns_label_count (cert_wild_card, delim);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700506 // By default we have no match
507 ok = 0;
508 wildcard_encountered = 0;
509 // First - do we have labels? If not, we refuse to even try to match
Will Drewryc45952f2013-09-03 13:51:24 -0500510 if ( (NULL != strpbrk (cert_wild_card, delim)) &&
511 (NULL != strpbrk (hostname, delim)) &&
512 (label_count <= ( (uint32_t) RFC2595_MIN_LABEL_COUNT)))
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700513 {
Will Drewryc45952f2013-09-03 13:51:24 -0500514 if (wildchar[0] == cert_wild_card[0])
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700515 {
Will Drewryc45952f2013-09-03 13:51:24 -0500516 verb ("V: Found wildcard in at start of provided certificate name\n");
517 do
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700518 {
Will Drewryc45952f2013-09-03 13:51:24 -0500519 // Skip over the bytes between the first char and until the next label
520 wildcard_label = strsep (&cert_wild_card, delim);
521 expected_label = strsep (&hostname, delim);
522 if (NULL != wildcard_label &&
523 NULL != expected_label &&
524 NULL != hostname &&
525 NULL != cert_wild_card)
526 {
527 // Now we only consider this wildcard valid if the rest of the
528 // hostnames match verbatim
529 verb ("V: Attempting match of '%s' against '%s'\n",
530 expected_label, wildcard_label);
531 // This is the case where we have a label that begins with wildcard
532 // Furthermore, we only allow this for the first label
533 if (wildcard_label[0] == wildchar[0] &&
534 0 == wildcard_encountered && 0 == ok)
535 {
536 verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
537 wildcard_encountered = 1;
538 }
539 else
540 {
541 verb ("V: Attempting match of '%s' against '%s'\n",
542 hostname, cert_wild_card);
543 if (0 == strcasecmp (expected_label, wildcard_label) &&
544 label_count >= ( (uint32_t) RFC2595_MIN_LABEL_COUNT))
545 {
546 ok = 1;
547 verb ("V: remaining labels match!\n");
548 break;
549 }
550 else
551 {
552 ok = 0;
553 verb ("V: remaining labels do not match!\n");
554 break;
555 }
556 }
557 }
558 else
559 {
560 // We hit this case when we have a mismatched number of labels
561 verb ("V: NULL label; no wildcard here\n");
562 break;
563 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700564 }
Will Drewryc45952f2013-09-03 13:51:24 -0500565 while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700566 }
Will Drewryc45952f2013-09-03 13:51:24 -0500567 else
568 {
569 verb ("V: Not a RFC 2595 wildcard\n");
570 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700571 }
Will Drewryc45952f2013-09-03 13:51:24 -0500572 else
573 {
574 verb ("V: Not a valid wildcard certificate\n");
575 ok = 0;
576 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700577 // Free our copies
Will Drewryc45952f2013-09-03 13:51:24 -0500578 free (wildchar);
579 free (delim);
580 free (hostname_to_free);
581 free (cert_wild_card_to_free);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700582 if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
Will Drewryc45952f2013-09-03 13:51:24 -0500583 {
584 verb ("V: wildcard match of %s against %s\n",
585 orig_hostname, orig_cert_wild_card);
586 return (wildcard_encountered & ok);
587 }
588 else
589 {
590 verb ("V: wildcard match failure of %s against %s\n",
591 orig_hostname, orig_cert_wild_card);
592 return 0;
593 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700594}
595
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700596/**
597 This extracts the first commonName and checks it against hostname.
598*/
599uint32_t
600check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700601{
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200602 int ok = 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700603 uint32_t ret;
604 char *cn_buf;
605 X509 *certificate;
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700606 X509_NAME *xname;
Will Drewryc45952f2013-09-03 13:51:24 -0500607 cn_buf = xmalloc (TLSDATE_HOST_NAME_MAX + 1);
608 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700609 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500610 {
611 die ("Unable to extract certificate\n");
612 }
613 memset (cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
614 xname = X509_get_subject_name (certificate);
615 ret = X509_NAME_get_text_by_NID (xname, NID_commonName,
616 cn_buf, TLSDATE_HOST_NAME_MAX);
617 if (-1 == ret && ret != strlen (hostname))
618 {
619 die ("Unable to extract commonName\n");
620 }
621 if (strcasecmp (cn_buf, hostname))
622 {
623 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
624 hostname, cn_buf);
625 }
626 else
627 {
628 verb ("V: commonName matched: %s\n", cn_buf);
629 ok = 1;
630 }
631 X509_NAME_free (xname);
632 X509_free (certificate);
633 xfree (cn_buf);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200634 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700635}
636
637/**
638 Search for a hostname match in the SubjectAlternativeNames.
639*/
640uint32_t
641check_san (SSL *ssl, const char *hostname)
642{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700643 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700644 int extcount, ok = 0;
645 /* What an OpenSSL mess ... */
Will Drewryc45952f2013-09-03 13:51:24 -0500646 if (NULL == (cert = SSL_get_peer_certificate (ssl)))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700647 {
Will Drewryc45952f2013-09-03 13:51:24 -0500648 die ("Getting certificate failed\n");
649 }
650 if ( (extcount = X509_get_ext_count (cert)) > 0)
651 {
652 int i;
653 for (i = 0; i < extcount; ++i)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700654 {
Will Drewryc45952f2013-09-03 13:51:24 -0500655 const char *extstr;
656 X509_EXTENSION *ext;
657 ext = X509_get_ext (cert, i);
658 extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext)));
659 if (!strcmp (extstr, "subjectAltName"))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700660 {
Will Drewryc45952f2013-09-03 13:51:24 -0500661 int j;
662 void *extvalstr;
Will Drewryc45952f2013-09-03 13:51:24 -0500663 STACK_OF (CONF_VALUE) *val;
664 CONF_VALUE *nval;
665#if OPENSSL_VERSION_NUMBER >= 0x10000000L
666 const
667#endif
668 X509V3_EXT_METHOD *method;
669 if (! (method = X509V3_EXT_get (ext)))
670 {
671 break;
672 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600673 extvalstr = X509V3_EXT_d2i(ext);
Will Drewryc45952f2013-09-03 13:51:24 -0500674 if (!extvalstr)
675 {
676 break;
677 }
678 if (method->i2v)
679 {
680 val = method->i2v (method, extvalstr, NULL);
681 for (j = 0; j < sk_CONF_VALUE_num (val); ++j)
682 {
683 nval = sk_CONF_VALUE_value (val, j);
684 if ( (!strcasecmp (nval->name, "DNS") &&
685 !strcasecmp (nval->value, hostname)) ||
686 (!strcasecmp (nval->name, "iPAddress") &&
687 !strcasecmp (nval->value, hostname)))
688 {
689 verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
690 ok = 1;
691 break;
692 }
693 // Attempt to match subjectAltName DNS names
694 if (!strcasecmp (nval->name, "DNS"))
695 {
696 ok = check_wildcard_match_rfc2595 (hostname, nval->value);
697 if (ok)
698 {
699 break;
700 }
701 }
702 verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
703 }
704 }
705 }
706 else
707 {
708 verb ("V: found non subjectAltName extension\n");
709 }
710 if (ok)
711 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700712 break;
713 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700714 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700715 }
Will Drewryc45952f2013-09-03 13:51:24 -0500716 else
717 {
718 verb ("V: no X509_EXTENSION field(s) found\n");
719 }
720 X509_free (cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700721 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700722}
723
724uint32_t
725check_name (SSL *ssl, const char *hostname)
726{
727 uint32_t ret;
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700728 ret = 0;
Will Drewryc45952f2013-09-03 13:51:24 -0500729 ret = check_cn (ssl, hostname);
730 ret += check_san (ssl, hostname);
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700731 if (0 != ret && 0 < ret)
Will Drewryc45952f2013-09-03 13:51:24 -0500732 {
733 verb ("V: hostname verification passed\n");
734 }
735 else
736 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100737 die ("hostname verification failed for host %s!\n", g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500738 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700739 return ret;
740}
741
742uint32_t
743verify_signature (SSL *ssl, const char *hostname)
744{
745 long ssl_verify_result;
746 X509 *certificate;
Will Drewryc45952f2013-09-03 13:51:24 -0500747 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700748 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500749 {
750 die ("Getting certificate failed\n");
751 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700752 // In theory, we verify that the cert is valid
Will Drewryc45952f2013-09-03 13:51:24 -0500753 ssl_verify_result = SSL_get_verify_result (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700754 switch (ssl_verify_result)
Will Drewryc45952f2013-09-03 13:51:24 -0500755 {
756 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
757 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
758 die ("certificate is self signed\n");
759 case X509_V_OK:
760 verb ("V: certificate verification passed\n");
761 break;
762 default:
763 die ("certification verification error: %ld\n",
764 ssl_verify_result);
765 }
766 return 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700767}
768
769void
770check_key_length (SSL *ssl)
771{
772 uint32_t key_bits;
773 X509 *certificate;
774 EVP_PKEY *public_key;
775 certificate = SSL_get_peer_certificate (ssl);
A soldier31056a62012-08-16 01:10:57 -0700776 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500777 {
778 die ("Getting certificate failed\n");
779 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700780 public_key = X509_get_pubkey (certificate);
781 if (NULL == public_key)
Will Drewryc45952f2013-09-03 13:51:24 -0500782 {
783 die ("public key extraction failure\n");
784 }
785 else
786 {
787 verb ("V: public key is ready for inspection\n");
788 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700789 key_bits = get_certificate_keybits (public_key);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600790 if (MIN_PUB_KEY_LEN >= key_bits && EVP_PKEY_id(public_key) != EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500791 {
792 die ("Unsafe public key size: %d bits\n", key_bits);
793 }
794 else
795 {
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600796 if (EVP_PKEY_id(public_key) == EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500797 if (key_bits >= MIN_ECC_PUB_KEY_LEN
798 && key_bits <= MAX_ECC_PUB_KEY_LEN)
799 {
800 verb ("V: ECC key length appears safe\n");
801 }
802 else
803 {
804 die ("Unsafe ECC key size: %d bits\n", key_bits);
805 }
806 else
807 {
808 verb ("V: key length appears safe\n");
809 }
810 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700811 EVP_PKEY_free (public_key);
812}
813
814void
815inspect_key (SSL *ssl, const char *hostname)
816{
Will Drewryc45952f2013-09-03 13:51:24 -0500817 verify_signature (ssl, hostname);
818 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700819}
820
Christian Grothoff88b422b2012-02-14 00:35:09 +0100821/**
822 * Run SSL handshake and store the resulting time value in the
823 * 'time_map'.
824 *
825 * @param time_map where to store the current time
826 */
827static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400828run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100829{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100830 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100831 SSL_CTX *ctx;
832 SSL *ssl;
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800833 struct stat statbuf;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100834 SSL_load_error_strings();
835 SSL_library_init();
Christian Grothoff90e9f832012-02-07 11:16:47 +0100836 ctx = NULL;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600837
Mattias Nissler3da9da42020-02-13 11:27:41 +0100838 /*
839 * Some of the XYZ_method() calls below are marked deprecated. We still want
840 * to use them for compatibility reasons, so silence the warnings or they'll
841 * break the build.
842 */
843#pragma GCC diagnostic push
844#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
845
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100846 if (0 == strcmp ("sslv23", g_protocol))
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800847 {
Will Drewryc45952f2013-09-03 13:51:24 -0500848 verb ("V: using SSLv23_client_method()\n");
849 ctx = SSL_CTX_new (SSLv23_client_method());
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800850 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100851#ifndef OPENSSL_NO_SSL3_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100852 else if (0 == strcmp ("sslv3", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500853 {
854 verb ("V: using SSLv3_client_method()\n");
855 ctx = SSL_CTX_new (SSLv3_client_method());
856 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100857#endif
858#ifndef OPENSSL_NO_TLS1_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100859 else if (0 == strcmp ("tlsv1", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500860 {
861 verb ("V: using TLSv1_client_method()\n");
862 ctx = SSL_CTX_new (TLSv1_client_method());
863 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100864#endif
865#ifndef OPENSSL_NO_TLS1_1_METHOD
866 else if (0 == strcmp ("tlsv11", g_protocol))
867 {
868 verb ("V: using TLSv1_1_client_method()\n");
869 ctx = SSL_CTX_new (TLSv1_1_client_method());
870 }
871#endif
872#ifndef OPENSSL_NO_TLS1_2_METHOD
873 else if (0 == strcmp ("tlsv12", g_protocol))
874 {
875 verb ("V: using TLSv1_2_client_method()\n");
876 ctx = SSL_CTX_new (TLSv1_2_client_method());
877 }
878#endif
Will Drewryc45952f2013-09-03 13:51:24 -0500879 else
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100880 die ("Unsupported protocol `%s'\n", g_protocol);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600881
Mattias Nissler3da9da42020-02-13 11:27:41 +0100882#pragma GCC diagnostic pop
883
Will Drewryc45952f2013-09-03 13:51:24 -0500884 if (ctx == NULL)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100885 die ("OpenSSL failed to support protocol `%s'\n", g_protocol);
886 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500887 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100888 if (-1 == stat (g_ca_cert_container, &statbuf))
Will Drewryc45952f2013-09-03 13:51:24 -0500889 {
890 die ("Unable to stat CA certficate container\n");
891 }
892 else
893 {
894 switch (statbuf.st_mode & S_IFMT)
895 {
896 case S_IFREG:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100897 if (1 != SSL_CTX_load_verify_locations(
898 ctx, g_ca_cert_container, NULL))
899 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500900 break;
901 case S_IFDIR:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100902 if (1 != SSL_CTX_load_verify_locations(
903 ctx, NULL, g_ca_cert_container))
904 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500905 break;
906 default:
907 die ("Unable to load CA certficate container\n");
908 }
909 }
910 }
David Benjamin1aba54c2017-02-05 16:24:49 -0500911
912 if (time_is_an_illusion)
913 {
914 SSL_CTX_set_cert_verify_callback (ctx, verify_with_server_time, NULL);
915 }
916
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100917 verb ("V: setting up connection to %s:%s\n", g_host, g_port);
918 if (NULL == (s_bio = make_ssl_bio(ctx, g_host, g_port, g_proxy)))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100919 die ("SSL BIO setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500920 BIO_get_ssl (s_bio, &ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100921 if (NULL == ssl)
922 die ("SSL setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500923 SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100924 SSL_set_tlsext_host_name (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500925 if (NULL == BIO_new_fp (stdout, BIO_NOCLOSE))
926 die ("BIO_new_fp returned error, possibly: %s", strerror (errno));
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800927 // This should run in seccomp
928 // eg: prctl(PR_SET_SECCOMP, 1);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100929 verb ("V: BIO_do_connect\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500930 if (1 != BIO_do_connect (s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800931 die ("SSL connection failed\n");
Pavol Markod9dd19d2020-01-17 23:32:57 +0100932 verb ("V: BIO_do_handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500933 if (1 != BIO_do_handshake (s_bio))
Philipp Winterd96af622012-02-15 22:15:50 +0100934 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100935 // Verify the peer certificate against the CA certs on the local system
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100936 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500937 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100938 inspect_key (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500939 }
940 else
941 {
942 verb ("V: Certificate verification skipped!\n");
943 }
944 check_key_length (ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100945 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700946 // ssl->s3->server_random is an unsigned char of 32 bits
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600947 SSL_get_server_random(ssl, (unsigned char *)time_map, sizeof(uint32_t));
Will Drewryc45952f2013-09-03 13:51:24 -0500948 SSL_free (ssl);
949 SSL_CTX_free (ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100950}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100951
Christian Grothoff191cd982012-02-14 00:48:45 +0100952/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100953
Christian Grothoff88b422b2012-02-14 00:35:09 +0100954int
Will Drewryc45952f2013-09-03 13:51:24 -0500955main (int argc, char **argv)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100956{
957 uint32_t *time_map;
David Goulet0809df12012-07-31 23:27:34 -0400958 struct tlsdate_time start_time, end_time, warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100959 int status;
960 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100961 long long rt_time_ms;
962 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200963 int setclock;
964 int showtime;
Will Drewry72706752013-09-13 15:57:10 -0500965 int showtime_raw;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400966 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400967 int leap;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400968 if (argc != 12)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100969 return 1;
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100970 g_host = argv[1];
971 g_port = argv[2];
972 validate_port(g_port);
973 g_protocol = argv[3];
974 g_ca_cert_container = argv[6];
975 g_ca_racket = (0 != strcmp ("unchecked", argv[4]));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100976 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200977 setclock = (0 == strcmp ("setclock", argv[7]));
978 showtime = (0 == strcmp ("showtime", argv[8]));
Will Drewry72706752013-09-13 15:57:10 -0500979 showtime_raw = (0 == strcmp ("showtime=raw", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400980 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400981 leap = (0 == strcmp ("leapaway", argv[10]));
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100982 g_proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
Michael Ershov2012e5b2021-03-25 13:18:13 +0100983 srandom(time(NULL));
Will Drewryc45952f2013-09-03 13:51:24 -0500984 clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400985 if (timewarp)
Will Drewryc45952f2013-09-03 13:51:24 -0500986 {
987 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
988 (unsigned long) CLOCK_SEC (&warp_time),
989 (unsigned long) CLOCK_USEC (&warp_time));
990 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200991 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400992 if (0 == setclock && 0 == timewarp)
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400993 {
Will Drewryc45952f2013-09-03 13:51:24 -0500994 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400995 }
Will Drewryc45952f2013-09-03 13:51:24 -0500996 time_map = mmap (NULL, sizeof (uint32_t),
997 PROT_READ | PROT_WRITE,
998 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
999 if (MAP_FAILED == time_map)
1000 {
1001 fprintf (stderr, "mmap failed: %s\n",
1002 strerror (errno));
1003 return 1;
1004 }
1005 /* Get the current time from the system clock. */
1006 if (0 != clock_get_real_time (&start_time))
1007 {
1008 die ("Failed to read current time of day: %s\n", strerror (errno));
1009 }
1010 verb ("V: time is currently %lu.%06lu\n",
1011 (unsigned long) CLOCK_SEC (&start_time),
1012 (unsigned long) CLOCK_NSEC (&start_time));
1013 if ( ( (unsigned long) CLOCK_SEC (&start_time)) < ( (unsigned long) CLOCK_SEC (&warp_time)))
1014 {
1015 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
1016 if (timewarp)
1017 {
1018 verb ("V: Attempting to warp local clock into the future\n");
1019 if (0 != clock_set_real_time (&warp_time))
1020 {
1021 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
1022 strerror (errno),
1023 (unsigned long) CLOCK_SEC (&warp_time),
1024 (unsigned long) CLOCK_SEC (&warp_time));
1025 }
1026 if (0 != clock_get_real_time (&start_time))
1027 {
1028 die ("Failed to read current time of day: %s\n", strerror (errno));
1029 }
1030 verb ("V: time is currently %lu.%06lu\n",
1031 (unsigned long) CLOCK_SEC (&start_time),
1032 (unsigned long) CLOCK_NSEC (&start_time));
1033 verb ("V: It's just a step to the left...\n");
1034 }
1035 }
1036 else
1037 {
1038 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
1039 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001040 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001041 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +01001042 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001043 ssl_child = fork ();
1044 if (-1 == ssl_child)
1045 die ("fork failed: %s\n", strerror (errno));
1046 if (0 == ssl_child)
Will Drewryc45952f2013-09-03 13:51:24 -05001047 {
1048 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
1049 run_ssl (time_map, leap);
1050 (void) munmap (time_map, sizeof (uint32_t));
1051 _exit (0);
1052 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001053 if (ssl_child != waitpid (ssl_child, &status, 0))
1054 die ("waitpid failed: %s\n", strerror (errno));
Will Drewryc45952f2013-09-03 13:51:24 -05001055 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
Christian Grothoff191cd982012-02-14 00:48:45 +01001056 die ("child process failed in SSL handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -05001057 if (0 != clock_get_real_time (&end_time))
Christian Grothoff88b422b2012-02-14 00:35:09 +01001058 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +01001059 /* calculate RTT */
Will Drewryc45952f2013-09-03 13:51:24 -05001060 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 +01001061 if (rt_time_ms < 0)
1062 rt_time_ms = 0; /* non-linear time... */
1063 server_time_s = ntohl (*time_map);
1064 munmap (time_map, sizeof (uint32_t));
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001065 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Will Drewryc45952f2013-09-03 13:51:24 -05001066 (unsigned int) server_time_s,
1067 CLOCK_SEC (&start_time) - server_time_s,
1068 rt_time_ms);
Philipp Winterb3ca5772012-02-16 11:56:11 +01001069 /* warning if the handshake took too long */
Will Drewryc45952f2013-09-03 13:51:24 -05001070 if (rt_time_ms > TLS_RTT_THRESHOLD)
1071 {
1072 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
1073 "server or run it again\n", TLS_RTT_THRESHOLD);
1074 }
Will Drewry72706752013-09-13 15:57:10 -05001075 if (showtime_raw)
Will Drewryc45952f2013-09-03 13:51:24 -05001076 {
1077 fwrite (&server_time_s, sizeof (server_time_s), 1, stdout);
1078 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001079 if (showtime)
Will Drewryc45952f2013-09-03 13:51:24 -05001080 {
1081 struct tm ltm;
1082 time_t tim = server_time_s;
1083 char buf[256];
1084 localtime_r (&tim, &ltm);
1085 if (0 == strftime (buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
1086 {
1087 die ("strftime returned 0\n");
1088 }
1089 fprintf (stdout, "%s\n", buf);
1090 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001091 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001092 if (setclock)
Will Drewryc45952f2013-09-03 13:51:24 -05001093 {
1094 struct tlsdate_time server_time;
1095 clock_init_time (&server_time, server_time_s + (rt_time_ms / 2 / 1000),
1096 (rt_time_ms / 2) % 1000);
1097 // We should never receive a time that is before the time we were last
1098 // compiled; we subscribe to the linear theory of time for this program
1099 // and this program alone!
1100 if (CLOCK_SEC (&server_time) >= MAX_REASONABLE_TIME)
1101 die ("remote server is a false ticker from the future!\n");
1102 if (CLOCK_SEC (&server_time) <= RECENT_COMPILE_DATE)
1103 die ("remote server is a false ticker!\n");
1104 if (0 != clock_set_real_time (&server_time))
1105 die ("setting time failed: %s (Difference from server is about %d)\n",
1106 strerror (errno),
1107 CLOCK_SEC (&start_time) - server_time_s);
1108 verb ("V: setting time succeeded\n");
1109 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001110 return 0;
1111}