blob: 35d677941a0b5c1e9ef6650f27b9dfbd70d1554a [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"
78#include "src/tlsdate-helper.h"
Christian Grothoff90e9f832012-02-07 11:16:47 +010079
Paul Bakker385386d2013-01-25 14:11:14 +010080#ifndef USE_POLARSSL
Jacob Appelbaumfa765302013-01-18 15:47:47 +010081#include "src/proxy-bio.h"
Paul Bakker010ef452013-02-01 15:13:24 +010082#else
83#include "src/proxy-polarssl.h"
Paul Bakker385386d2013-01-25 14:11:14 +010084#endif
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -040085
Brian Akerb12abad2012-10-16 01:25:00 -040086#include "src/compat/clock.h"
Elly Jones9ae3aa62012-06-20 15:32:46 -040087
Jacob Appelbaum8f5dbfd2013-02-13 23:13:44 -080088#ifndef MAP_ANONYMOUS
89#define MAP_ANONYMOUS MAP_ANON
90#endif
91
Paul Bakker385386d2013-01-25 14:11:14 +010092#ifdef USE_POLARSSL
93#include "polarssl/entropy.h"
94#include "polarssl/ctr_drbg.h"
95#include "polarssl/ssl.h"
96#endif
97
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -040098static void
99validate_proxy_scheme(const char *scheme)
100{
101 if (!strcmp(scheme, "http"))
102 return;
103 if (!strcmp(scheme, "socks4"))
104 return;
105 if (!strcmp(scheme, "socks5"))
106 return;
107 die("invalid proxy scheme\n");
108}
109
110static void
111validate_proxy_host(const char *host)
112{
113 const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
114 "abcdefghijklmnopqrstuvwxyz"
115 "0123456789"
116 ".-";
117 if (strspn(host, kValid) != strlen(host))
118 die("invalid char in host\n");
119}
120
121static void
122validate_proxy_port(const char *port)
123{
124 while (*port)
Taylor R Campbell6b7041d2013-04-17 21:04:33 +0000125 if (!isdigit((int)(unsigned char)*port++))
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400126 die("invalid char in port\n");
127}
128
129static void
130parse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
131{
132 /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
133 *scheme = proxy;
134 proxy = strstr(proxy, "://");
135 if (!proxy)
136 die("malformed proxy URI\n");
137 *proxy = '\0'; /* terminate scheme string */
138 proxy += strlen("://");
139
140 *host = proxy;
141 proxy = strchr(proxy, ':');
142 if (!proxy)
143 die("malformed proxy URI\n");
144 *proxy++ = '\0';
145
146 *port = proxy;
147
148 validate_proxy_scheme(*scheme);
149 validate_proxy_host(*host);
150 validate_proxy_port(*port);
151}
152
Paul Bakker010ef452013-02-01 15:13:24 +0100153#ifndef USE_POLARSSL
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400154static void
155setup_proxy(BIO *ssl)
156{
157 BIO *bio;
158 char *scheme;
159 char *proxy_host;
160 char *proxy_port;
161
162 if (!proxy)
163 return;
164 /*
165 * grab the proxy's host and port out of the URI we have for it. We want the
166 * underlying connect BIO to connect to this, not the target host and port, so
167 * we squirrel away the target host and port in the proxy BIO (as the proxy
168 * target) and swap out the connect BIO's target host and port so it'll
169 * connect to the proxy instead.
170 */
171 parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
172 bio = BIO_new_proxy();
173 BIO_proxy_set_type(bio, scheme);
174 BIO_proxy_set_host(bio, host);
175 BIO_proxy_set_port(bio, atoi(port));
176 host = proxy_host;
177 port = proxy_port;
178 BIO_push(ssl, bio);
179}
180
181static BIO *
182make_ssl_bio(SSL_CTX *ctx)
183{
184 BIO *con = NULL;
185 BIO *ssl = NULL;
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -0400186
187 if (!(con = BIO_new(BIO_s_connect())))
188 die("BIO_s_connect failed\n");
189 if (!(ssl = BIO_new_ssl(ctx, 1)))
190 die("BIO_new_ssl failed\n");
191 setup_proxy(ssl);
192 BIO_push(ssl, con);
193 return ssl;
194}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100195
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200196/** helper function for 'malloc' */
197static void *
198xmalloc (size_t size)
199{
200 void *ptr;
201
202 if (0 == size)
203 die("xmalloc: zero size\n");
204
205 ptr = malloc(size);
206 if (NULL == ptr)
207 die("xmalloc: out of memory (allocating %zu bytes)\n", size);
208
209 return ptr;
210}
211
212
213/** helper function for 'free' */
214static void
215xfree (void *ptr)
216{
Daniel Borkmann592acc52012-07-30 14:08:02 +0200217 if (NULL == ptr)
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200218 die("xfree: NULL pointer given as argument\n");
219
220 free(ptr);
221}
222
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700223void
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700224openssl_time_callback (const SSL* ssl, int where, int ret)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700225{
A soldier31056a62012-08-16 01:10:57 -0700226 if (where == SSL_CB_CONNECT_LOOP &&
Elly Fong-Jones9b811a42012-12-13 16:17:21 -0500227 (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700228 {
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700229 // XXX TODO: If we want to trust the remote system for time,
230 // can we just read that time out of the remote system and if the
231 // cert verifies, decide that the time is reasonable?
232 // Such a process seems to indicate that a once valid cert would be
233 // forever valid - we stopgap that by ensuring it isn't less than
234 // the latest compiled_time and isn't above max_reasonable_time...
235 // XXX TODO: Solve eternal question about the Chicken and the Egg...
236 uint32_t compiled_time = RECENT_COMPILE_DATE;
237 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700238 uint32_t server_time;
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700239 verb("V: freezing time for x509 verification\n");
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700240 memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700241 if (compiled_time < ntohl(server_time)
242 &&
243 ntohl(server_time) < max_reasonable_time)
244 {
Jacob Appelbaumaf1e68c2012-11-08 00:24:02 -0800245 verb("V: remote peer provided: %d, preferred over compile time: %d\n",
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700246 ntohl(server_time), compiled_time);
247 verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
Elly Fong-Jones9b811a42012-12-13 16:17:21 -0500248 X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
249 (time_t) ntohl(server_time) + 86400);
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700250 } else {
251 die("V: the remote server is a false ticker! server: %d compile: %d\n",
252 ntohl(server_time), compiled_time);
253 }
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700254 }
255}
256
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700257uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700258get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700259{
260 /*
261 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
262 */
263 uint32_t key_bits;
264 switch (public_key->type)
265 {
266 case EVP_PKEY_RSA:
267 verb("V: key type: EVP_PKEY_RSA\n");
268 key_bits = BN_num_bits(public_key->pkey.rsa->n);
269 break;
270 case EVP_PKEY_RSA2:
271 verb("V: key type: EVP_PKEY_RSA2\n");
272 key_bits = BN_num_bits(public_key->pkey.rsa->n);
273 break;
274 case EVP_PKEY_DSA:
275 verb("V: key type: EVP_PKEY_DSA\n");
276 key_bits = BN_num_bits(public_key->pkey.dsa->p);
277 break;
278 case EVP_PKEY_DSA1:
279 verb("V: key type: EVP_PKEY_DSA1\n");
280 key_bits = BN_num_bits(public_key->pkey.dsa->p);
281 break;
282 case EVP_PKEY_DSA2:
283 verb("V: key type: EVP_PKEY_DSA2\n");
284 key_bits = BN_num_bits(public_key->pkey.dsa->p);
285 break;
286 case EVP_PKEY_DSA3:
287 verb("V: key type: EVP_PKEY_DSA3\n");
288 key_bits = BN_num_bits(public_key->pkey.dsa->p);
289 break;
290 case EVP_PKEY_DSA4:
291 verb("V: key type: EVP_PKEY_DSA4\n");
292 key_bits = BN_num_bits(public_key->pkey.dsa->p);
293 break;
294 case EVP_PKEY_DH:
295 verb("V: key type: EVP_PKEY_DH\n");
296 key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
297 break;
298 case EVP_PKEY_EC:
299 verb("V: key type: EVP_PKEY_EC\n");
300 key_bits = EVP_PKEY_bits(public_key);
301 break;
302 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
303 default:
304 key_bits = 0;
305 die ("unknown public key type\n");
306 break;
307 }
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700308 verb ("V: keybits: %d\n", key_bits);
309 return key_bits;
310}
311
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700312uint32_t
313dns_label_count(char *label, char *delim)
314{
315 char *label_tmp;
316 char *saveptr;
317 char *saveptr_tmp;
318 uint32_t label_count;
319
320 label_tmp = strdup(label);
321 label_count = 0;
322 saveptr = NULL;
323 saveptr_tmp = NULL;
324 saveptr = strtok_r(label_tmp, delim, &saveptr);
325 if (NULL != saveptr)
326 {
327 // Did we find our first label?
328 if (saveptr[0] != delim[0])
329 {
330 label_count++;
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700331 }
332 do
333 {
334 // Find all subsequent labels
335 label_count++;
336 saveptr_tmp = strtok_r(NULL, delim, &saveptr);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700337 } while (NULL != saveptr_tmp);
338 }
Jacob Appelbaum04ae3c22013-04-26 13:46:22 -0700339 verb ("V: label found; total label count: %d\n", label_count);
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700340 free(label_tmp);
341 return label_count;
342}
343
344// first we split strings on '.'
345// then we call each split string a 'label'
346// Do not allow '*' for the top level domain label; eg never allow *.*.com
347// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
348// Do allow *.example.com
349uint32_t
350check_wildcard_match_rfc2595 (const char *orig_hostname,
351 const char *orig_cert_wild_card)
352{
353 char *hostname;
354 char *hostname_to_free;
355 char *cert_wild_card;
356 char *cert_wild_card_to_free;
357 char *expected_label;
358 char *wildcard_label;
359 char *delim;
360 char *wildchar;
361 uint32_t ok;
362 uint32_t wildcard_encountered;
363 uint32_t label_count;
364
365 // First we copy the original strings
366 hostname = strndup(orig_hostname, strlen(orig_hostname));
367 cert_wild_card = strndup(orig_cert_wild_card, strlen(orig_cert_wild_card));
368 hostname_to_free = hostname;
369 cert_wild_card_to_free = cert_wild_card;
370 delim = strdup(".");
371 wildchar = strdup("*");
372
373 verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
374 hostname, cert_wild_card);
375
376 // By default we have not processed any labels
377 label_count = dns_label_count(cert_wild_card, delim);
378
379 // By default we have no match
380 ok = 0;
381 wildcard_encountered = 0;
382 // First - do we have labels? If not, we refuse to even try to match
383 if ((NULL != strpbrk(cert_wild_card, delim)) &&
384 (NULL != strpbrk(hostname, delim)) &&
385 (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
386 {
387 if (wildchar[0] == cert_wild_card[0])
388 {
389 verb ("V: Found wildcard in at start of provided certificate name\n");
390 do
391 {
392 // Skip over the bytes between the first char and until the next label
393 wildcard_label = strsep(&cert_wild_card, delim);
394 expected_label = strsep(&hostname, delim);
395 if (NULL != wildcard_label &&
396 NULL != expected_label &&
397 NULL != hostname &&
398 NULL != cert_wild_card)
399 {
400 // Now we only consider this wildcard valid if the rest of the
401 // hostnames match verbatim
402 verb ("V: Attempting match of '%s' against '%s'\n",
403 expected_label, wildcard_label);
404 // This is the case where we have a label that begins with wildcard
405 // Furthermore, we only allow this for the first label
406 if (wildcard_label[0] == wildchar[0] &&
407 0 == wildcard_encountered && 0 == ok)
408 {
409 verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
410 wildcard_encountered = 1;
411 } else {
412 verb ("V: Attempting match of '%s' against '%s'\n",
413 hostname, cert_wild_card);
414 if (0 == strcasecmp (expected_label, wildcard_label) &&
415 label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
416 {
417 ok = 1;
418 verb ("V: remaining labels match!\n");
419 break;
420 } else {
421 ok = 0;
422 verb ("V: remaining labels do not match!\n");
423 break;
424 }
425 }
426 } else {
427 // We hit this case when we have a mismatched number of labels
428 verb("V: NULL label; no wildcard here\n");
429 break;
430 }
431 } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
432 } else {
433 verb ("V: Not a RFC 2595 wildcard\n");
434 }
435 } else {
436 verb ("V: Not a valid wildcard certificate\n");
437 ok = 0;
438 }
439 // Free our copies
440 free(wildchar);
441 free(delim);
442 free(hostname_to_free);
443 free(cert_wild_card_to_free);
444 if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
445 {
446 verb ("V: wildcard match of %s against %s\n",
447 orig_hostname, orig_cert_wild_card);
448 return (wildcard_encountered & ok);
449 } else {
450 verb ("V: wildcard match failure of %s against %s\n",
451 orig_hostname, orig_cert_wild_card);
452 return 0;
453 }
454}
Paul Bakker385386d2013-01-25 14:11:14 +0100455#endif
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700456
Paul Bakker385386d2013-01-25 14:11:14 +0100457#ifndef USE_POLARSSL
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700458/**
459 This extracts the first commonName and checks it against hostname.
460*/
461uint32_t
462check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700463{
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200464 int ok = 0;
Jacob Appelbaumdb5f01f2013-02-05 22:27:29 -0500465 int ret;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700466 char *cn_buf;
467 X509 *certificate;
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700468 X509_NAME *xname;
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200469
Jacob Appelbaumdb5f01f2013-02-05 22:27:29 -0500470 // We cast this to cast away g++ complaining about the following:
471 // error: invalid conversion from ‘void*’ to ‘char*’
472 cn_buf = (char *) xmalloc(TLSDATE_HOST_NAME_MAX + 1);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700473
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700474 certificate = SSL_get_peer_certificate(ssl);
475 if (NULL == certificate)
476 {
477 die ("Unable to extract certificate\n");
478 }
479
Brian Aker95d9fd52012-10-15 22:44:03 -0400480 memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700481 xname = X509_get_subject_name(certificate);
482 ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
Brian Aker95d9fd52012-10-15 22:44:03 -0400483 cn_buf, TLSDATE_HOST_NAME_MAX);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700484
Thijs Alkemade41491302013-02-14 10:27:49 +0100485 if (-1 == ret || ret != (int) strlen(cn_buf))
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700486 {
487 die ("Unable to extract commonName\n");
488 }
489 if (strcasecmp(cn_buf, hostname))
490 {
Jacob Appelbaum6bb4b812012-07-30 02:27:37 -0700491 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700492 hostname, cn_buf);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700493 } else {
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700494 verb ("V: commonName matched: %s\n", cn_buf);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200495 ok = 1;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700496 }
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200497
Jacob Appelbaum8f7682d2012-07-31 03:28:26 -0700498 X509_NAME_free(xname);
499 X509_free(certificate);
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200500 xfree(cn_buf);
Daniel Borkmann7066f382012-08-01 12:02:14 +0200501
Daniel Borkmann23c2b802012-07-30 14:06:12 +0200502 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700503}
504
505/**
506 Search for a hostname match in the SubjectAlternativeNames.
507*/
508uint32_t
509check_san (SSL *ssl, const char *hostname)
510{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700511 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700512 int extcount, ok = 0;
513 /* What an OpenSSL mess ... */
514 if (NULL == (cert = SSL_get_peer_certificate(ssl)))
515 {
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700516 die ("Getting certificate failed\n");
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700517 }
518
519 if ((extcount = X509_get_ext_count(cert)) > 0)
520 {
521 int i;
522 for (i = 0; i < extcount; ++i)
523 {
524 const char *extstr;
525 X509_EXTENSION *ext;
526 ext = X509_get_ext(cert, i);
527 extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
528
529 if (!strcmp(extstr, "subjectAltName"))
530 {
531
532 int j;
533 void *extvalstr;
534 const unsigned char *tmp;
535
536 STACK_OF(CONF_VALUE) *val;
537 CONF_VALUE *nval;
Mike Frysinger1b237ae2012-12-18 15:29:29 -0500538#if OPENSSL_VERSION_NUMBER >= 0x10000000L
539 const
540#endif
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700541 X509V3_EXT_METHOD *method;
542
543 if (!(method = X509V3_EXT_get(ext)))
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700544 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700545 break;
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700546 }
547
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700548 tmp = ext->value->data;
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700549 if (method->it)
550 {
551 extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
552 ASN1_ITEM_ptr(method->it));
553 } else {
554 extvalstr = method->d2i(NULL, &tmp, ext->value->length);
555 }
556
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700557 if (!extvalstr)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700558 {
559 break;
560 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700561
562 if (method->i2v)
563 {
564 val = method->i2v(method, extvalstr, NULL);
565 for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
566 {
567 nval = sk_CONF_VALUE_value(val, j);
Jacob Appelbaum9cbf1f42012-07-30 03:21:26 -0700568 if ((!strcasecmp(nval->name, "DNS") &&
ellyceb1fe22013-02-27 10:50:25 -0500569 !strcasecmp(nval->value, hostname) ) ||
Jacob Appelbaum9cbf1f42012-07-30 03:21:26 -0700570 (!strcasecmp(nval->name, "iPAddress") &&
ellyceb1fe22013-02-27 10:50:25 -0500571 !strcasecmp(nval->value, hostname)))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700572 {
Jacob Appelbaum9cbf1f42012-07-30 03:21:26 -0700573 verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); // We matched this; so it's safe to print
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700574 ok = 1;
575 break;
576 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700577 // Attempt to match subjectAltName DNS names
578 if (!strcasecmp(nval->name, "DNS"))
579 {
ellyceb1fe22013-02-27 10:50:25 -0500580 ok = check_wildcard_match_rfc2595(hostname, nval->value);
Thijs Alkemade41491302013-02-14 10:27:49 +0100581 if (ok)
582 {
583 break;
584 }
Jacob Appelbaumad12a3a2012-08-05 17:47:17 -0700585 }
586 verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700587 }
588 }
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700589 } else {
590 verb ("V: found non subjectAltName extension\n");
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700591 }
592 if (ok)
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700593 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700594 break;
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700595 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700596 }
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700597 } else {
598 verb ("V: no X509_EXTENSION field(s) found\n");
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700599 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700600 X509_free(cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700601 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700602}
603
604uint32_t
605check_name (SSL *ssl, const char *hostname)
606{
607 uint32_t ret;
608 ret = check_cn(ssl, hostname);
609 ret += check_san(ssl, hostname);
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700610 if (0 != ret && 0 < ret)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700611 {
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700612 verb ("V: hostname verification passed\n");
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700613 } else {
Jacob Appelbaum193e5612012-07-30 03:01:35 -0700614 die ("hostname verification failed for host %s!\n", host);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700615 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700616 return ret;
617}
Paul Bakker385386d2013-01-25 14:11:14 +0100618#endif
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700619
Paul Bakker385386d2013-01-25 14:11:14 +0100620#ifdef USE_POLARSSL
621uint32_t
622verify_signature (ssl_context *ssl, const char *hostname)
623{
624 int ssl_verify_result;
625
626 ssl_verify_result = ssl_get_verify_result (ssl);
627 if (ssl_verify_result & BADCERT_EXPIRED)
628 {
629 die ("certificate has expired\n");
630 }
631 if (ssl_verify_result & BADCERT_REVOKED)
632 {
633 die ("certificate has been revoked\n");
634 }
635 if (ssl_verify_result & BADCERT_CN_MISMATCH)
636 {
637 die ("CN and subject AltName mismatch for certificate\n");
638 }
639 if (ssl_verify_result & BADCERT_NOT_TRUSTED)
640 {
641 die ("certificate is self-signed or not signed by a trusted CA\n");
642 }
643
644 if (0 == ssl_verify_result)
645 {
646 verb ("V: verify success\n");
647 }
648 else
649 {
650 die ("certificate verification error: -0x%04x\n", -ssl_verify_result);
651 }
652 return 0;
653}
654#else
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700655uint32_t
656verify_signature (SSL *ssl, const char *hostname)
657{
658 long ssl_verify_result;
659 X509 *certificate;
660
661 certificate = SSL_get_peer_certificate(ssl);
662 if (NULL == certificate)
663 {
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700664 die ("Getting certificate failed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700665 }
666 // In theory, we verify that the cert is valid
667 ssl_verify_result = SSL_get_verify_result(ssl);
668 switch (ssl_verify_result)
669 {
670 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
671 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700672 die ("certificate is self signed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700673 case X509_V_OK:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700674 verb ("V: certificate verification passed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700675 break;
676 default:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700677 die ("certification verification error: %ld\n",
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700678 ssl_verify_result);
679 }
680 return 0;
681}
Paul Bakker385386d2013-01-25 14:11:14 +0100682#endif
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700683
Paul Bakker385386d2013-01-25 14:11:14 +0100684#ifdef USE_POLARSSL
685void
686check_key_length (ssl_context *ssl)
687{
688 uint32_t key_bits;
689 const x509_cert *certificate;
690 const rsa_context *public_key;
Paul Bakker010ef452013-02-01 15:13:24 +0100691 char buf[1024];
692
Paul Bakker385386d2013-01-25 14:11:14 +0100693 certificate = ssl_get_peer_cert (ssl);
694 if (NULL == certificate)
695 {
696 die ("Getting certificate failed\n");
697 }
Paul Bakker010ef452013-02-01 15:13:24 +0100698
699 x509parse_dn_gets(buf, 1024, &certificate->subject);
700 verb ("V: Certificate for subject '%s'\n", buf);
701
Paul Bakker385386d2013-01-25 14:11:14 +0100702 public_key = &certificate->rsa;
703 if (NULL == public_key)
704 {
705 die ("public key extraction failure\n");
706 } else {
707 verb ("V: public key is ready for inspection\n");
708 }
709 key_bits = mpi_msb (&public_key->N);
710 if (MIN_PUB_KEY_LEN >= key_bits)
711 {
712 die ("Unsafe public key size: %d bits\n", key_bits);
713 } else {
714 verb ("V: key length appears safe\n");
715 }
716}
717#else
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700718void
719check_key_length (SSL *ssl)
720{
721 uint32_t key_bits;
722 X509 *certificate;
723 EVP_PKEY *public_key;
724 certificate = SSL_get_peer_certificate (ssl);
A soldier31056a62012-08-16 01:10:57 -0700725 if (NULL == certificate)
726 {
727 die ("Getting certificate failed\n");
728 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700729 public_key = X509_get_pubkey (certificate);
730 if (NULL == public_key)
731 {
732 die ("public key extraction failure\n");
733 } else {
734 verb ("V: public key is ready for inspection\n");
735 }
736
737 key_bits = get_certificate_keybits (public_key);
738 if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
739 {
740 die ("Unsafe public key size: %d bits\n", key_bits);
741 } else {
742 if (public_key->type == EVP_PKEY_EC)
743 if(key_bits >= MIN_ECC_PUB_KEY_LEN
744 && key_bits <= MAX_ECC_PUB_KEY_LEN)
745 {
746 verb ("V: ECC key length appears safe\n");
747 } else {
748 die ("Unsafe ECC key size: %d bits\n", key_bits);
749 } else {
750 verb ("V: key length appears safe\n");
751 }
752 }
753 EVP_PKEY_free (public_key);
754}
Paul Bakker385386d2013-01-25 14:11:14 +0100755#endif
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700756
Paul Bakker385386d2013-01-25 14:11:14 +0100757#ifdef USE_POLARSSL
758void
759inspect_key (ssl_context *ssl, const char *hostname)
760{
761 verify_signature (ssl, hostname);
762
763 // ssl_get_verify_result() already checks for CN / subjectAltName match
764 // and reports the mismatch as error. So check_name() is not called
765}
766#else
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700767void
768inspect_key (SSL *ssl, const char *hostname)
769{
770
771 verify_signature (ssl, hostname);
772 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700773}
Paul Bakker385386d2013-01-25 14:11:14 +0100774#endif
775
776#ifdef USE_POLARSSL
777void
778check_timestamp (uint32_t server_time)
779{
780 uint32_t compiled_time = RECENT_COMPILE_DATE;
781 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
Paul Bakker385386d2013-01-25 14:11:14 +0100782 if (compiled_time < server_time
783 &&
784 server_time < max_reasonable_time)
785 {
786 verb("V: remote peer provided: %d, preferred over compile time: %d\n",
787 server_time, compiled_time);
788 } else {
789 die("V: the remote server is a false ticker! server: %d compile: %d\n",
790 server_time, compiled_time);
791 }
792}
793
794static int ssl_do_handshake_part(ssl_context *ssl)
795{
796 int ret = 0;
797
798 /* Only do steps till ServerHello is received */
799 while (ssl->state != SSL_SERVER_HELLO)
800 {
801 ret = ssl_handshake_step (ssl);
802 if (0 != ret)
803 {
804 die("SSL handshake failed\n");
805 }
806 }
807 /* Do ServerHello so we can skim the timestamp */
808 ret = ssl_handshake_step (ssl);
809 if (0 != ret)
810 {
811 die("SSL handshake failed\n");
812 }
813
814 return 0;
815}
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700816
Christian Grothoff88b422b2012-02-14 00:35:09 +0100817/**
818 * Run SSL handshake and store the resulting time value in the
819 * 'time_map'.
820 *
821 * @param time_map where to store the current time
822 */
823static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400824run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100825{
Paul Bakker385386d2013-01-25 14:11:14 +0100826 entropy_context entropy;
827 ctr_drbg_context ctr_drbg;
828 ssl_context ssl;
Paul Bakker010ef452013-02-01 15:13:24 +0100829 proxy_polarssl_ctx proxy_ctx;
Paul Bakker385386d2013-01-25 14:11:14 +0100830 x509_cert cacert;
831 struct stat statbuf;
832 int ret = 0, server_fd = 0;
833 char *pers = "tlsdate-helper";
834
835 memset (&ssl, 0, sizeof(ssl_context));
836 memset (&cacert, 0, sizeof(x509_cert));
837
Paul Bakker010ef452013-02-01 15:13:24 +0100838 verb("V: Using PolarSSL for SSL\n");
Paul Bakker385386d2013-01-25 14:11:14 +0100839 if (ca_racket)
840 {
841 if (-1 == stat (ca_cert_container, &statbuf))
842 {
Fabian Keilbb638b82013-03-15 15:50:43 +0100843 die("Unable to stat CA certficate container %s\n", ca_cert_container);
Paul Bakker385386d2013-01-25 14:11:14 +0100844 }
845 else
846 {
847 switch (statbuf.st_mode & S_IFMT)
848 {
849 case S_IFREG:
850 if (0 > x509parse_crtfile(&cacert, ca_cert_container))
851 fprintf(stderr, "x509parse_crtfile failed\n");
852 break;
853 case S_IFDIR:
854 if (0 > x509parse_crtpath(&cacert, ca_cert_container))
855 fprintf(stderr, "x509parse_crtpath failed\n");
856 break;
857 default:
Fabian Keilbb638b82013-03-15 15:50:43 +0100858 die("Unable to load CA certficate container %s\n", ca_cert_container);
Paul Bakker385386d2013-01-25 14:11:14 +0100859 }
860 }
861 }
862
863 entropy_init (&entropy);
864 if (0 != ctr_drbg_init (&ctr_drbg, entropy_func, &entropy,
865 (unsigned char *) pers, strlen(pers)))
866 {
867 die("Failed to initialize CTR_DRBG\n");
868 }
869
Paul Bakker385386d2013-01-25 14:11:14 +0100870 if (0 != ssl_init (&ssl))
871 {
872 die("SSL initialization failed\n");
873 }
874 ssl_set_endpoint (&ssl, SSL_IS_CLIENT);
875 ssl_set_rng (&ssl, ctr_drbg_random, &ctr_drbg);
Paul Bakker385386d2013-01-25 14:11:14 +0100876 ssl_set_ca_chain (&ssl, &cacert, NULL, hostname_to_verify);
877 if (ca_racket)
878 {
879 // You can do SSL_VERIFY_REQUIRED here, but then the check in
880 // inspect_key() never happens as the ssl_handshake() will fail.
881 ssl_set_authmode (&ssl, SSL_VERIFY_OPTIONAL);
882 }
883
Paul Bakker010ef452013-02-01 15:13:24 +0100884 if (proxy)
885 {
886 char *scheme;
887 char *proxy_host;
888 char *proxy_port;
889
890 parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
891
892 verb("V: opening socket to proxy %s:%s\n", proxy_host, proxy_port);
893 if (0 != net_connect (&server_fd, proxy_host, atoi(proxy_port)))
894 {
895 die ("SSL connection failed\n");
896 }
897
898 proxy_polarssl_init (&proxy_ctx);
899 proxy_polarssl_set_bio (&proxy_ctx, net_recv, &server_fd, net_send, &server_fd);
900 proxy_polarssl_set_host (&proxy_ctx, host);
901 proxy_polarssl_set_port (&proxy_ctx, atoi(port));
902 proxy_polarssl_set_scheme (&proxy_ctx, scheme);
903
904 ssl_set_bio (&ssl, proxy_polarssl_recv, &proxy_ctx, proxy_polarssl_send, &proxy_ctx);
905
906 verb("V: Handle proxy connection\n");
907 if (0 == proxy_ctx.f_connect (&proxy_ctx))
908 die("Proxy connection failed\n");
909 }
910 else
911 {
912 verb("V: opening socket to %s:%s\n", host, port);
913 if (0 != net_connect (&server_fd, host, atoi(port)))
914 {
915 die ("SSL connection failed\n");
916 }
917
918 ssl_set_bio (&ssl, net_recv, &server_fd, net_send, &server_fd);
919 }
920
Paul Bakker385386d2013-01-25 14:11:14 +0100921 verb("V: starting handshake\n");
922 if (0 != ssl_do_handshake_part (&ssl))
923 die("SSL handshake first part failed\n");
924
925 uint32_t timestamp = ( (uint32_t) ssl.in_msg[6] << 24 )
926 | ( (uint32_t) ssl.in_msg[7] << 16 )
927 | ( (uint32_t) ssl.in_msg[8] << 8 )
928 | ( (uint32_t) ssl.in_msg[9] );
929 check_timestamp (timestamp);
930
931 verb("V: continuing handshake\n");
932 /* Continue with handshake */
933 while (0 != (ret = ssl_handshake (&ssl)))
934 {
935 if (POLARSSL_ERR_NET_WANT_READ != ret &&
936 POLARSSL_ERR_NET_WANT_WRITE != ret)
937 {
938 die("SSL handshake failed\n");
939 }
940 }
941
942 // Verify the peer certificate against the CA certs on the local system
943 if (ca_racket) {
944 inspect_key (&ssl, hostname_to_verify);
945 } else {
946 verb ("V: Certificate verification skipped!\n");
947 }
948 check_key_length (&ssl);
949
950 memcpy (time_map, &timestamp, sizeof(uint32_t));
Paul Bakker010ef452013-02-01 15:13:24 +0100951 proxy_polarssl_free (&proxy_ctx);
Paul Bakker385386d2013-01-25 14:11:14 +0100952 ssl_free (&ssl);
953 x509_free (&cacert);
954}
955#else /* USE_POLARSSL */
956/**
957 * Run SSL handshake and store the resulting time value in the
958 * 'time_map'.
959 *
960 * @param time_map where to store the current time
961 */
962static void
Linus Nordberg8e68c4e2013-02-12 17:14:45 +0100963run_ssl (uint32_t *time_map, int time_is_an_illusion)
Paul Bakker385386d2013-01-25 14:11:14 +0100964{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100965 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100966 SSL_CTX *ctx;
967 SSL *ssl;
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800968 struct stat statbuf;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100969
Christian Grothoff90e9f832012-02-07 11:16:47 +0100970 SSL_load_error_strings();
971 SSL_library_init();
972
973 ctx = NULL;
974 if (0 == strcmp("sslv23", protocol))
975 {
976 verb ("V: using SSLv23_client_method()\n");
977 ctx = SSL_CTX_new(SSLv23_client_method());
978 } else if (0 == strcmp("sslv3", protocol))
979 {
980 verb ("V: using SSLv3_client_method()\n");
981 ctx = SSL_CTX_new(SSLv3_client_method());
982 } else if (0 == strcmp("tlsv1", protocol))
983 {
984 verb ("V: using TLSv1_client_method()\n");
985 ctx = SSL_CTX_new(TLSv1_client_method());
986 } else
987 die("Unsupported protocol `%s'\n", protocol);
988
989 if (ctx == NULL)
990 die("OpenSSL failed to support protocol `%s'\n", protocol);
991
Paul Bakker010ef452013-02-01 15:13:24 +0100992 verb("V: Using OpenSSL for SSL\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100993 if (ca_racket)
994 {
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800995 if (-1 == stat(ca_cert_container, &statbuf))
996 {
Fabian Keilbb638b82013-03-15 15:50:43 +0100997 die("Unable to stat CA certficate container %s\n", ca_cert_container);
Jacob Appelbaum12e15c92013-01-07 11:17:32 -0800998 } else
999 {
1000 switch (statbuf.st_mode & S_IFMT)
1001 {
1002 case S_IFREG:
1003 if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
1004 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
1005 break;
1006 case S_IFDIR:
1007 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
1008 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
1009 break;
1010 default:
Jacob Appelbaum8f5dbfd2013-02-13 23:13:44 -08001011 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
1012 {
1013 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
Fabian Keilbb638b82013-03-15 15:50:43 +01001014 die("Unable to load CA certficate container %s\n", ca_cert_container);
Jacob Appelbaum8f5dbfd2013-02-13 23:13:44 -08001015 }
Jacob Appelbaum12e15c92013-01-07 11:17:32 -08001016 }
1017 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001018 }
1019
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -04001020 if (NULL == (s_bio = make_ssl_bio(ctx)))
Christian Grothoff90e9f832012-02-07 11:16:47 +01001021 die ("SSL BIO setup failed\n");
1022 BIO_get_ssl(s_bio, &ssl);
1023 if (NULL == ssl)
1024 die ("SSL setup failed\n");
Jacob Appelbaum9f807292012-07-16 18:24:37 -07001025
1026 if (time_is_an_illusion)
1027 {
1028 SSL_set_info_callback(ssl, openssl_time_callback);
1029 }
1030
Christian Grothoff90e9f832012-02-07 11:16:47 +01001031 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
Jacob Appelbaum587e2472012-11-02 00:15:31 +00001032 verb("V: opening socket to %s:%s\n", host, port);
Christian Grothoff90e9f832012-02-07 11:16:47 +01001033 if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
1034 (1 != BIO_set_conn_port(s_bio, port)) )
1035 die ("Failed to initialize connection to `%s:%s'\n", host, port);
1036
Stewart Smith3aa3f382012-06-29 14:36:34 +10001037 if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
1038 die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
Christian Grothoff90e9f832012-02-07 11:16:47 +01001039
Jacob Appelbaum405a7932012-02-15 15:22:02 -08001040 // This should run in seccomp
1041 // eg: prctl(PR_SET_SECCOMP, 1);
1042 if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001043 die ("SSL connection failed\n");
Philipp Winterd96af622012-02-15 22:15:50 +01001044 if (1 != BIO_do_handshake(s_bio))
1045 die ("SSL handshake failed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -07001046
Christian Grothoff90e9f832012-02-07 11:16:47 +01001047 // Verify the peer certificate against the CA certs on the local system
1048 if (ca_racket) {
Jacob Appelbaum5cc5ede2012-11-02 00:10:18 +00001049 inspect_key (ssl, hostname_to_verify);
Christian Grothoff90e9f832012-02-07 11:16:47 +01001050 } else {
1051 verb ("V: Certificate verification skipped!\n");
1052 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -07001053 check_key_length(ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +01001054 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -07001055 // ssl->s3->server_random is an unsigned char of 32 bits
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001056 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
Jacob Appelbaum8355d732012-07-30 01:29:05 -07001057 SSL_free(ssl);
Jacob Appelbaumb79b0eb2012-07-29 23:00:21 -07001058 SSL_CTX_free(ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +01001059}
Paul Bakker385386d2013-01-25 14:11:14 +01001060#endif /* USE_POLARSSL */
Christian Grothoff191cd982012-02-14 00:48:45 +01001061/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +01001062
Christian Grothoff88b422b2012-02-14 00:35:09 +01001063int
1064main(int argc, char **argv)
1065{
1066 uint32_t *time_map;
David Goulet0809df12012-07-31 23:27:34 -04001067 struct tlsdate_time start_time, end_time, warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +01001068 int status;
1069 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +01001070 long long rt_time_ms;
1071 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001072 int setclock;
1073 int showtime;
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001074 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -04001075 int leap;
Christian Grothoff88b422b2012-02-14 00:35:09 +01001076
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -04001077 if (argc != 12)
Christian Grothoff88b422b2012-02-14 00:35:09 +01001078 return 1;
1079 host = argv[1];
Jacob Appelbaum5cc5ede2012-11-02 00:10:18 +00001080 hostname_to_verify = argv[1];
Christian Grothoff88b422b2012-02-14 00:35:09 +01001081 port = argv[2];
1082 protocol = argv[3];
Jacob Appelbaum12e15c92013-01-07 11:17:32 -08001083 ca_cert_container = argv[6];
Christian Grothoff88b422b2012-02-14 00:35:09 +01001084 ca_racket = (0 != strcmp ("unchecked", argv[4]));
1085 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001086 setclock = (0 == strcmp ("setclock", argv[7]));
1087 showtime = (0 == strcmp ("showtime", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001088 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -04001089 leap = (0 == strcmp ("leapaway", argv[10]));
Elly Fong-Jones4687c5d2012-10-03 17:34:48 -04001090 proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001091
1092 if (timewarp)
1093 {
Jacob Appelbaumabb16cb2013-04-12 11:31:52 -07001094
Jacob Appelbaum96390032012-07-15 15:53:13 -04001095 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
David Goulet0809df12012-07-31 23:27:34 -04001096 (unsigned long) CLOCK_SEC(&warp_time),
1097 (unsigned long) CLOCK_USEC(&warp_time));
Jacob Appelbaumabb16cb2013-04-12 11:31:52 -07001098
1099 if (1 == setclock) {
1100 clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
1101 } else {
1102 verb ("V: we'll do the time warp another time - we're not setting clock\n");
1103 }
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001104 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001105
1106 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001107 if (0 == setclock && 0 == timewarp)
1108 {
Elly Fong-Jonesa5e7fbb2013-01-08 14:08:33 -05001109 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001110 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001111
Jacob Appelbaumdb5f01f2013-02-05 22:27:29 -05001112 // We cast the mmap value to remove this error when compiling with g++:
1113 // src/tlsdate-helper.c: In function ‘int main(int, char**)’:
1114 // src/tlsdate-helper.c:822:41: error: invalid conversion from ‘void*’ to ‘uint32_t
1115 time_map = (uint32_t *) mmap (NULL, sizeof (uint32_t),
Jacob Appelbaumd84456c2012-02-15 16:02:31 -08001116 PROT_READ | PROT_WRITE,
1117 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
Jacob Appelbaumdb5f01f2013-02-05 22:27:29 -05001118 if (MAP_FAILED == time_map)
Christian Grothoff88b422b2012-02-14 00:35:09 +01001119 {
1120 fprintf (stderr, "mmap failed: %s\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001121 strerror (errno));
Christian Grothoff88b422b2012-02-14 00:35:09 +01001122 return 1;
1123 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001124
1125 /* Get the current time from the system clock. */
David Goulet0809df12012-07-31 23:27:34 -04001126 if (0 != clock_get_real_time(&start_time))
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001127 {
Christian Grothoff88b422b2012-02-14 00:35:09 +01001128 die ("Failed to read current time of day: %s\n", strerror (errno));
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001129 }
1130
Christian Grothoff191cd982012-02-14 00:48:45 +01001131 verb ("V: time is currently %lu.%06lu\n",
David Goulet0809df12012-07-31 23:27:34 -04001132 (unsigned long) CLOCK_SEC(&start_time),
1133 (unsigned long) CLOCK_NSEC(&start_time));
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001134
David Goulet0809df12012-07-31 23:27:34 -04001135 if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001136 {
1137 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
1138 if (timewarp)
1139 {
1140 verb ("V: Attempting to warp local clock into the future\n");
David Goulet0809df12012-07-31 23:27:34 -04001141 if (0 != clock_set_real_time(&warp_time))
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001142 {
1143 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
1144 strerror (errno),
David Goulet0809df12012-07-31 23:27:34 -04001145 (unsigned long) CLOCK_SEC(&warp_time),
1146 (unsigned long) CLOCK_SEC(&warp_time));
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001147 }
David Goulet0809df12012-07-31 23:27:34 -04001148 if (0 != clock_get_real_time(&start_time))
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001149 {
1150 die ("Failed to read current time of day: %s\n", strerror (errno));
1151 }
1152 verb ("V: time is currently %lu.%06lu\n",
David Goulet0809df12012-07-31 23:27:34 -04001153 (unsigned long) CLOCK_SEC(&start_time),
1154 (unsigned long) CLOCK_NSEC(&start_time));
Jacob Appelbaum894d5272012-07-15 14:32:39 -04001155 verb ("V: It's just a step to the left...\n");
1156 }
1157 } else {
1158 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
1159 }
Christian Grothoff191cd982012-02-14 00:48:45 +01001160
1161 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001162 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +01001163
1164 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +01001165 ssl_child = fork ();
1166 if (-1 == ssl_child)
1167 die ("fork failed: %s\n", strerror (errno));
1168 if (0 == ssl_child)
1169 {
Elly Fong-Jonesa5e7fbb2013-01-08 14:08:33 -05001170 drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -04001171 run_ssl (time_map, leap);
Christian Grothoff88b422b2012-02-14 00:35:09 +01001172 (void) munmap (time_map, sizeof (uint32_t));
1173 _exit (0);
Jorge Lucangeli Obesf5d7bf82012-12-12 10:21:01 -08001174 }
Christian Grothoff88b422b2012-02-14 00:35:09 +01001175 if (ssl_child != waitpid (ssl_child, &status, 0))
1176 die ("waitpid failed: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +01001177 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
1178 die ("child process failed in SSL handshake\n");
Christian Grothoff88b422b2012-02-14 00:35:09 +01001179
David Goulet0809df12012-07-31 23:27:34 -04001180 if (0 != clock_get_real_time(&end_time))
Christian Grothoff88b422b2012-02-14 00:35:09 +01001181 die ("Failed to read current time of day: %s\n", strerror (errno));
Jorge Lucangeli Obesf5d7bf82012-12-12 10:21:01 -08001182
Christian Grothoffe267c352012-02-14 01:10:54 +01001183 /* calculate RTT */
David Goulet0809df12012-07-31 23:27:34 -04001184 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 +01001185 if (rt_time_ms < 0)
1186 rt_time_ms = 0; /* non-linear time... */
Paul Bakker385386d2013-01-25 14:11:14 +01001187#ifdef USE_POLARSSL
1188 server_time_s = *time_map;
1189#else
Christian Grothoffe267c352012-02-14 01:10:54 +01001190 server_time_s = ntohl (*time_map);
Paul Bakker385386d2013-01-25 14:11:14 +01001191#endif
Jacob Appelbauma29d6952013-04-26 19:25:29 -07001192 // We should never have a time_map of zero here;
1193 // It either stayed zero or we have a false ticker.
Jacob Appelbaum1ad5c832013-04-26 19:40:23 -07001194 if ( 0 == server_time_s )
Jacob Appelbauma29d6952013-04-26 19:25:29 -07001195 die ("child process failed to update time map; weird platform issues?\n");
Christian Grothoffe267c352012-02-14 01:10:54 +01001196 munmap (time_map, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +01001197
Jacob Appelbaum9a159572012-02-20 12:39:44 -08001198 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -08001199 (unsigned int) server_time_s,
David Goulet0809df12012-07-31 23:27:34 -04001200 CLOCK_SEC(&start_time) - server_time_s,
Jacob Appelbaumd84456c2012-02-15 16:02:31 -08001201 rt_time_ms);
Christian Grothoff191cd982012-02-14 00:48:45 +01001202
Philipp Winterb3ca5772012-02-16 11:56:11 +01001203 /* warning if the handshake took too long */
1204 if (rt_time_ms > TLS_RTT_THRESHOLD) {
1205 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
1206 "server or run it again\n", TLS_RTT_THRESHOLD);
1207 }
1208
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001209 if (showtime)
1210 {
Jacob Appelbaum699a2762012-07-15 16:14:14 -04001211 struct tm ltm;
1212 time_t tim = server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001213 char buf[256];
1214
1215 localtime_r(&tim, &ltm);
A soldier31056a62012-08-16 01:10:57 -07001216 if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
1217 {
1218 die ("strftime returned 0\n");
1219 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001220 fprintf(stdout, "%s\n", buf);
1221 }
1222
Christian Grothoff191cd982012-02-14 00:48:45 +01001223 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001224 if (setclock)
Christian Grothoff90e9f832012-02-07 11:16:47 +01001225 {
David Goulet0809df12012-07-31 23:27:34 -04001226 struct tlsdate_time server_time;
Christian Grothoff90e9f832012-02-07 11:16:47 +01001227
David Goulet0809df12012-07-31 23:27:34 -04001228 clock_init_time(&server_time, server_time_s + (rt_time_ms / 2 / 1000),
1229 (rt_time_ms / 2) % 1000);
Christian Grothoffe267c352012-02-14 01:10:54 +01001230
Christian Grothoff90e9f832012-02-07 11:16:47 +01001231 // We should never receive a time that is before the time we were last
1232 // compiled; we subscribe to the linear theory of time for this program
1233 // and this program alone!
David Goulet0809df12012-07-31 23:27:34 -04001234 if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -08001235 die("remote server is a false ticker from the future!\n");
David Goulet0809df12012-07-31 23:27:34 -04001236 if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -08001237 die ("remote server is a false ticker!\n");
David Goulet0809df12012-07-31 23:27:34 -04001238 if (0 != clock_set_real_time(&server_time))
Stewart Smithf4780442012-06-29 14:31:49 +10001239 die ("setting time failed: %s (Difference from server is about %d)\n",
Jacob Appelbaum699a2762012-07-15 16:14:14 -04001240 strerror (errno),
David Goulet0809df12012-07-31 23:27:34 -04001241 CLOCK_SEC(&start_time) - server_time_s);
Jeroen Massarc27a92a2012-07-13 11:49:05 +02001242 verb ("V: setting time succeeded\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +01001243 }
Christian Grothoff90e9f832012-02-07 11:16:47 +01001244 return 0;
1245}