blob: 5821dd9f547eaf78fd0989a63db931cf9f997bfa [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
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700325void
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700326openssl_time_callback (const SSL* ssl, int where, int ret)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700327{
A soldier31056a62012-08-16 01:10:57 -0700328 if (where == SSL_CB_CONNECT_LOOP &&
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600329#if OPENSSL_VERSION_NUMBER < 0x10100000L
Elly Fong-Jones9b811a42012-12-13 16:17:21 -0500330 (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600331#else
332 (SSL_get_state(ssl) == TLS_ST_CR_SRVR_HELLO))
333#endif
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700334 {
Will Drewryc45952f2013-09-03 13:51:24 -0500335 // XXX TODO: If we want to trust the remote system for time,
336 // can we just read that time out of the remote system and if the
337 // cert verifies, decide that the time is reasonable?
338 // Such a process seems to indicate that a once valid cert would be
339 // forever valid - we stopgap that by ensuring it isn't less than
340 // the latest compiled_time and isn't above max_reasonable_time...
341 // XXX TODO: Solve eternal question about the Chicken and the Egg...
342 uint32_t compiled_time = RECENT_COMPILE_DATE;
343 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
344 uint32_t server_time;
345 verb ("V: freezing time for x509 verification\n");
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600346 SSL_get_server_random(ssl, (unsigned char *)&server_time,
347 sizeof (uint32_t));
Will Drewryc45952f2013-09-03 13:51:24 -0500348 if (compiled_time < ntohl (server_time)
349 &&
350 ntohl (server_time) < max_reasonable_time)
351 {
352 verb ("V: remote peer provided: %d, preferred over compile time: %d\n",
353 ntohl (server_time), compiled_time);
354 verb ("V: freezing time with X509_VERIFY_PARAM_set_time\n");
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600355 X509_VERIFY_PARAM_set_time (SSL_get0_param((SSL *)ssl),
Will Drewryc45952f2013-09-03 13:51:24 -0500356 (time_t) ntohl (server_time) + 86400);
357 }
358 else
359 {
360 die ("V: the remote server is a false ticker! server: %d compile: %d\n",
361 ntohl (server_time), compiled_time);
362 }
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700363 }
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700364}
365
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700366uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700367get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700368{
369 /*
370 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
371 */
372 uint32_t key_bits;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600373 switch (EVP_PKEY_id (public_key))
Will Drewryc45952f2013-09-03 13:51:24 -0500374 {
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700375 case EVP_PKEY_RSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500376 verb ("V: key type: EVP_PKEY_RSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700377 break;
378 case EVP_PKEY_RSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500379 verb ("V: key type: EVP_PKEY_RSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700380 break;
381 case EVP_PKEY_DSA:
Will Drewryc45952f2013-09-03 13:51:24 -0500382 verb ("V: key type: EVP_PKEY_DSA\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700383 break;
384 case EVP_PKEY_DSA1:
Will Drewryc45952f2013-09-03 13:51:24 -0500385 verb ("V: key type: EVP_PKEY_DSA1\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700386 break;
387 case EVP_PKEY_DSA2:
Will Drewryc45952f2013-09-03 13:51:24 -0500388 verb ("V: key type: EVP_PKEY_DSA2\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700389 break;
390 case EVP_PKEY_DSA3:
Will Drewryc45952f2013-09-03 13:51:24 -0500391 verb ("V: key type: EVP_PKEY_DSA3\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700392 break;
393 case EVP_PKEY_DSA4:
Will Drewryc45952f2013-09-03 13:51:24 -0500394 verb ("V: key type: EVP_PKEY_DSA4\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700395 break;
396 case EVP_PKEY_DH:
Will Drewryc45952f2013-09-03 13:51:24 -0500397 verb ("V: key type: EVP_PKEY_DH\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700398 break;
399 case EVP_PKEY_EC:
Will Drewryc45952f2013-09-03 13:51:24 -0500400 verb ("V: key type: EVP_PKEY_EC\n");
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700401 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500402 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700403 default:
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700404 die ("unknown public key type\n");
405 break;
Will Drewryc45952f2013-09-03 13:51:24 -0500406 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600407 key_bits = EVP_PKEY_bits (public_key);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700408 verb ("V: keybits: %d\n", key_bits);
409 return key_bits;
410}
411
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700412uint32_t
Will Drewryc45952f2013-09-03 13:51:24 -0500413dns_label_count (char *label, char *delim)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700414{
415 char *label_tmp;
416 char *saveptr;
417 char *saveptr_tmp;
418 uint32_t label_count;
Will Drewryc45952f2013-09-03 13:51:24 -0500419 label_tmp = strdup (label);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700420 label_count = 0;
421 saveptr = NULL;
422 saveptr_tmp = NULL;
Will Drewryc45952f2013-09-03 13:51:24 -0500423 saveptr = strtok_r (label_tmp, delim, &saveptr);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700424 if (NULL != saveptr)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700425 {
Will Drewryc45952f2013-09-03 13:51:24 -0500426 // Did we find our first label?
427 if (saveptr[0] != delim[0])
428 {
429 label_count++;
430 verb ("V: label found; total label count: %d\n", label_count);
431 }
432 do
433 {
434 // Find all subsequent labels
435 label_count++;
436 saveptr_tmp = strtok_r (NULL, delim, &saveptr);
437 verb ("V: label found; total label count: %d\n", label_count);
438 }
439 while (NULL != saveptr_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700440 }
Will Drewryc45952f2013-09-03 13:51:24 -0500441 free (label_tmp);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700442 return label_count;
443}
444
445// first we split strings on '.'
446// then we call each split string a 'label'
447// Do not allow '*' for the top level domain label; eg never allow *.*.com
448// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
449// Do allow *.example.com
450uint32_t
451check_wildcard_match_rfc2595 (const char *orig_hostname,
Will Drewryc45952f2013-09-03 13:51:24 -0500452 const char *orig_cert_wild_card)
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700453{
454 char *hostname;
455 char *hostname_to_free;
456 char *cert_wild_card;
457 char *cert_wild_card_to_free;
458 char *expected_label;
459 char *wildcard_label;
460 char *delim;
461 char *wildchar;
462 uint32_t ok;
463 uint32_t wildcard_encountered;
464 uint32_t label_count;
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700465 // First we copy the original strings
Will Drewryc45952f2013-09-03 13:51:24 -0500466 hostname = strndup (orig_hostname, strlen (orig_hostname));
467 cert_wild_card = strndup (orig_cert_wild_card, strlen (orig_cert_wild_card));
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700468 hostname_to_free = hostname;
469 cert_wild_card_to_free = cert_wild_card;
Will Drewryc45952f2013-09-03 13:51:24 -0500470 delim = strdup (".");
471 wildchar = strdup ("*");
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700472 verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
Will Drewryc45952f2013-09-03 13:51:24 -0500473 hostname, cert_wild_card);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700474 // By default we have not processed any labels
Will Drewryc45952f2013-09-03 13:51:24 -0500475 label_count = dns_label_count (cert_wild_card, delim);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700476 // By default we have no match
477 ok = 0;
478 wildcard_encountered = 0;
479 // First - do we have labels? If not, we refuse to even try to match
Will Drewryc45952f2013-09-03 13:51:24 -0500480 if ( (NULL != strpbrk (cert_wild_card, delim)) &&
481 (NULL != strpbrk (hostname, delim)) &&
482 (label_count <= ( (uint32_t) RFC2595_MIN_LABEL_COUNT)))
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700483 {
Will Drewryc45952f2013-09-03 13:51:24 -0500484 if (wildchar[0] == cert_wild_card[0])
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700485 {
Will Drewryc45952f2013-09-03 13:51:24 -0500486 verb ("V: Found wildcard in at start of provided certificate name\n");
487 do
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700488 {
Will Drewryc45952f2013-09-03 13:51:24 -0500489 // Skip over the bytes between the first char and until the next label
490 wildcard_label = strsep (&cert_wild_card, delim);
491 expected_label = strsep (&hostname, delim);
492 if (NULL != wildcard_label &&
493 NULL != expected_label &&
494 NULL != hostname &&
495 NULL != cert_wild_card)
496 {
497 // Now we only consider this wildcard valid if the rest of the
498 // hostnames match verbatim
499 verb ("V: Attempting match of '%s' against '%s'\n",
500 expected_label, wildcard_label);
501 // This is the case where we have a label that begins with wildcard
502 // Furthermore, we only allow this for the first label
503 if (wildcard_label[0] == wildchar[0] &&
504 0 == wildcard_encountered && 0 == ok)
505 {
506 verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
507 wildcard_encountered = 1;
508 }
509 else
510 {
511 verb ("V: Attempting match of '%s' against '%s'\n",
512 hostname, cert_wild_card);
513 if (0 == strcasecmp (expected_label, wildcard_label) &&
514 label_count >= ( (uint32_t) RFC2595_MIN_LABEL_COUNT))
515 {
516 ok = 1;
517 verb ("V: remaining labels match!\n");
518 break;
519 }
520 else
521 {
522 ok = 0;
523 verb ("V: remaining labels do not match!\n");
524 break;
525 }
526 }
527 }
528 else
529 {
530 // We hit this case when we have a mismatched number of labels
531 verb ("V: NULL label; no wildcard here\n");
532 break;
533 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700534 }
Will Drewryc45952f2013-09-03 13:51:24 -0500535 while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700536 }
Will Drewryc45952f2013-09-03 13:51:24 -0500537 else
538 {
539 verb ("V: Not a RFC 2595 wildcard\n");
540 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700541 }
Will Drewryc45952f2013-09-03 13:51:24 -0500542 else
543 {
544 verb ("V: Not a valid wildcard certificate\n");
545 ok = 0;
546 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700547 // Free our copies
Will Drewryc45952f2013-09-03 13:51:24 -0500548 free (wildchar);
549 free (delim);
550 free (hostname_to_free);
551 free (cert_wild_card_to_free);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700552 if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
Will Drewryc45952f2013-09-03 13:51:24 -0500553 {
554 verb ("V: wildcard match of %s against %s\n",
555 orig_hostname, orig_cert_wild_card);
556 return (wildcard_encountered & ok);
557 }
558 else
559 {
560 verb ("V: wildcard match failure of %s against %s\n",
561 orig_hostname, orig_cert_wild_card);
562 return 0;
563 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700564}
565
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700566/**
567 This extracts the first commonName and checks it against hostname.
568*/
569uint32_t
570check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700571{
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200572 int ok = 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700573 uint32_t ret;
574 char *cn_buf;
575 X509 *certificate;
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700576 X509_NAME *xname;
Will Drewryc45952f2013-09-03 13:51:24 -0500577 cn_buf = xmalloc (TLSDATE_HOST_NAME_MAX + 1);
578 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700579 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500580 {
581 die ("Unable to extract certificate\n");
582 }
583 memset (cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
584 xname = X509_get_subject_name (certificate);
585 ret = X509_NAME_get_text_by_NID (xname, NID_commonName,
586 cn_buf, TLSDATE_HOST_NAME_MAX);
587 if (-1 == ret && ret != strlen (hostname))
588 {
589 die ("Unable to extract commonName\n");
590 }
591 if (strcasecmp (cn_buf, hostname))
592 {
593 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
594 hostname, cn_buf);
595 }
596 else
597 {
598 verb ("V: commonName matched: %s\n", cn_buf);
599 ok = 1;
600 }
601 X509_NAME_free (xname);
602 X509_free (certificate);
603 xfree (cn_buf);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200604 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700605}
606
607/**
608 Search for a hostname match in the SubjectAlternativeNames.
609*/
610uint32_t
611check_san (SSL *ssl, const char *hostname)
612{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700613 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700614 int extcount, ok = 0;
615 /* What an OpenSSL mess ... */
Will Drewryc45952f2013-09-03 13:51:24 -0500616 if (NULL == (cert = SSL_get_peer_certificate (ssl)))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700617 {
Will Drewryc45952f2013-09-03 13:51:24 -0500618 die ("Getting certificate failed\n");
619 }
620 if ( (extcount = X509_get_ext_count (cert)) > 0)
621 {
622 int i;
623 for (i = 0; i < extcount; ++i)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700624 {
Will Drewryc45952f2013-09-03 13:51:24 -0500625 const char *extstr;
626 X509_EXTENSION *ext;
627 ext = X509_get_ext (cert, i);
628 extstr = OBJ_nid2sn (OBJ_obj2nid (X509_EXTENSION_get_object (ext)));
629 if (!strcmp (extstr, "subjectAltName"))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700630 {
Will Drewryc45952f2013-09-03 13:51:24 -0500631 int j;
632 void *extvalstr;
Will Drewryc45952f2013-09-03 13:51:24 -0500633 STACK_OF (CONF_VALUE) *val;
634 CONF_VALUE *nval;
635#if OPENSSL_VERSION_NUMBER >= 0x10000000L
636 const
637#endif
638 X509V3_EXT_METHOD *method;
639 if (! (method = X509V3_EXT_get (ext)))
640 {
641 break;
642 }
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600643 extvalstr = X509V3_EXT_d2i(ext);
Will Drewryc45952f2013-09-03 13:51:24 -0500644 if (!extvalstr)
645 {
646 break;
647 }
648 if (method->i2v)
649 {
650 val = method->i2v (method, extvalstr, NULL);
651 for (j = 0; j < sk_CONF_VALUE_num (val); ++j)
652 {
653 nval = sk_CONF_VALUE_value (val, j);
654 if ( (!strcasecmp (nval->name, "DNS") &&
655 !strcasecmp (nval->value, hostname)) ||
656 (!strcasecmp (nval->name, "iPAddress") &&
657 !strcasecmp (nval->value, hostname)))
658 {
659 verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
660 ok = 1;
661 break;
662 }
663 // Attempt to match subjectAltName DNS names
664 if (!strcasecmp (nval->name, "DNS"))
665 {
666 ok = check_wildcard_match_rfc2595 (hostname, nval->value);
667 if (ok)
668 {
669 break;
670 }
671 }
672 verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
673 }
674 }
675 }
676 else
677 {
678 verb ("V: found non subjectAltName extension\n");
679 }
680 if (ok)
681 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700682 break;
683 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700684 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700685 }
Will Drewryc45952f2013-09-03 13:51:24 -0500686 else
687 {
688 verb ("V: no X509_EXTENSION field(s) found\n");
689 }
690 X509_free (cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700691 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700692}
693
694uint32_t
695check_name (SSL *ssl, const char *hostname)
696{
697 uint32_t ret;
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700698 ret = 0;
Will Drewryc45952f2013-09-03 13:51:24 -0500699 ret = check_cn (ssl, hostname);
700 ret += check_san (ssl, hostname);
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700701 if (0 != ret && 0 < ret)
Will Drewryc45952f2013-09-03 13:51:24 -0500702 {
703 verb ("V: hostname verification passed\n");
704 }
705 else
706 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100707 die ("hostname verification failed for host %s!\n", g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500708 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700709 return ret;
710}
711
712uint32_t
713verify_signature (SSL *ssl, const char *hostname)
714{
715 long ssl_verify_result;
716 X509 *certificate;
Will Drewryc45952f2013-09-03 13:51:24 -0500717 certificate = SSL_get_peer_certificate (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700718 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500719 {
720 die ("Getting certificate failed\n");
721 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700722 // In theory, we verify that the cert is valid
Will Drewryc45952f2013-09-03 13:51:24 -0500723 ssl_verify_result = SSL_get_verify_result (ssl);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700724 switch (ssl_verify_result)
Will Drewryc45952f2013-09-03 13:51:24 -0500725 {
726 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
727 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
728 die ("certificate is self signed\n");
729 case X509_V_OK:
730 verb ("V: certificate verification passed\n");
731 break;
732 default:
733 die ("certification verification error: %ld\n",
734 ssl_verify_result);
735 }
736 return 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700737}
738
739void
740check_key_length (SSL *ssl)
741{
742 uint32_t key_bits;
743 X509 *certificate;
744 EVP_PKEY *public_key;
745 certificate = SSL_get_peer_certificate (ssl);
A soldier31056a62012-08-16 01:10:57 -0700746 if (NULL == certificate)
Will Drewryc45952f2013-09-03 13:51:24 -0500747 {
748 die ("Getting certificate failed\n");
749 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700750 public_key = X509_get_pubkey (certificate);
751 if (NULL == public_key)
Will Drewryc45952f2013-09-03 13:51:24 -0500752 {
753 die ("public key extraction failure\n");
754 }
755 else
756 {
757 verb ("V: public key is ready for inspection\n");
758 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700759 key_bits = get_certificate_keybits (public_key);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600760 if (MIN_PUB_KEY_LEN >= key_bits && EVP_PKEY_id(public_key) != EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500761 {
762 die ("Unsafe public key size: %d bits\n", key_bits);
763 }
764 else
765 {
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600766 if (EVP_PKEY_id(public_key) == EVP_PKEY_EC)
Will Drewryc45952f2013-09-03 13:51:24 -0500767 if (key_bits >= MIN_ECC_PUB_KEY_LEN
768 && key_bits <= MAX_ECC_PUB_KEY_LEN)
769 {
770 verb ("V: ECC key length appears safe\n");
771 }
772 else
773 {
774 die ("Unsafe ECC key size: %d bits\n", key_bits);
775 }
776 else
777 {
778 verb ("V: key length appears safe\n");
779 }
780 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700781 EVP_PKEY_free (public_key);
782}
783
784void
785inspect_key (SSL *ssl, const char *hostname)
786{
Will Drewryc45952f2013-09-03 13:51:24 -0500787 verify_signature (ssl, hostname);
788 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700789}
790
Christian Grothoff88b422b2012-02-14 00:35:09 +0100791/**
792 * Run SSL handshake and store the resulting time value in the
793 * 'time_map'.
794 *
795 * @param time_map where to store the current time
796 */
797static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400798run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100799{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100800 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100801 SSL_CTX *ctx;
802 SSL *ssl;
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800803 struct stat statbuf;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100804 SSL_load_error_strings();
805 SSL_library_init();
Christian Grothoff90e9f832012-02-07 11:16:47 +0100806 ctx = NULL;
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600807
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100808 if (0 == strcmp ("sslv23", g_protocol))
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800809 {
Will Drewryc45952f2013-09-03 13:51:24 -0500810 verb ("V: using SSLv23_client_method()\n");
811 ctx = SSL_CTX_new (SSLv23_client_method());
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800812 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100813#ifndef OPENSSL_NO_SSL3_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100814 else if (0 == strcmp ("sslv3", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500815 {
816 verb ("V: using SSLv3_client_method()\n");
817 ctx = SSL_CTX_new (SSLv3_client_method());
818 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100819#endif
820#ifndef OPENSSL_NO_TLS1_METHOD
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100821 else if (0 == strcmp ("tlsv1", g_protocol))
Will Drewryc45952f2013-09-03 13:51:24 -0500822 {
823 verb ("V: using TLSv1_client_method()\n");
824 ctx = SSL_CTX_new (TLSv1_client_method());
825 }
Mattias Nissler2ca14572020-01-13 15:01:43 +0100826#endif
827#ifndef OPENSSL_NO_TLS1_1_METHOD
828 else if (0 == strcmp ("tlsv11", g_protocol))
829 {
830 verb ("V: using TLSv1_1_client_method()\n");
831 ctx = SSL_CTX_new (TLSv1_1_client_method());
832 }
833#endif
834#ifndef OPENSSL_NO_TLS1_2_METHOD
835 else if (0 == strcmp ("tlsv12", g_protocol))
836 {
837 verb ("V: using TLSv1_2_client_method()\n");
838 ctx = SSL_CTX_new (TLSv1_2_client_method());
839 }
840#endif
Will Drewryc45952f2013-09-03 13:51:24 -0500841 else
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100842 die ("Unsupported protocol `%s'\n", g_protocol);
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600843
Will Drewryc45952f2013-09-03 13:51:24 -0500844 if (ctx == NULL)
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100845 die ("OpenSSL failed to support protocol `%s'\n", g_protocol);
846 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500847 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100848 if (-1 == stat (g_ca_cert_container, &statbuf))
Will Drewryc45952f2013-09-03 13:51:24 -0500849 {
850 die ("Unable to stat CA certficate container\n");
851 }
852 else
853 {
854 switch (statbuf.st_mode & S_IFMT)
855 {
856 case S_IFREG:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100857 if (1 != SSL_CTX_load_verify_locations(
858 ctx, g_ca_cert_container, NULL))
859 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500860 break;
861 case S_IFDIR:
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100862 if (1 != SSL_CTX_load_verify_locations(
863 ctx, NULL, g_ca_cert_container))
864 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500865 break;
866 default:
867 die ("Unable to load CA certficate container\n");
868 }
869 }
870 }
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100871 verb ("V: setting up connection to %s:%s\n", g_host, g_port);
872 if (NULL == (s_bio = make_ssl_bio(ctx, g_host, g_port, g_proxy)))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100873 die ("SSL BIO setup failed\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500874 BIO_get_ssl (s_bio, &ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100875 if (NULL == ssl)
876 die ("SSL setup failed\n");
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700877 if (time_is_an_illusion)
Will Drewryc45952f2013-09-03 13:51:24 -0500878 {
879 SSL_set_info_callback (ssl, openssl_time_callback);
880 }
881 SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100882 SSL_set_tlsext_host_name (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500883 if (NULL == BIO_new_fp (stdout, BIO_NOCLOSE))
884 die ("BIO_new_fp returned error, possibly: %s", strerror (errno));
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800885 // This should run in seccomp
886 // eg: prctl(PR_SET_SECCOMP, 1);
Pavol Markod9dd19d2020-01-17 23:32:57 +0100887 verb ("V: BIO_do_connect\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500888 if (1 != BIO_do_connect (s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800889 die ("SSL connection failed\n");
Pavol Markod9dd19d2020-01-17 23:32:57 +0100890 verb ("V: BIO_do_handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -0500891 if (1 != BIO_do_handshake (s_bio))
Philipp Winterd96af622012-02-15 22:15:50 +0100892 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100893 // Verify the peer certificate against the CA certs on the local system
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100894 if (g_ca_racket)
Will Drewryc45952f2013-09-03 13:51:24 -0500895 {
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100896 inspect_key (ssl, g_host);
Will Drewryc45952f2013-09-03 13:51:24 -0500897 }
898 else
899 {
900 verb ("V: Certificate verification skipped!\n");
901 }
902 check_key_length (ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100903 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700904 // ssl->s3->server_random is an unsigned char of 32 bits
Daniel Kurtza2d82d52019-06-07 15:26:54 -0600905 SSL_get_server_random(ssl, (unsigned char *)time_map, sizeof(uint32_t));
Will Drewryc45952f2013-09-03 13:51:24 -0500906 SSL_free (ssl);
907 SSL_CTX_free (ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100908}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100909
Christian Grothoff191cd982012-02-14 00:48:45 +0100910/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100911
Christian Grothoff88b422b2012-02-14 00:35:09 +0100912int
Will Drewryc45952f2013-09-03 13:51:24 -0500913main (int argc, char **argv)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100914{
915 uint32_t *time_map;
David Goulet0809df12012-07-31 23:27:34 -0400916 struct tlsdate_time start_time, end_time, warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100917 int status;
918 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100919 long long rt_time_ms;
920 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200921 int setclock;
922 int showtime;
Will Drewry72706752013-09-13 15:57:10 -0500923 int showtime_raw;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400924 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400925 int leap;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400926 if (argc != 12)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100927 return 1;
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100928 g_host = argv[1];
929 g_port = argv[2];
930 validate_port(g_port);
931 g_protocol = argv[3];
932 g_ca_cert_container = argv[6];
933 g_ca_racket = (0 != strcmp ("unchecked", argv[4]));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100934 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200935 setclock = (0 == strcmp ("setclock", argv[7]));
936 showtime = (0 == strcmp ("showtime", argv[8]));
Will Drewry72706752013-09-13 15:57:10 -0500937 showtime_raw = (0 == strcmp ("showtime=raw", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400938 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400939 leap = (0 == strcmp ("leapaway", argv[10]));
Andreea Costinas6d6944a2019-03-27 15:29:09 +0100940 g_proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
Will Drewryc45952f2013-09-03 13:51:24 -0500941 clock_init_time (&warp_time, RECENT_COMPILE_DATE, 0);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400942 if (timewarp)
Will Drewryc45952f2013-09-03 13:51:24 -0500943 {
944 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
945 (unsigned long) CLOCK_SEC (&warp_time),
946 (unsigned long) CLOCK_USEC (&warp_time));
947 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200948 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400949 if (0 == setclock && 0 == timewarp)
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400950 {
Will Drewryc45952f2013-09-03 13:51:24 -0500951 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400952 }
Will Drewryc45952f2013-09-03 13:51:24 -0500953 time_map = mmap (NULL, sizeof (uint32_t),
954 PROT_READ | PROT_WRITE,
955 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
956 if (MAP_FAILED == time_map)
957 {
958 fprintf (stderr, "mmap failed: %s\n",
959 strerror (errno));
960 return 1;
961 }
962 /* Get the current time from the system clock. */
963 if (0 != clock_get_real_time (&start_time))
964 {
965 die ("Failed to read current time of day: %s\n", strerror (errno));
966 }
967 verb ("V: time is currently %lu.%06lu\n",
968 (unsigned long) CLOCK_SEC (&start_time),
969 (unsigned long) CLOCK_NSEC (&start_time));
970 if ( ( (unsigned long) CLOCK_SEC (&start_time)) < ( (unsigned long) CLOCK_SEC (&warp_time)))
971 {
972 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
973 if (timewarp)
974 {
975 verb ("V: Attempting to warp local clock into the future\n");
976 if (0 != clock_set_real_time (&warp_time))
977 {
978 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
979 strerror (errno),
980 (unsigned long) CLOCK_SEC (&warp_time),
981 (unsigned long) CLOCK_SEC (&warp_time));
982 }
983 if (0 != clock_get_real_time (&start_time))
984 {
985 die ("Failed to read current time of day: %s\n", strerror (errno));
986 }
987 verb ("V: time is currently %lu.%06lu\n",
988 (unsigned long) CLOCK_SEC (&start_time),
989 (unsigned long) CLOCK_NSEC (&start_time));
990 verb ("V: It's just a step to the left...\n");
991 }
992 }
993 else
994 {
995 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
996 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100997 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100998 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +0100999 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001000 ssl_child = fork ();
1001 if (-1 == ssl_child)
1002 die ("fork failed: %s\n", strerror (errno));
1003 if (0 == ssl_child)
Will Drewryc45952f2013-09-03 13:51:24 -05001004 {
1005 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
1006 run_ssl (time_map, leap);
1007 (void) munmap (time_map, sizeof (uint32_t));
1008 _exit (0);
1009 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001010 if (ssl_child != waitpid (ssl_child, &status, 0))
1011 die ("waitpid failed: %s\n", strerror (errno));
Will Drewryc45952f2013-09-03 13:51:24 -05001012 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
Christian Grothoff191cd982012-02-14 00:48:45 +01001013 die ("child process failed in SSL handshake\n");
Will Drewryc45952f2013-09-03 13:51:24 -05001014 if (0 != clock_get_real_time (&end_time))
Christian Grothoff88b422b2012-02-14 00:35:09 +01001015 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +01001016 /* calculate RTT */
Will Drewryc45952f2013-09-03 13:51:24 -05001017 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 +01001018 if (rt_time_ms < 0)
1019 rt_time_ms = 0; /* non-linear time... */
1020 server_time_s = ntohl (*time_map);
1021 munmap (time_map, sizeof (uint32_t));
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001022 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Will Drewryc45952f2013-09-03 13:51:24 -05001023 (unsigned int) server_time_s,
1024 CLOCK_SEC (&start_time) - server_time_s,
1025 rt_time_ms);
Philipp Winterb3ca5772012-02-16 11:56:11 +01001026 /* warning if the handshake took too long */
Will Drewryc45952f2013-09-03 13:51:24 -05001027 if (rt_time_ms > TLS_RTT_THRESHOLD)
1028 {
1029 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
1030 "server or run it again\n", TLS_RTT_THRESHOLD);
1031 }
Will Drewry72706752013-09-13 15:57:10 -05001032 if (showtime_raw)
Will Drewryc45952f2013-09-03 13:51:24 -05001033 {
1034 fwrite (&server_time_s, sizeof (server_time_s), 1, stdout);
1035 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001036 if (showtime)
Will Drewryc45952f2013-09-03 13:51:24 -05001037 {
1038 struct tm ltm;
1039 time_t tim = server_time_s;
1040 char buf[256];
1041 localtime_r (&tim, &ltm);
1042 if (0 == strftime (buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
1043 {
1044 die ("strftime returned 0\n");
1045 }
1046 fprintf (stdout, "%s\n", buf);
1047 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001048 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001049 if (setclock)
Will Drewryc45952f2013-09-03 13:51:24 -05001050 {
1051 struct tlsdate_time server_time;
1052 clock_init_time (&server_time, server_time_s + (rt_time_ms / 2 / 1000),
1053 (rt_time_ms / 2) % 1000);
1054 // We should never receive a time that is before the time we were last
1055 // compiled; we subscribe to the linear theory of time for this program
1056 // and this program alone!
1057 if (CLOCK_SEC (&server_time) >= MAX_REASONABLE_TIME)
1058 die ("remote server is a false ticker from the future!\n");
1059 if (CLOCK_SEC (&server_time) <= RECENT_COMPILE_DATE)
1060 die ("remote server is a false ticker!\n");
1061 if (0 != clock_set_real_time (&server_time))
1062 die ("setting time failed: %s (Difference from server is about %d)\n",
1063 strerror (errno),
1064 CLOCK_SEC (&start_time) - server_time_s);
1065 verb ("V: setting time succeeded\n");
1066 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001067 return 0;
1068}