blob: bdcad9d50134cc58d08f53e9a14796295837aac3 [file] [log] [blame]
Christian Grothoff90e9f832012-02-07 11:16:47 +01001/* Copyright (c) 2012, Jacob Appelbaum.
2 * Copyright (c) 2012, The Tor Project, Inc. */
3/* See LICENSE for licensing information */
4/*
5 This file contains the license for tlsdate,
6 a free software project to set your system clock securely.
7
8 It also lists the licenses for other components used by tlsdate.
9
10 For more information about tlsdate, see https://github.com/ioerror/tlsdate
11
12 If you got this file as a part of a larger bundle,
13 there may be other license terms that you should be aware of.
14
15===============================================================================
16tlsdate is distributed under this license:
17
18Copyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
19Copyright (c) 2011-2012, The Tor Project, Inc.
20
21Redistribution and use in source and binary forms, with or without
22modification, are permitted provided that the following conditions are
23met:
24
25 * Redistributions of source code must retain the above copyright
26notice, this list of conditions and the following disclaimer.
27
28 * Redistributions in binary form must reproduce the above
29copyright notice, this list of conditions and the following disclaimer
30in the documentation and/or other materials provided with the
31distribution.
32
33 * Neither the names of the copyright owners nor the names of its
34contributors may be used to endorse or promote products derived from
35this software without specific prior written permission.
36
37THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48===============================================================================
49If you got tlsdate as a static binary with OpenSSL included, then you should
50know:
51
52 "This product includes software developed by the OpenSSL Project for use in
53 the OpenSSL Toolkit (http://www.openssl.org/)"
54
55===============================================================================
56*/
57
58/**
59 * \file tlsdate.c
60 * \brief The main program to assist in setting the system clock.
61 **/
62
63/*
64 * tlsdate is a tool for setting the system clock by hand or by communication
65 * with the network. It does not set the RTC. It is designed to be as secure as
66 * TLS (RFC 2246) but of course the security of TLS is often reduced to
67 * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
68 * your local CA root store - so any of these companies could assist in a MITM
69 * attack against you and you'd be screwed.
70
71 * This tool is designed to be run by hand or as a system daemon. It must be
72 * run as root or otherwise have the proper caps; it will not be able to set
73 * the system time without running as root or another privileged user.
74 */
75
76#include "tlsdate-config.h"
77
78#include <stdarg.h>
79#include <stdint.h>
Christian Grothoff191cd982012-02-14 00:48:45 +010080#include <stdio.h>
81#include <unistd.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010082#include <sys/time.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010083#include <sys/types.h>
84#include <sys/wait.h>
Christian Grothoff88b422b2012-02-14 00:35:09 +010085#include <sys/mman.h>
Christian Grothoff191cd982012-02-14 00:48:45 +010086#include <time.h>
87#include <pwd.h>
Christian Grothoff90e9f832012-02-07 11:16:47 +010088#include <arpa/inet.h>
89
90#include <openssl/bio.h>
91#include <openssl/ssl.h>
92#include <openssl/err.h>
93#include <openssl/evp.h>
94
Christian Grothoff191cd982012-02-14 00:48:45 +010095/** Name of user that we feel safe to run SSL handshake with. */
Christian Grothoff90e9f832012-02-07 11:16:47 +010096#define UNPRIV_USER "nobody"
97
98// We should never accept a time before we were compiled
99// We measure in seconds since the epoch - eg: echo `date '+%s'`
100// We set this manually to ensure others can reproduce a build;
101// automation of this will make every build different!
Christian Grothofff5098b42012-02-07 12:20:33 +0100102#define RECENT_COMPILE_DATE (uint32_t) 1328610583
dave blf4a92d52012-02-07 22:39:24 +0800103#define MAX_REASONABLE_TIME (uint32_t) 1999991337
Christian Grothoff90e9f832012-02-07 11:16:47 +0100104
105
Christian Grothoff90e9f832012-02-07 11:16:47 +0100106static int verbose;
107
Christian Grothoff88b422b2012-02-14 00:35:09 +0100108static int ca_racket;
109
110static const char *host;
111
112static const char *port;
113
114static const char *protocol;
115
116
Christian Grothoff191cd982012-02-14 00:48:45 +0100117/** helper function to print message and die */
118static void
119die(const char *fmt, ...)
120{
121 va_list ap;
122
123 va_start(ap, fmt);
124 vfprintf(stderr, fmt, ap);
125 va_end(ap);
126 exit(1);
127}
128
129
Christian Grothoff90e9f832012-02-07 11:16:47 +0100130/** helper function for 'verbose' output */
131static void
132verb (const char *fmt, ...)
133{
134 va_list ap;
135
Christian Grothoffafbae372012-02-07 14:17:53 +0100136 if (! verbose) return;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100137 va_start(ap, fmt);
138 // FIXME: stdout or stderr for verbose messages?
139 vfprintf(stderr, fmt, ap);
140 va_end(ap);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100141}
142
143
Christian Grothoff88b422b2012-02-14 00:35:09 +0100144/**
145 * Run SSL handshake and store the resulting time value in the
146 * 'time_map'.
147 *
148 * @param time_map where to store the current time
149 */
150static void
151run_ssl (uint32_t *time_map)
Christian Grothoff90e9f832012-02-07 11:16:47 +0100152{
Christian Grothoff90e9f832012-02-07 11:16:47 +0100153 BIO *s_bio;
154 BIO *c_bio;
155 SSL_CTX *ctx;
156 SSL *ssl;
157
Christian Grothoff90e9f832012-02-07 11:16:47 +0100158 SSL_load_error_strings();
159 SSL_library_init();
160
161 ctx = NULL;
162 if (0 == strcmp("sslv23", protocol))
163 {
164 verb ("V: using SSLv23_client_method()\n");
165 ctx = SSL_CTX_new(SSLv23_client_method());
166 } else if (0 == strcmp("sslv3", protocol))
167 {
168 verb ("V: using SSLv3_client_method()\n");
169 ctx = SSL_CTX_new(SSLv3_client_method());
170 } else if (0 == strcmp("tlsv1", protocol))
171 {
172 verb ("V: using TLSv1_client_method()\n");
173 ctx = SSL_CTX_new(TLSv1_client_method());
174 } else
175 die("Unsupported protocol `%s'\n", protocol);
176
177 if (ctx == NULL)
178 die("OpenSSL failed to support protocol `%s'\n", protocol);
179
180 if (ca_racket)
181 {
182 // For google specifically:
183 // SSL_CTX_load_verify_locations(ctx, "/etc/ssl/certs/Equifax_Secure_CA.pem", NULL);
Jacob Appelbaum43051142012-02-07 14:00:39 +0100184 if (1 != SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs/"))
Christian Grothoff90e9f832012-02-07 11:16:47 +0100185 fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
186 }
187
188 if (NULL == (s_bio = BIO_new_ssl_connect(ctx)))
189 die ("SSL BIO setup failed\n");
190 BIO_get_ssl(s_bio, &ssl);
191 if (NULL == ssl)
192 die ("SSL setup failed\n");
193 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
194 if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
195 (1 != BIO_set_conn_port(s_bio, port)) )
196 die ("Failed to initialize connection to `%s:%s'\n", host, port);
197
198 if (NULL == (c_bio = BIO_new_fp(stdout, BIO_NOCLOSE)))
199 die ("FIXME: error message");
200
201 // This should run in seccomp
202 // eg: prctl(PR_SET_SECCOMP, 1);
Jacob Appelbaum43051142012-02-07 14:00:39 +0100203 if (1 != BIO_do_connect(s_bio)) // XXX TODO: BIO_should_retry() later?
Christian Grothoff1dbd04f2012-02-07 14:14:27 +0100204 die ("SSL connection failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100205 if (1 != BIO_do_handshake(s_bio))
206 die ("SSL handshake failed\n");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100207 // Verify the peer certificate against the CA certs on the local system
208 if (ca_racket) {
209 X509 *x509;
210 long ssl_verify_result;
211
212 verb ("V: Attempting to verify certificate\n");
213 if (NULL == (x509 = SSL_get_peer_certificate(ssl)) )
214 die ("Getting SSL certificate failed\n");
215
216 // In theory, we verify that the cert is valid
217 ssl_verify_result = SSL_get_verify_result(ssl);
218 switch (ssl_verify_result)
219 {
220 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
221 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
222 fprintf (stderr, "E: self signed cert\n");
223 break;
224 case X509_V_OK:
225 verb ("V: verification OK: %ld\n", ssl_verify_result);
226 break;
227 default:
228 fprintf(stderr, "E: verification error: %ld\n", ssl_verify_result);
229 break;
230 }
231 if (ssl_verify_result != X509_V_OK)
232 die("certificate verification failed!\n");
233 } else {
234 verb ("V: Certificate verification skipped!\n");
235 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100236
237 // from /usr/include/openssl/ssl3.h
238 // ssl->s3->server_random is an unsigned char of 32 bytes
Christian Grothoff88b422b2012-02-14 00:35:09 +0100239 memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
240}
Christian Grothoff90e9f832012-02-07 11:16:47 +0100241
242
Christian Grothoff191cd982012-02-14 00:48:45 +0100243/** drop root rights and become 'nobody' */
Christian Grothoffbd15a222012-02-14 00:40:57 +0100244static void
245become_nobody ()
246{
247 uid_t uid;
248 struct passwd *pw;
249
250 pw = getpwnam(UNPRIV_USER);
251 if (NULL == pw)
252 die ("Failed to obtain UID for `%s'\n", UNPRIV_USER);
253 uid = pw->pw_uid;
254 if (0 == uid)
255 die ("UID for `%s' is 0, refusing to run SSL\n", UNPRIV_USER);
256#ifdef HAVE_SETRESUID
257 if (0 != setresuid (uid, uid, uid))
258 die ("Failed to setresuid: %s\n", strerror (errno));
259#else
260 if (0 != (setuid (uid) | seteuid (uid)))
261 die ("Failed to setuid: %s\n", strerror (errno));
262#endif
263}
264
265
Christian Grothoff88b422b2012-02-14 00:35:09 +0100266int
267main(int argc, char **argv)
268{
269 uint32_t *time_map;
270 struct timeval start_timeval;
271 struct timeval end_timeval;
272 int status;
273 pid_t ssl_child;
274
275 if (argc != 6)
276 return 1;
277 host = argv[1];
278 port = argv[2];
279 protocol = argv[3];
280 ca_racket = (0 != strcmp ("unchecked", argv[4]));
281 verbose = (0 != strcmp ("quiet", argv[5]));
282
283 time_map = mmap (NULL, sizeof (uint32_t),
284 PROT_READ | PROT_WRITE,
285 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
286 if (MAP_FAILED == time_map)
287 {
288 fprintf (stderr, "mmap failed: %s\n",
289 strerror (errno));
290 return 1;
291 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100292
293 /* Get the current time from the system clock. */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100294 if (0 != gettimeofday(&start_timeval, NULL))
295 die ("Failed to read current time of day: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +0100296 verb ("V: time is currently %lu.%06lu\n",
297 (unsigned long)start_timeval.tv_sec,
298 (unsigned long)start_timeval.tv_usec);
299
300 /* initialize to bogus value, just to be on the safe side */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100301 *time_map = 0;
302 ssl_child = fork ();
303 if (-1 == ssl_child)
304 die ("fork failed: %s\n", strerror (errno));
305 if (0 == ssl_child)
306 {
Christian Grothoffbd15a222012-02-14 00:40:57 +0100307 become_nobody ();
Christian Grothoff88b422b2012-02-14 00:35:09 +0100308 run_ssl (time_map);
309 (void) munmap (time_map, sizeof (uint32_t));
310 _exit (0);
311 }
312 if (ssl_child != waitpid (ssl_child, &status, 0))
313 die ("waitpid failed: %s\n", strerror (errno));
Christian Grothoff191cd982012-02-14 00:48:45 +0100314 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
315 die ("child process failed in SSL handshake\n");
Christian Grothoff88b422b2012-02-14 00:35:09 +0100316
317 if (0 != gettimeofday(&end_timeval, NULL))
318 die ("Failed to read current time of day: %s\n", strerror (errno));
319
Christian Grothoff90e9f832012-02-07 11:16:47 +0100320 {
321 uint32_t rt_time;
322
323 /* FIXME: report in ms instead... */
324 /* FIXME: abs!? */
325 rt_time = abs(end_timeval.tv_sec - start_timeval.tv_sec);
326 verb ("V: server_random fetched in %i sec\n", rt_time);
327 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100328
329 /* finally, actually set the time */
Christian Grothoff90e9f832012-02-07 11:16:47 +0100330 {
331 struct timeval server_time;
Christian Grothoff90e9f832012-02-07 11:16:47 +0100332
Christian Grothoff88b422b2012-02-14 00:35:09 +0100333 server_time.tv_sec = ntohl(*time_map);
Christian Grothoff90e9f832012-02-07 11:16:47 +0100334 server_time.tv_usec = 0;
335 verb ("V: server_random with ntohl is: %lu.0\n",
336 (unsigned long)server_time.tv_sec);
337 // We should never receive a time that is before the time we were last
338 // compiled; we subscribe to the linear theory of time for this program
339 // and this program alone!
Christian Grothofff5098b42012-02-07 12:20:33 +0100340 if (server_time.tv_sec >= MAX_REASONABLE_TIME)
341 die("remote server is a false ticker from the future!");
Christian Grothoff90e9f832012-02-07 11:16:47 +0100342 if (server_time.tv_sec <= RECENT_COMPILE_DATE)
343 die ("remote server is a false ticker!");
344
345 // FIXME: correct by RTT?
346 if (0 != settimeofday(&server_time, NULL))
347 die ("V: setting time failed: %s\n", strerror (errno));
348 }
Christian Grothoff191cd982012-02-14 00:48:45 +0100349 /* clean up */
Christian Grothoff88b422b2012-02-14 00:35:09 +0100350 munmap (time_map, sizeof (uint32_t));
Christian Grothoff90e9f832012-02-07 11:16:47 +0100351 verb ("V: setting time succeeded\n");
352 return 0;
353}
354