blob: fd97e39b5a2eea77f83758a4096b6cb645460358 [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
Jacob Appelbaum96390032012-07-15 15:53:13 -040077#include "../config/tlsdate-config.h"
Jacob Appelbaum8355d732012-07-30 01:29:05 -070078#include "tlsdate-helper.h"
Christian Grothoff90e9f832012-02-07 11:16:47 +010079
Elly Jones9ae3aa62012-06-20 15:32:46 -040080
Christian Grothoff191cd982012-02-14 00:48:45 +010081/** helper function to print message and die */
Christian Grothoff90e9f832012-02-07 11:16:47 +010082static void
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -070083die (const char *fmt, ...)
Christian Grothoff90e9f832012-02-07 11:16:47 +010084{
85 va_list ap;
86
87 va_start(ap, fmt);
88 vfprintf(stderr, fmt, ap);
89 va_end(ap);
90 exit(1);
91}
92
93
Christian Grothoff90e9f832012-02-07 11:16:47 +010094/** helper function for 'verbose' output */
95static void
96verb (const char *fmt, ...)
97{
98 va_list ap;
99
Christian Grothoffafbae372012-02-07 14:17:53 +0100100 if (! verbose) return;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100101 va_start(ap, fmt);
102 // FIXME: stdout or stderr for verbose messages?
103 vfprintf(stderr, fmt, ap);
104 va_end(ap);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100105}
106
107
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700108void
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700109openssl_time_callback (const SSL* ssl, int where, int ret)
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700110{
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700111 if (where == SSL_CB_CONNECT_LOOP && ssl->state == SSL3_ST_CR_CERT_A)
112 {
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700113 // XXX TODO: If we want to trust the remote system for time,
114 // can we just read that time out of the remote system and if the
115 // cert verifies, decide that the time is reasonable?
116 // Such a process seems to indicate that a once valid cert would be
117 // forever valid - we stopgap that by ensuring it isn't less than
118 // the latest compiled_time and isn't above max_reasonable_time...
119 // XXX TODO: Solve eternal question about the Chicken and the Egg...
120 uint32_t compiled_time = RECENT_COMPILE_DATE;
121 uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700122 uint32_t server_time;
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700123 verb("V: freezing time for x509 verification\n");
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700124 memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700125 if (compiled_time < ntohl(server_time)
126 &&
127 ntohl(server_time) < max_reasonable_time)
128 {
129 verb("V: remote peer provided: %d, prefered over compile time: %d\n",
130 ntohl(server_time), compiled_time);
131 verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
132 X509_VERIFY_PARAM_set_time(ssl->ctx->param, (time_t) ntohl(server_time));
133 } else {
134 die("V: the remote server is a false ticker! server: %d compile: %d\n",
135 ntohl(server_time), compiled_time);
136 }
Jacob Appelbaum123bb3e2012-07-16 17:25:34 -0700137 }
138}
139
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700140uint32_t
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700141get_certificate_keybits (EVP_PKEY *public_key)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700142{
143 /*
144 In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
145 */
146 uint32_t key_bits;
147 switch (public_key->type)
148 {
149 case EVP_PKEY_RSA:
150 verb("V: key type: EVP_PKEY_RSA\n");
151 key_bits = BN_num_bits(public_key->pkey.rsa->n);
152 break;
153 case EVP_PKEY_RSA2:
154 verb("V: key type: EVP_PKEY_RSA2\n");
155 key_bits = BN_num_bits(public_key->pkey.rsa->n);
156 break;
157 case EVP_PKEY_DSA:
158 verb("V: key type: EVP_PKEY_DSA\n");
159 key_bits = BN_num_bits(public_key->pkey.dsa->p);
160 break;
161 case EVP_PKEY_DSA1:
162 verb("V: key type: EVP_PKEY_DSA1\n");
163 key_bits = BN_num_bits(public_key->pkey.dsa->p);
164 break;
165 case EVP_PKEY_DSA2:
166 verb("V: key type: EVP_PKEY_DSA2\n");
167 key_bits = BN_num_bits(public_key->pkey.dsa->p);
168 break;
169 case EVP_PKEY_DSA3:
170 verb("V: key type: EVP_PKEY_DSA3\n");
171 key_bits = BN_num_bits(public_key->pkey.dsa->p);
172 break;
173 case EVP_PKEY_DSA4:
174 verb("V: key type: EVP_PKEY_DSA4\n");
175 key_bits = BN_num_bits(public_key->pkey.dsa->p);
176 break;
177 case EVP_PKEY_DH:
178 verb("V: key type: EVP_PKEY_DH\n");
179 key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
180 break;
181 case EVP_PKEY_EC:
182 verb("V: key type: EVP_PKEY_EC\n");
183 key_bits = EVP_PKEY_bits(public_key);
184 break;
185 // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
186 default:
187 key_bits = 0;
188 die ("unknown public key type\n");
189 break;
190 }
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700191 verb ("V: keybits: %d\n", key_bits);
192 return key_bits;
193}
194
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700195/**
196 This extracts the first commonName and checks it against hostname.
197*/
198uint32_t
199check_cn (SSL *ssl, const char *hostname)
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700200{
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700201 uint32_t ret;
202 char *cn_buf;
203 X509 *certificate;
Jacob Appelbaum6bb4b812012-07-30 02:27:37 -0700204 cn_buf = malloc(MAX_CN_NAME_LENGTH);
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700205 if (NULL == cn_buf)
206 {
207 die ("Unable to allocate memory for cn_buf\n");
Jacob Appelbaumf3ef6382012-07-18 10:34:54 -0700208 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700209 certificate = SSL_get_peer_certificate(ssl);
210
211 memset(cn_buf, '\0', (strlen(hostname) + 1));
212 ret = X509_NAME_get_text_by_NID(X509_get_subject_name(certificate),
213 NID_commonName, cn_buf, (strlen(hostname) + 1));
214
215 if (-1 == ret && ret != strlen(hostname))
216 {
217 die ("Unable to extract commonName\n");
218 }
219 if (strcasecmp(cn_buf, hostname))
220 {
Jacob Appelbaum6bb4b812012-07-30 02:27:37 -0700221 verb ("V: commonName mismatch! Expected: %s - received: %s\n",
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700222 hostname, cn_buf);
Jacob Appelbaumc548c292012-07-30 02:04:35 -0700223 return 0;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700224 } else {
225 verb ("V: commonName match\n");
226 return 1;
227 }
228 return 0;
229}
230
231/**
232 Search for a hostname match in the SubjectAlternativeNames.
233*/
234uint32_t
235check_san (SSL *ssl, const char *hostname)
236{
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700237 X509 *cert;
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700238 int extcount, ok = 0;
239 /* What an OpenSSL mess ... */
240 if (NULL == (cert = SSL_get_peer_certificate(ssl)))
241 {
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700242 die ("Getting certificate failed\n");
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700243 }
244
245 if ((extcount = X509_get_ext_count(cert)) > 0)
246 {
247 int i;
248 for (i = 0; i < extcount; ++i)
249 {
250 const char *extstr;
251 X509_EXTENSION *ext;
252 ext = X509_get_ext(cert, i);
253 extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
254
255 if (!strcmp(extstr, "subjectAltName"))
256 {
257
258 int j;
259 void *extvalstr;
260 const unsigned char *tmp;
261
262 STACK_OF(CONF_VALUE) *val;
263 CONF_VALUE *nval;
264 X509V3_EXT_METHOD *method;
265
266 if (!(method = X509V3_EXT_get(ext)))
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700267 {
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700268 break;
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700269 }
270
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700271 tmp = ext->value->data;
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700272 if (method->it)
273 {
274 extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
275 ASN1_ITEM_ptr(method->it));
276 } else {
277 extvalstr = method->d2i(NULL, &tmp, ext->value->length);
278 }
279
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700280 if (!extvalstr)
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700281 {
282 break;
283 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700284
285 if (method->i2v)
286 {
287 val = method->i2v(method, extvalstr, NULL);
288 for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
289 {
290 nval = sk_CONF_VALUE_value(val, j);
291 if (!strcasecmp(nval->name, "DNS") &&
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700292 !strcasecmp(nval->value, host))
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700293 {
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700294 verb ("V: subjectAltName matched\n");
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700295 ok = 1;
296 break;
297 }
298 }
299 }
300 }
301 if (ok)
302 break;
303 }
304 }
Jacob Appelbaumfc9761e2012-07-30 01:29:49 -0700305 X509_free(cert);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700306 return ok;
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700307}
308
309uint32_t
310check_name (SSL *ssl, const char *hostname)
311{
312 uint32_t ret;
313 ret = check_cn(ssl, hostname);
314 ret += check_san(ssl, hostname);
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700315 if (0 != ret)
316 {
317 verb ("V: subjectAltName host verification passed\n");
318 } else {
319 die ("subjectAltName host verification failed for host %s!\n", host);
320 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700321 return ret;
322}
323
324uint32_t
325verify_signature (SSL *ssl, const char *hostname)
326{
327 long ssl_verify_result;
328 X509 *certificate;
329
330 certificate = SSL_get_peer_certificate(ssl);
331 if (NULL == certificate)
332 {
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700333 die ("Getting certificate failed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700334 }
335 // In theory, we verify that the cert is valid
336 ssl_verify_result = SSL_get_verify_result(ssl);
337 switch (ssl_verify_result)
338 {
339 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
340 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700341 die ("certificate is self signed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700342 case X509_V_OK:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700343 verb ("V: certificate verification passed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700344 break;
345 default:
Jacob Appelbaum145886f2012-07-30 01:56:53 -0700346 die ("certification verification error: %ld\n",
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700347 ssl_verify_result);
348 }
349 return 0;
350}
351
352void
353check_key_length (SSL *ssl)
354{
355 uint32_t key_bits;
356 X509 *certificate;
357 EVP_PKEY *public_key;
358 certificate = SSL_get_peer_certificate (ssl);
359 public_key = X509_get_pubkey (certificate);
360 if (NULL == public_key)
361 {
362 die ("public key extraction failure\n");
363 } else {
364 verb ("V: public key is ready for inspection\n");
365 }
366
367 key_bits = get_certificate_keybits (public_key);
368 if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
369 {
370 die ("Unsafe public key size: %d bits\n", key_bits);
371 } else {
372 if (public_key->type == EVP_PKEY_EC)
373 if(key_bits >= MIN_ECC_PUB_KEY_LEN
374 && key_bits <= MAX_ECC_PUB_KEY_LEN)
375 {
376 verb ("V: ECC key length appears safe\n");
377 } else {
378 die ("Unsafe ECC key size: %d bits\n", key_bits);
379 } else {
380 verb ("V: key length appears safe\n");
381 }
382 }
383 EVP_PKEY_free (public_key);
384}
385
386void
387inspect_key (SSL *ssl, const char *hostname)
388{
389
390 verify_signature (ssl, hostname);
391 check_name (ssl, hostname);
Jacob Appelbaumc4d3f9f2012-07-17 18:20:56 -0700392}
393
Christian Grothoff88b422b2012-02-14 00:35:09 +0100394/**
395 * Run SSL handshake and store the resulting time value in the
396 * 'time_map'.
397 *
398 * @param time_map where to store the current time
399 */
400static void
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400401run_ssl (uint32_t *time_map, int time_is_an_illusion)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100402{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100403 BIO *s_bio;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100404 SSL_CTX *ctx;
405 SSL *ssl;
406
Christian Grothoff90e9f832012-02-07 11:16:47 +0100407 SSL_load_error_strings();
408 SSL_library_init();
409
410 ctx = NULL;
411 if (0 == strcmp("sslv23", protocol))
412 {
413 verb ("V: using SSLv23_client_method()\n");
414 ctx = SSL_CTX_new(SSLv23_client_method());
415 } else if (0 == strcmp("sslv3", protocol))
416 {
417 verb ("V: using SSLv3_client_method()\n");
418 ctx = SSL_CTX_new(SSLv3_client_method());
419 } else if (0 == strcmp("tlsv1", protocol))
420 {
421 verb ("V: using TLSv1_client_method()\n");
422 ctx = SSL_CTX_new(TLSv1_client_method());
423 } else
424 die("Unsupported protocol `%s'\n", protocol);
425
426 if (ctx == NULL)
427 die("OpenSSL failed to support protocol `%s'\n", protocol);
428
429 if (ca_racket)
430 {
Elly Jones9ae3aa62012-06-20 15:32:46 -0400431 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, certdir))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100432 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
433 }
434
435 if (NULL == (s_bio = BIO_new_ssl_connect(ctx)))
436 die ("SSL BIO setup failed\n");
437 BIO_get_ssl(s_bio, &ssl);
438 if (NULL == ssl)
439 die ("SSL setup failed\n");
Jacob Appelbaum9f807292012-07-16 18:24:37 -0700440
441 if (time_is_an_illusion)
442 {
443 SSL_set_info_callback(ssl, openssl_time_callback);
444 }
445
Christian Grothoff90e9f832012-02-07 11:16:47 +0100446 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
447 if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
448 (1 != BIO_set_conn_port(s_bio, port)) )
449 die ("Failed to initialize connection to `%s:%s'\n", host, port);
450
Stewart Smith3aa3f382012-06-29 14:36:34 +1000451 if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
452 die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
Christian Grothoff90e9f832012-02-07 11:16:47 +0100453
Jacob Appelbaum405a7932012-02-15 15:22:02 -0800454 // This should run in seccomp
455 // eg: prctl(PR_SET_SECCOMP, 1);
456 if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800457 die ("SSL connection failed\n");
Philipp Winterd96af622012-02-15 22:15:50 +0100458 if (1 != BIO_do_handshake(s_bio))
459 die ("SSL handshake failed\n");
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700460
Christian Grothoff90e9f832012-02-07 11:16:47 +0100461 // Verify the peer certificate against the CA certs on the local system
462 if (ca_racket) {
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700463 inspect_key (ssl, host);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100464 } else {
465 verb ("V: Certificate verification skipped!\n");
466 }
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700467 check_key_length(ssl);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100468 // from /usr/include/openssl/ssl3.h
Jacob Appelbaumca64b502012-06-28 21:54:14 -0700469 // ssl->s3->server_random is an unsigned char of 32 bits
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800470 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
Jacob Appelbaum8355d732012-07-30 01:29:05 -0700471 SSL_free(ssl);
Jacob Appelbaumb79b0eb2012-07-29 23:00:21 -0700472 SSL_CTX_free(ctx);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100473}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100474
Christian Grothoff191cd982012-02-14 00:48:45 +0100475/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100476static void
Jacob Appelbaum42ccf9d2012-07-29 16:30:15 -0700477become_nobody (void)
Christian Grothoffbd15a222012-02-14 00:40:57 +0100478{
479 uid_t uid;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800480 gid_t gid;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100481 struct passwd *pw;
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800482 struct group *gr;
Christian Grothoffbd15a222012-02-14 00:40:57 +0100483
Christian Grothoffe267c352012-02-14 01:10:54 +0100484 if (0 != getuid ())
485 return; /* not running as root to begin with; should (!) be harmless to continue
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800486 without dropping to 'nobody' (setting time will fail in the end) */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100487 pw = getpwnam(UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800488 gr = getgrnam(UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100489 if (NULL == pw)
490 die ("Failed to obtain UID for `%s'\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800491 if (NULL == gr)
492 die ("Failed to obtain GID for `%s'\n", UNPRIV_GROUP);
Christian Grothoffbd15a222012-02-14 00:40:57 +0100493 uid = pw->pw_uid;
494 if (0 == uid)
495 die ("UID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800496 gid = pw->pw_gid;
497 if (0 == gid || 0 == gr->gr_gid)
498 die ("GID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
499 if (pw->pw_gid != gr->gr_gid)
Jacob Appelbaumad873f32012-02-21 14:36:10 -0800500 die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
501 UNPRIV_USER, UNPRIV_GROUP);
502
503 if (0 != initgroups((const char *)UNPRIV_USER, gr->gr_gid))
504 die ("Unable to initgroups for `%s' in group `%s' as expected\n",
505 UNPRIV_USER, UNPRIV_GROUP);
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800506
507#ifdef HAVE_SETRESGID
508 if (0 != setresgid (gid, gid, gid))
509 die ("Failed to setresgid: %s\n", strerror (errno));
510#else
511 if (0 != (setgid (gid) | setegid (gid)))
512 die ("Failed to setgid: %s\n", strerror (errno));
513#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100514#ifdef HAVE_SETRESUID
515 if (0 != setresuid (uid, uid, uid))
516 die ("Failed to setresuid: %s\n", strerror (errno));
517#else
518 if (0 != (setuid (uid) | seteuid (uid)))
519 die ("Failed to setuid: %s\n", strerror (errno));
Jacob Appelbaum2c385d22012-02-21 14:04:15 -0800520#endif
Christian Grothoffbd15a222012-02-14 00:40:57 +0100521}
522
523
Christian Grothoff88b422b2012-02-14 00:35:09 +0100524int
525main(int argc, char **argv)
526{
527 uint32_t *time_map;
528 struct timeval start_timeval;
529 struct timeval end_timeval;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400530 struct timeval warp_time;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100531 int status;
532 pid_t ssl_child;
Christian Grothoffe267c352012-02-14 01:10:54 +0100533 long long rt_time_ms;
534 uint32_t server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200535 int setclock;
536 int showtime;
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400537 int timewarp;
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400538 int leap;
Christian Grothoff88b422b2012-02-14 00:35:09 +0100539
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400540 if (argc != 11)
Christian Grothoff88b422b2012-02-14 00:35:09 +0100541 return 1;
542 host = argv[1];
543 port = argv[2];
544 protocol = argv[3];
Elly Jones9ae3aa62012-06-20 15:32:46 -0400545 certdir = argv[6];
Christian Grothoff88b422b2012-02-14 00:35:09 +0100546 ca_racket = (0 != strcmp ("unchecked", argv[4]));
547 verbose = (0 != strcmp ("quiet", argv[5]));
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200548 setclock = (0 == strcmp ("setclock", argv[7]));
549 showtime = (0 == strcmp ("showtime", argv[8]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400550 timewarp = (0 == strcmp ("timewarp", argv[9]));
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400551 leap = (0 == strcmp ("leapaway", argv[10]));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400552
553 if (timewarp)
554 {
555 warp_time.tv_sec = RECENT_COMPILE_DATE;
556 warp_time.tv_usec = 0;
Jacob Appelbaum96390032012-07-15 15:53:13 -0400557 verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
558 (unsigned long)warp_time.tv_sec,
559 (unsigned long)warp_time.tv_usec);
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400560 }
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200561
562 /* We are not going to set the clock, thus no need to stay root */
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400563 if (0 == setclock && 0 == timewarp)
564 {
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200565 become_nobody ();
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400566 }
Christian Grothoff88b422b2012-02-14 00:35:09 +0100567
568 time_map = mmap (NULL, sizeof (uint32_t),
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800569 PROT_READ | PROT_WRITE,
570 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100571 if (MAP_FAILED == time_map)
572 {
573 fprintf (stderr, "mmap failed: %s\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400574 strerror (errno));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100575 return 1;
576 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100577
578 /* Get the current time from the system clock. */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100579 if (0 != gettimeofday(&start_timeval, NULL))
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400580 {
Christian Grothoff88b422b2012-02-14 00:35:09 +0100581 die ("Failed to read current time of day: %s\n", strerror (errno));
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400582 }
583
Christian Grothoff191cd982012-02-14 00:48:45 +0100584 verb ("V: time is currently %lu.%06lu\n",
Jacob Appelbaum894d5272012-07-15 14:32:39 -0400585 (unsigned long)start_timeval.tv_sec,
586 (unsigned long)start_timeval.tv_usec);
587
588 if (((unsigned long)start_timeval.tv_sec) < ((unsigned long)warp_time.tv_sec))
589 {
590 verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
591 if (timewarp)
592 {
593 verb ("V: Attempting to warp local clock into the future\n");
594 if (0 != settimeofday(&warp_time, NULL))
595 {
596 die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
597 strerror (errno),
598 (unsigned long)warp_time.tv_sec,
599 (unsigned long)warp_time.tv_usec);
600 }
601 if (0 != gettimeofday(&start_timeval, NULL))
602 {
603 die ("Failed to read current time of day: %s\n", strerror (errno));
604 }
605 verb ("V: time is currently %lu.%06lu\n",
606 (unsigned long)start_timeval.tv_sec,
607 (unsigned long)start_timeval.tv_usec);
608 verb ("V: It's just a step to the left...\n");
609 }
610 } else {
611 verb ("V: time is greater than RECENT_COMPILE_DATE\n");
612 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100613
614 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100615 *time_map = 0;
Christian Grothoffe267c352012-02-14 01:10:54 +0100616
617 /* Run SSL interaction in separate process (and not as 'root') */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100618 ssl_child = fork ();
619 if (-1 == ssl_child)
620 die ("fork failed: %s\n", strerror (errno));
621 if (0 == ssl_child)
622 {
Christian Grothoffbd15a222012-02-14 00:40:57 +0100623 become_nobody ();
Jacob Appelbaumc732f4e2012-07-15 22:38:46 -0400624 run_ssl (time_map, leap);
Christian Grothoff88b422b2012-02-14 00:35:09 +0100625 (void) munmap (time_map, sizeof (uint32_t));
626 _exit (0);
627 }
628 if (ssl_child != waitpid (ssl_child, &status, 0))
629 die ("waitpid failed: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +0100630 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
631 die ("child process failed in SSL handshake\n");
Christian Grothoff88b422b2012-02-14 00:35:09 +0100632
633 if (0 != gettimeofday(&end_timeval, NULL))
634 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoffe267c352012-02-14 01:10:54 +0100635
636 /* calculate RTT */
637 rt_time_ms = (end_timeval.tv_sec - start_timeval.tv_sec) * 1000 + (end_timeval.tv_usec - start_timeval.tv_usec) / 1000;
638 if (rt_time_ms < 0)
639 rt_time_ms = 0; /* non-linear time... */
640 server_time_s = ntohl (*time_map);
641 munmap (time_map, sizeof (uint32_t));
Christian Grothoff88b422b2012-02-14 00:35:09 +0100642
Jacob Appelbaum9a159572012-02-20 12:39:44 -0800643 verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800644 (unsigned int) server_time_s,
645 start_timeval.tv_sec - server_time_s,
646 rt_time_ms);
Christian Grothoff191cd982012-02-14 00:48:45 +0100647
Philipp Winterb3ca5772012-02-16 11:56:11 +0100648 /* warning if the handshake took too long */
649 if (rt_time_ms > TLS_RTT_THRESHOLD) {
650 verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
651 "server or run it again\n", TLS_RTT_THRESHOLD);
652 }
653
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200654 if (showtime)
655 {
Jacob Appelbaum699a2762012-07-15 16:14:14 -0400656 struct tm ltm;
657 time_t tim = server_time_s;
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200658 char buf[256];
659
660 localtime_r(&tim, &ltm);
661 (void) strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm);
662 fprintf(stdout, "%s\n", buf);
663 }
664
Christian Grothoff191cd982012-02-14 00:48:45 +0100665 /* finally, actually set the time */
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200666 if (setclock)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100667 {
668 struct timeval server_time;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100669
Christian Grothoffe267c352012-02-14 01:10:54 +0100670 /* correct server time by half of RTT */
671 server_time.tv_sec = server_time_s + (rt_time_ms / 2 / 1000);
672 server_time.tv_usec = (rt_time_ms / 2) % 1000;
673
Christian Grothoff90e9f832012-02-07 11:16:47 +0100674 // We should never receive a time that is before the time we were last
675 // compiled; we subscribe to the linear theory of time for this program
676 // and this program alone!
Christian Grothofff5098b42012-02-07 12:20:33 +0100677 if (server_time.tv_sec >= MAX_REASONABLE_TIME)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800678 die("remote server is a false ticker from the future!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100679 if (server_time.tv_sec <= RECENT_COMPILE_DATE)
Jacob Appelbaumd84456c2012-02-15 16:02:31 -0800680 die ("remote server is a false ticker!\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100681 if (0 != settimeofday(&server_time, NULL))
Stewart Smithf4780442012-06-29 14:31:49 +1000682 die ("setting time failed: %s (Difference from server is about %d)\n",
Jacob Appelbaum699a2762012-07-15 16:14:14 -0400683 strerror (errno),
684 start_timeval.tv_sec - server_time_s);
Jeroen Massarc27a92a2012-07-13 11:49:05 +0200685 verb ("V: setting time succeeded\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100686 }
Christian Grothoff90e9f832012-02-07 11:16:47 +0100687 return 0;
688}