122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/* Copyright (c) 2012, Jacob Appelbaum.
222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * Copyright (c) 2012, The Tor Project, Inc.
322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * Copyright (c) 2012, Christian Grothoff. */
422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/* See LICENSE for licensing information */
522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/*
622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                    This file contains the license for tlsdate,
722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        a free software project to set your system clock securely.
822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        It also lists the licenses for other components used by tlsdate.
1022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
1122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      For more information about tlsdate, see https://github.com/ioerror/tlsdate
1222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
1322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans             If you got this file as a part of a larger bundle,
1422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        there may be other license terms that you should be aware of.
1522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
1622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans===============================================================================
1722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanstlsdate is distributed under this license:
1822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
1922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansCopyright (c) 2011-2012, Jacob Appelbaum <jacob@appelbaum.net>
2022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansCopyright (c) 2011-2012, The Tor Project, Inc.
2122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
2222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansRedistribution and use in source and binary forms, with or without
2322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansmodification, are permitted provided that the following conditions are
2422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansmet:
2522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
2622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    * Redistributions of source code must retain the above copyright
2722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansnotice, this list of conditions and the following disclaimer.
2822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
2922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    * Redistributions in binary form must reproduce the above
3022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscopyright notice, this list of conditions and the following disclaimer
3122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansin the documentation and/or other materials provided with the
3222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansdistribution.
3322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
3422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    * Neither the names of the copyright owners nor the names of its
3522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscontributors may be used to endorse or promote products derived from
3622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansthis software without specific prior written permission.
3722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
3822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
4122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
4222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
4522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
4622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
4822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans===============================================================================
5022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah EvansIf you got tlsdate as a static binary with OpenSSL included, then you should
5122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansknow:
5222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
5322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans "This product includes software developed by the OpenSSL Project for use in
5422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  the OpenSSL Toolkit (http://www.openssl.org/)"
5522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
5622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans===============================================================================
5722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans*/
5822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
5922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/**
6022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * \file tlsdate-helper.c
6122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * \brief Helper program that does the actual work of setting the system clock.
6222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans **/
6322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
6422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/*
6522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * tlsdate is a tool for setting the system clock by hand or by communication
6622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * with the network. It does not set the RTC. It is designed to be as secure as
6722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * TLS (RFC 2246) but of course the security of TLS is often reduced to
6822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
6922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * your local CA root store - so any of these companies could assist in a MITM
7022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * attack against you and you'd be screwed.
7122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
7222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * This tool is designed to be run by hand or as a system daemon. It must be
7322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * run as root or otherwise have the proper caps; it will not be able to set
7422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * the system time without running as root or another privileged user.
7522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans */
7622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
7722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "config.h"
7822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "src/tlsdate-helper-plan9.h"
7922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
8022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifndef USE_POLARSSL
8122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "src/proxy-bio-plan9.h"
8222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else
8322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "src/proxy-polarssl.h"
8422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
8522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
8622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "src/compat/clock-plan9.h"
8722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
8822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifndef MAP_ANONYMOUS
8922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#define MAP_ANONYMOUS MAP_ANON
9022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
9122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
9222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
9322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "polarssl/entropy.h"
9422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "polarssl/ctr_drbg.h"
9522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#include "polarssl/ssl.h"
9622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
9722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
9822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
9922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvalidate_proxy_scheme(const char *scheme)
10022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
10122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!strcmp(scheme, "http"))
10222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return;
10322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!strcmp(scheme, "socks4"))
10422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return;
10522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!strcmp(scheme, "socks5"))
10622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return;
10722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  die("invalid proxy scheme\n");
10822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
10922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
11022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
11122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvalidate_proxy_host(const char *host)
11222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
11322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
11422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                       "abcdefghijklmnopqrstuvwxyz"
11522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                       "0123456789"
11622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                       ".-";
11722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (strspn(host, kValid) != strlen(host))
11822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("invalid char in host\n");
11922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
12022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
12122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
12222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvalidate_proxy_port(const char *port)
12322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
12422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  while (*port)
12522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (!isdigit(*port++))
12622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("invalid char in port\n");
12722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
12822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
12922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
13022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansparse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
13122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
13222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
13322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *scheme = proxy;
13422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy = strstr(proxy, "://");
13522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!proxy)
13622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("malformed proxy URI\n");
13722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *proxy = '\0'; /* terminate scheme string */
13822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy += strlen("://");
13922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
14022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *host = proxy;
14122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy = strchr(proxy, ':');
14222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!proxy)
14322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("malformed proxy URI\n");
14422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *proxy++ = '\0';
14522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
14622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *port = proxy;
14722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
14822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  validate_proxy_scheme(*scheme);
14922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  validate_proxy_host(*host);
15022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  validate_proxy_port(*port);
15122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
15222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
15322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifndef USE_POLARSSL
15422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
15522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanssetup_proxy(BIO *ssl)
15622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
15722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO *bio;
15822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *scheme;
15922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *proxy_host;
16022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *proxy_port;
16122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
16222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!proxy)
16322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return;
16422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /*
16522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   * grab the proxy's host and port out of the URI we have for it. We want the
16622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   * underlying connect BIO to connect to this, not the target host and port, so
16722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   * we squirrel away the target host and port in the proxy BIO (as the proxy
16822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   * target) and swap out the connect BIO's target host and port so it'll
16922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   * connect to the proxy instead.
17022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   */
17122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
17222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  bio = BIO_new_proxy();
17322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_proxy_set_type(bio, scheme);
17422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_proxy_set_host(bio, host);
17522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_proxy_set_port(bio, atoi(port));
17622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  host = proxy_host;
17722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  port = proxy_port;
17822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_push(ssl, bio);
17922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
18022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
18122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic BIO *
18222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansmake_ssl_bio(SSL_CTX *ctx)
18322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
18422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO *con = NULL;
18522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO *ssl = NULL;
18622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
18722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!(con = BIO_new(BIO_s_connect())))
18822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("BIO_s_connect failed\n");
18922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (!(ssl = BIO_new_ssl(ctx, 1)))
19022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("BIO_new_ssl failed\n");
19122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  setup_proxy(ssl);
19222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_push(ssl, con);
19322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return ssl;
19422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
19522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
19622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/** helper function for 'malloc' */
19722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void *
19822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansxmalloc (size_t size)
19922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
20022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  void *ptr;
20122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
20222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 == size)
20322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("xmalloc: zero size\n");
20422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
20522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ptr = malloc(size);
20622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == ptr)
20722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("xmalloc: out of memory (allocating %zu bytes)\n", size);
20822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
20922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return ptr;
21022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
21122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
21222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
21322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/** helper function for 'free' */
21422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
21522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansxfree (void *ptr)
21622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
21722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == ptr)
21822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("xfree: NULL pointer given as argument\n");
21922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
22022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(ptr);
22122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
22222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
22322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
22422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansopenssl_time_callback (const SSL* ssl, int where, int ret)
22522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
22622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (where == SSL_CB_CONNECT_LOOP &&
22722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
22822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
22922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /*
23022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // XXX TODO: If we want to trust the remote system for time,
23122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // can we just read that time out of the remote system and if the
23222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // cert verifies, decide that the time is reasonable?
23322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // Such a process seems to indicate that a once valid cert would be
23422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // forever valid - we stopgap that by ensuring it isn't less than
23522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // the latest compiled_time and isn't above max_reasonable_time...
23622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // XXX TODO: Solve eternal question about the Chicken and the Egg...
23722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   */
23822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    uint32_t compiled_time = RECENT_COMPILE_DATE;
23922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
24022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    uint32_t server_time;
24122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb("V: freezing time for x509 verification\n");
24222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
24322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (compiled_time < ntohl(server_time)
24422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        &&
24522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        ntohl(server_time) < max_reasonable_time)
24622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
24722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: remote peer provided: %d, preferred over compile time: %d\n",
24822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            ntohl(server_time), compiled_time);
24922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
25022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
25122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                                 (time_t) ntohl(server_time) + 86400);
25222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    } else {
25322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("V: the remote server is a false ticker! server: %d compile: %d\n",
25422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans           ntohl(server_time), compiled_time);
25522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
25622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
25722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
25822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
25922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
26022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansget_certificate_keybits (EVP_PKEY *public_key)
26122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
26222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /*
26322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
26422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   */
26522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t key_bits;
26622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  switch (public_key->type)
26722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
26822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_RSA:
26922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_RSA\n");
27022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.rsa->n);
27122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
27222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_RSA2:
27322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_RSA2\n");
27422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.rsa->n);
27522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
27622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DSA:
27722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DSA\n");
27822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dsa->p);
27922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
28022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DSA1:
28122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DSA1\n");
28222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dsa->p);
28322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
28422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DSA2:
28522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DSA2\n");
28622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dsa->p);
28722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
28822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DSA3:
28922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DSA3\n");
29022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dsa->p);
29122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
29222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DSA4:
29322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DSA4\n");
29422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dsa->p);
29522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
29622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_DH:
29722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_DH\n");
29822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
29922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
30022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    case EVP_PKEY_EC:
30122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb("V: key type: EVP_PKEY_EC\n");
30222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = EVP_PKEY_bits(public_key);
30322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
30422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
30522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    default:
30622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      key_bits = 0;
30722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die ("unknown public key type\n");
30822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      break;
30922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
31022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb ("V: keybits: %d\n", key_bits);
31122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return key_bits;
31222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
31322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
31422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
31522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansdns_label_count(char *label, char *delim)
31622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
31722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *label_tmp;
31822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *saveptr;
31922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *saveptr_tmp;
32022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t label_count;
32122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
32222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  label_tmp = strdup(label);
32322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  label_count = 0;
32422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  saveptr = NULL;
32522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  saveptr_tmp = NULL;
32622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  saveptr = strtok_r(label_tmp, delim, &saveptr);
32722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL != saveptr)
32822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
32922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // Did we find our first label?
33022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (saveptr[0] != delim[0])
33122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
33222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      label_count++;
33322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: label found; total label count: %d\n", label_count);
33422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
33522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    do
33622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
33722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      // Find all subsequent labels
33822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      label_count++;
33922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      saveptr_tmp = strtok_r(NULL, delim, &saveptr);
34022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: label found; total label count: %d\n", label_count);
34122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    } while (NULL != saveptr_tmp);
34222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
34322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(label_tmp);
34422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return label_count;
34522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
34622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
34722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans// first we split strings on '.'
34822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans// then we call each split string a 'label'
34922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans// Do not allow '*' for the top level domain label; eg never allow *.*.com
35022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans// Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
35122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans// Do allow *.example.com
35222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
35322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_wildcard_match_rfc2595 (const char *orig_hostname,
35422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                      const char *orig_cert_wild_card)
35522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
35622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *hostname;
35722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *hostname_to_free;
35822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *cert_wild_card;
35922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *cert_wild_card_to_free;
36022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *expected_label;
36122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *wildcard_label;
36222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *delim;
36322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *wildchar;
36422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t ok;
36522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t wildcard_encountered;
36622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t label_count;
36722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
36822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // First we copy the original strings
36922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  hostname = strdup(orig_hostname);
37022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  cert_wild_card = strdup(orig_cert_wild_card);
37122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  hostname_to_free = hostname;
37222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  cert_wild_card_to_free = cert_wild_card;
37322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  delim = strdup(".");
37422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  wildchar = strdup("*");
37522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
37622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
37722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         hostname, cert_wild_card);
37822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
37922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // By default we have not processed any labels
38022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  label_count = dns_label_count(cert_wild_card, delim);
38122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
38222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // By default we have no match
38322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ok = 0;
38422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  wildcard_encountered = 0;
38522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // First - do we have labels? If not, we refuse to even try to match
38622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if ((NULL != strpbrk(cert_wild_card, delim)) &&
38722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      (NULL != strpbrk(hostname, delim)) &&
38822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
38922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
39022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (wildchar[0] == cert_wild_card[0])
39122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
39222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: Found wildcard in at start of provided certificate name\n");
39322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      do
39422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
39522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        // Skip over the bytes between the first char and until the next label
39622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        wildcard_label = strtok(cert_wild_card, delim);
39722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        expected_label = strtok(hostname, delim);
39822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (NULL != wildcard_label &&
39922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            NULL != expected_label &&
40022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            NULL != hostname &&
40122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            NULL != cert_wild_card)
40222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
40322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          // Now we only consider this wildcard valid if the rest of the
40422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          // hostnames match verbatim
40522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          verb ("V: Attempting match of '%s' against '%s'\n",
40622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                 expected_label, wildcard_label);
40722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          // This is the case where we have a label that begins with wildcard
40822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          // Furthermore, we only allow this for the first label
40922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          if (wildcard_label[0] == wildchar[0] &&
41022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              0 == wildcard_encountered && 0 == ok)
41122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          {
41222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
41322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            wildcard_encountered = 1;
41422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          } else {
41522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            verb ("V: Attempting match of '%s' against '%s'\n",
41622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                   hostname, cert_wild_card);
41722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            if (0 == strcasecmp (expected_label, wildcard_label) &&
41822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
41922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            {
42022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              ok = 1;
42122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              verb ("V: remaining labels match!\n");
42222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              break;
42322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            } else {
42422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              ok = 0;
42522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              verb ("V: remaining labels do not match!\n");
42622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              break;
42722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            }
42822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          }
42922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        } else {
43022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          // We hit this case when we have a mismatched number of labels
43122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          verb("V: NULL label; no wildcard here\n");
43222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          break;
43322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
43422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
43522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    } else {
43622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: Not a RFC 2595 wildcard\n");
43722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
43822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
43922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: Not a valid wildcard certificate\n");
44022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ok = 0;
44122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
44222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // Free our copies
44322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(wildchar);
44422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(delim);
44522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(hostname_to_free);
44622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  free(cert_wild_card_to_free);
44722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
44822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
44922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: wildcard match of %s against %s\n",
45022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          orig_hostname, orig_cert_wild_card);
45122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return (wildcard_encountered & ok);
45222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
45322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: wildcard match failure of %s against %s\n",
45422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          orig_hostname, orig_cert_wild_card);
45522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return 0;
45622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
45722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
45822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
45922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
46022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifndef USE_POLARSSL
46122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/**
46222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans This extracts the first commonName and checks it against hostname.
46322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans*/
46422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
46522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_cn (SSL *ssl, const char *hostname)
46622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
46722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int ok = 0;
46822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int ret;
46922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *cn_buf;
47022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509 *certificate;
47122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509_NAME *xname;
47222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
47322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // We cast this to cast away g++ complaining about the following:
47422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // error: invalid conversion from ‘void*’ to ‘char*’
47522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  cn_buf = (char *) xmalloc(TLSDATE_HOST_NAME_MAX + 1);
47622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
47722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  certificate = SSL_get_peer_certificate(ssl);
47822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == certificate)
47922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
48022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Unable to extract certificate\n");
48122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
48222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
48322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
48422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  xname = X509_get_subject_name(certificate);
48522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
48622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                                  cn_buf, TLSDATE_HOST_NAME_MAX);
48722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
48822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (-1 == ret || ret != (int) strlen(cn_buf))
48922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
49022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Unable to extract commonName\n");
49122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
49222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (strcasecmp(cn_buf, hostname))
49322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
49422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: commonName mismatch! Expected: %s - received: %s\n",
49522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          hostname, cn_buf);
49622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
49722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: commonName matched: %s\n", cn_buf);
49822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ok = 1;
49922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
50022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
50122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509_NAME_free(xname);
50222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509_free(certificate);
50322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  xfree(cn_buf);
50422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
50522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return ok;
50622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
50722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
50822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/**
50922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans Search for a hostname match in the SubjectAlternativeNames.
51022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans*/
51122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
51222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_san (SSL *ssl, const char *hostname)
51322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
51422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509 *cert;
51522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int extcount, ok = 0;
51622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* What an OpenSSL mess ... */
51722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == (cert = SSL_get_peer_certificate(ssl)))
51822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
51922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Getting certificate failed\n");
52022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
52122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
52222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if ((extcount = X509_get_ext_count(cert)) > 0)
52322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
52422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    int i;
52522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    for (i = 0; i < extcount; ++i)
52622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
52722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      const char *extstr;
52822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      X509_EXTENSION *ext;
52922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      ext = X509_get_ext(cert, i);
53022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
53122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
53222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      if (!strcmp(extstr, "subjectAltName"))
53322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
53422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
53522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        int j;
53622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        void *extvalstr;
53722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        const unsigned char *tmp;
53822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
53922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        STACK_OF(CONF_VALUE) *val;
54022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        CONF_VALUE *nval;
54122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#if OPENSSL_VERSION_NUMBER >= 0x10000000L
54222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        const
54322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
54422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        X509V3_EXT_METHOD *method;
54522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
54622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (!(method = X509V3_EXT_get(ext)))
54722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
54822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          break;
54922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
55022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
55122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        tmp = ext->value->data;
55222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (method->it)
55322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
55422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
55522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                                    ASN1_ITEM_ptr(method->it));
55622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        } else {
55722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          extvalstr = method->d2i(NULL, &tmp, ext->value->length);
55822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
55922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
56022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (!extvalstr)
56122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
56222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          break;
56322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
56422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
56522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (method->i2v)
56622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
56722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          val = method->i2v(method, extvalstr, NULL);
56822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
56922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          {
57022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            nval = sk_CONF_VALUE_value(val, j);
57122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            if ((!strcasecmp(nval->name, "DNS") &&
57222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                !strcasecmp(nval->value, hostname) ) ||
57322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                (!strcasecmp(nval->name, "iPAddress") &&
57422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                !strcasecmp(nval->value, hostname)))
57522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            {
57622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); /* We matched this; so it's safe to print */
57722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              ok = 1;
57822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              break;
57922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            }
58022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            // Attempt to match subjectAltName DNS names
58122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            if (!strcasecmp(nval->name, "DNS"))
58222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            {
58322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              ok = check_wildcard_match_rfc2595(hostname, nval->value);
58422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              if (ok)
58522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              {
58622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                break;
58722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans              }
58822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            }
58922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans            verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
59022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          }
59122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
59222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      } else {
59322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        verb ("V: found non subjectAltName extension\n");
59422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
59522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      if (ok)
59622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
59722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        break;
59822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
59922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
60022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
60122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: no X509_EXTENSION field(s) found\n");
60222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
60322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509_free(cert);
60422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return ok;
60522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
60622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
60722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
60822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_name (SSL *ssl, const char *hostname)
60922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
61022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t ret;
61122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ret = check_cn(ssl, hostname);
61222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ret += check_san(ssl, hostname);
61322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != ret && 0 < ret)
61422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
61522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: hostname verification passed\n");
61622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
61722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("hostname verification failed for host %s!\n", host);
61822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
61922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return ret;
62022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
62122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
62222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
62322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
62422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
62522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansverify_signature (ssl_context *ssl, const char *hostname)
62622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
62722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int ssl_verify_result;
62822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
62922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_verify_result = ssl_get_verify_result (ssl);
63022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ssl_verify_result & BADCERT_EXPIRED)
63122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
63222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certificate has expired\n");
63322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
63422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ssl_verify_result & BADCERT_REVOKED)
63522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
63622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certificate has been revoked\n");
63722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
63822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ssl_verify_result & BADCERT_CN_MISMATCH)
63922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
64022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("CN and subject AltName mismatch for certificate\n");
64122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
64222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ssl_verify_result & BADCERT_NOT_TRUSTED)
64322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
64422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certificate is self-signed or not signed by a trusted CA\n");
64522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
64622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
64722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 == ssl_verify_result)
64822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
64922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: verify success\n");
65022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
65122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  else
65222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
65322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certificate verification error: -0x%04x\n", -ssl_verify_result);
65422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
65522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return 0;
65622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
65722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else
65822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansuint32_t
65922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansverify_signature (SSL *ssl, const char *hostname)
66022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
66122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  long ssl_verify_result;
66222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509 *certificate;
66322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
66422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  certificate = SSL_get_peer_certificate(ssl);
66522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == certificate)
66622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
66722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Getting certificate failed\n");
66822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
66922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // In theory, we verify that the cert is valid
67022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_verify_result = SSL_get_verify_result(ssl);
67122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  switch (ssl_verify_result)
67222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
67322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
67422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
67522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certificate is self signed\n");
67622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  case X509_V_OK:
67722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: certificate verification passed\n");
67822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    break;
67922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  default:
68022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("certification verification error: %ld\n",
68122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         ssl_verify_result);
68222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
68322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans return 0;
68422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
68522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
68622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
68722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
68822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
68922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_key_length (ssl_context *ssl)
69022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
69122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t key_bits;
69222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  const x509_cert *certificate;
69322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  const rsa_context *public_key;
69422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char buf[1024];
69522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
69622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  certificate = ssl_get_peer_cert (ssl);
69722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == certificate)
69822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
69922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Getting certificate failed\n");
70022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
70122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
70222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  x509parse_dn_gets(buf, 1024, &certificate->subject);
70322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb ("V: Certificate for subject '%s'\n", buf);
70422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
70522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  public_key = &certificate->rsa;
70622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == public_key)
70722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
70822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("public key extraction failure\n");
70922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
71022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: public key is ready for inspection\n");
71122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
71222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  key_bits = mpi_msb (&public_key->N);
71322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (MIN_PUB_KEY_LEN >= key_bits)
71422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
71522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Unsafe public key size: %d bits\n", key_bits);
71622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
71722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: key length appears safe\n");
71822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
71922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
72022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else
72122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
72222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_key_length (SSL *ssl)
72322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
72422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t key_bits;
72522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  X509 *certificate;
72622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  EVP_PKEY *public_key;
72722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  certificate = SSL_get_peer_certificate (ssl);
72822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == certificate)
72922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
73022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Getting certificate failed\n");
73122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
73222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  public_key = X509_get_pubkey (certificate);
73322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == public_key)
73422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
73522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("public key extraction failure\n");
73622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
73722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: public key is ready for inspection\n");
73822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
73922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
74022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  key_bits = get_certificate_keybits (public_key);
74122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
74222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
74322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Unsafe public key size: %d bits\n", key_bits);
74422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
74522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     if (public_key->type == EVP_PKEY_EC)
74622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       if(key_bits >= MIN_ECC_PUB_KEY_LEN
74722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          && key_bits <= MAX_ECC_PUB_KEY_LEN)
74822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       {
74922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         verb ("V: ECC key length appears safe\n");
75022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       } else {
75122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         die ("Unsafe ECC key size: %d bits\n", key_bits);
75222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     } else {
75322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       verb ("V: key length appears safe\n");
75422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     }
75522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
75622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  EVP_PKEY_free (public_key);
75722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
75822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
75922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
76022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
76122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
76222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansinspect_key (ssl_context *ssl, const char *hostname)
76322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
76422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verify_signature (ssl, hostname);
76522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
76622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // ssl_get_verify_result() already checks for CN / subjectAltName match
76722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // and reports the mismatch as error. So check_name() is not called
76822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
76922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else
77022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
77122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansinspect_key (SSL *ssl, const char *hostname)
77222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
77322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
77422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verify_signature (ssl, hostname);
77522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    check_name (ssl, hostname);
77622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
77722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
77822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
77922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
78022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansvoid
78122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evanscheck_timestamp (uint32_t server_time)
78222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
78322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t compiled_time = RECENT_COMPILE_DATE;
78422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
78522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (compiled_time < server_time
78622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      &&
78722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      server_time < max_reasonable_time)
78822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
78922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb("V: remote peer provided: %d, preferred over compile time: %d\n",
79022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          server_time, compiled_time);
79122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
79222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("V: the remote server is a false ticker! server: %d compile: %d\n",
79322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         server_time, compiled_time);
79422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
79522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
79622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
79722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic int ssl_do_handshake_part(ssl_context *ssl)
79822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
79922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int ret = 0;
80022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
80122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Only do steps till ServerHello is received */
80222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  while (ssl->state != SSL_SERVER_HELLO)
80322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
80422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ret = ssl_handshake_step (ssl);
80522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (0 != ret)
80622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
80722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("SSL handshake failed\n");
80822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
80922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
81022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Do ServerHello so we can skim the timestamp */
81122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ret = ssl_handshake_step (ssl);
81222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != ret)
81322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
81422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("SSL handshake failed\n");
81522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
81622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
81722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return 0;
81822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
81922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
82022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/**
82122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * Run SSL handshake and store the resulting time value in the
82222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * 'time_map'.
82322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans *
82422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * @param time_map where to store the current time
82522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans */
82622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
82722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansrun_ssl (uint32_t *time_map, int time_is_an_illusion)
82822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
82922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  entropy_context entropy;
83022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ctr_drbg_context ctr_drbg;
83122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_context ssl;
83222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy_polarssl_ctx proxy_ctx;
83322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  x509_cert cacert;
83422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  struct stat statbuf;
83522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int ret = 0, server_fd = 0;
83622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  char *pers = "tlsdate-helper";
83722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
83822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  memset (&ssl, 0, sizeof(ssl_context));
83922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  memset (&cacert, 0, sizeof(x509_cert));
84022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
84122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb("V: Using PolarSSL for SSL\n");
84222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ca_racket)
84322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
84422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (-1 == stat (ca_cert_container, &statbuf))
84522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
84622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("Unable to stat CA certficate container %s\n", ca_cert_container);
84722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
84822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    else
84922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
85022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      switch (statbuf.st_mode & S_IFMT)
85122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
85222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      case S_IFREG:
85322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (0 > x509parse_crtfile(&cacert, ca_cert_container))
85422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          fprintf(stderr, "x509parse_crtfile failed\n");
85522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        break;
85622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      case S_IFDIR:
85722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (0 > x509parse_crtpath(&cacert, ca_cert_container))
85822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          fprintf(stderr, "x509parse_crtpath failed\n");
85922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        break;
86022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      default:
86122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        die("Unable to load CA certficate container %s\n", ca_cert_container);
86222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
86322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
86422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
86522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
86622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  entropy_init (&entropy);
86722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != ctr_drbg_init (&ctr_drbg, entropy_func, &entropy,
86822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                         (unsigned char *) pers, strlen(pers)))
86922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
87022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("Failed to initialize CTR_DRBG\n");
87122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
87222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
87322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != ssl_init (&ssl))
87422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
87522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("SSL initialization failed\n");
87622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
87722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_set_endpoint (&ssl, SSL_IS_CLIENT);
87822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_set_rng (&ssl, ctr_drbg_random, &ctr_drbg);
87922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_set_ca_chain (&ssl, &cacert, NULL, hostname_to_verify);
88022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ca_racket)
88122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
88222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      // You can do SSL_VERIFY_REQUIRED here, but then the check in
88322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      // inspect_key() never happens as the ssl_handshake() will fail.
88422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      ssl_set_authmode (&ssl, SSL_VERIFY_OPTIONAL);
88522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
88622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
88722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (proxy)
88822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
88922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    char *scheme;
89022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    char *proxy_host;
89122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    char *proxy_port;
89222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
89322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
89422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
89522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb("V: opening socket to proxy %s:%s\n", proxy_host, proxy_port);
89622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (0 != net_connect (&server_fd, proxy_host, atoi(proxy_port)))
89722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
89822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die ("SSL connection failed\n");
89922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
90022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
90122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    proxy_polarssl_init (&proxy_ctx);
90222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    proxy_polarssl_set_bio (&proxy_ctx, net_recv, &server_fd, net_send, &server_fd);
90322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    proxy_polarssl_set_host (&proxy_ctx, host);
90422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    proxy_polarssl_set_port (&proxy_ctx, atoi(port));
90522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    proxy_polarssl_set_scheme (&proxy_ctx, scheme);
90622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
90722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ssl_set_bio (&ssl, proxy_polarssl_recv, &proxy_ctx, proxy_polarssl_send, &proxy_ctx);
90822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
90922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb("V: Handle proxy connection\n");
91022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (0 == proxy_ctx.f_connect (&proxy_ctx))
91122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("Proxy connection failed\n");
91222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
91322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  else
91422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
91522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb("V: opening socket to %s:%s\n", host, port);
91622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (0 != net_connect (&server_fd, host, atoi(port)))
91722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
91822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die ("SSL connection failed\n");
91922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
92022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
92122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ssl_set_bio (&ssl, net_recv, &server_fd, net_send, &server_fd);
92222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
92322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
92422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb("V: starting handshake\n");
92522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != ssl_do_handshake_part (&ssl))
92622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("SSL handshake first part failed\n");
92722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
92822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t timestamp = ( (uint32_t) ssl.in_msg[6] << 24 )
92922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                     | ( (uint32_t) ssl.in_msg[7] << 16 )
93022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                     | ( (uint32_t) ssl.in_msg[8] <<  8 )
93122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                     | ( (uint32_t) ssl.in_msg[9]       );
93222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  check_timestamp (timestamp);
93322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
93422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb("V: continuing handshake\n");
93522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Continue with handshake */
93622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  while (0 != (ret = ssl_handshake (&ssl)))
93722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
93822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (POLARSSL_ERR_NET_WANT_READ  != ret &&
93922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        POLARSSL_ERR_NET_WANT_WRITE != ret)
94022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
94122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("SSL handshake failed\n");
94222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
94322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
94422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
94522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // Verify the peer certificate against the CA certs on the local system
94622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ca_racket) {
94722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    inspect_key (&ssl, hostname_to_verify);
94822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
94922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: Certificate verification skipped!\n");
95022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
95122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  check_key_length (&ssl);
95222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
95322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  memcpy (time_map, &timestamp, sizeof(uint32_t));
95422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy_polarssl_free (&proxy_ctx);
95522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_free (&ssl);
95622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  x509_free (&cacert);
95722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
95822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else /* USE_POLARSSL */
95922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/**
96022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * Run SSL handshake and store the resulting time value in the
96122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * 'time_map'.
96222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans *
96322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans * @param time_map where to store the current time
96422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans */
96522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansstatic void
96622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansrun_ssl (uint32_t *time_map, int time_is_an_illusion)
96722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
96822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO *s_bio;
96922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_CTX *ctx;
97022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL *ssl;
97122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  struct stat statbuf;
97222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
97322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_load_error_strings();
97422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_library_init();
97522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
97622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ctx = NULL;
97722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 == strcmp("sslv23", protocol))
97822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
97922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: using SSLv23_client_method()\n");
98022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ctx = SSL_CTX_new(SSLv23_client_method());
98122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else if (0 == strcmp("sslv3", protocol))
98222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
98322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: using SSLv3_client_method()\n");
98422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ctx = SSL_CTX_new(SSLv3_client_method());
98522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else if (0 == strcmp("tlsv1", protocol))
98622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
98722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: using TLSv1_client_method()\n");
98822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    ctx = SSL_CTX_new(TLSv1_client_method());
98922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else
99022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("Unsupported protocol `%s'\n", protocol);
99122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
99222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ctx == NULL)
99322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die("OpenSSL failed to support protocol `%s'\n", protocol);
99422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
99522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb("V: Using OpenSSL for SSL\n");
99622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ca_racket)
99722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
99822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (-1 == stat(ca_cert_container, &statbuf))
99922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
100022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("Unable to stat CA certficate container %s\n", ca_cert_container);
100122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    } else
100222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
100322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      switch (statbuf.st_mode & S_IFMT)
100422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
100522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      case S_IFREG:
100622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
100722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
100822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        break;
100922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      case S_IFDIR:
101022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
101122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
101222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        break;
101322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      default:
101422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
101522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        {
101622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
101722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans          die("Unable to load CA certficate container %s\n", ca_cert_container);
101822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        }
101922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
102022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
102122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
102222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
102322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == (s_bio = make_ssl_bio(ctx)))
102422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("SSL BIO setup failed\n");
102522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  BIO_get_ssl(s_bio, &ssl);
102622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == ssl)
102722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("SSL setup failed\n");
102822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
102922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (time_is_an_illusion)
103022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
103122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    SSL_set_info_callback(ssl, openssl_time_callback);
103222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
103322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
103422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
103522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb("V: opening socket to %s:%s\n", host, port);
103622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
103722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       (1 != BIO_set_conn_port(s_bio, port)) )
103822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Failed to initialize connection to `%s:%s'\n", host, port);
103922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
104022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
104122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
104222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
104322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // This should run in seccomp
104422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // eg:     prctl(PR_SET_SECCOMP, 1);
104522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (1 != BIO_do_connect(s_bio)) /* XXX TODO: BIO_should_retry() later? */
104622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("SSL connection failed\n");
104722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (1 != BIO_do_handshake(s_bio))
104822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("SSL handshake failed\n");
104922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
105022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // Verify the peer certificate against the CA certs on the local system
105122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ca_racket) {
105222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    inspect_key (ssl, hostname_to_verify);
105322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
105422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: Certificate verification skipped!\n");
105522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
105622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  check_key_length(ssl);
105722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // from /usr/include/openssl/ssl3.h
105822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  //  ssl->s3->server_random is an unsigned char of 32 bits
105922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
106022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_free(ssl);
106122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  SSL_CTX_free(ctx);
106222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
106322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif /* USE_POLARSSL */
106422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/** drop root rights and become 'nobody' */
106522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
106622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansint
106722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evansmain(int argc, char **argv)
106822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans{
106922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t *time_map;
107022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  struct tlsdate_time start_time, end_time, warp_time;
107122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int status;
107222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  pid_t ssl_child;
107322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  long long rt_time_ms;
107422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  uint32_t server_time_s;
107522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int setclock;
107622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int showtime;
107722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int timewarp;
107822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  int leap;
107922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
108022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (argc != 12)
108122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return 1;
108222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  host = argv[1];
108322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  hostname_to_verify = argv[1];
108422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  port = argv[2];
108522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  protocol = argv[3];
108622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ca_cert_container = argv[6];
108722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ca_racket = (0 != strcmp ("unchecked", argv[4]));
108822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verbose = (0 != strcmp ("quiet", argv[5]));
108922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  setclock = (0 == strcmp ("setclock", argv[7]));
109022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  showtime = (0 == strcmp ("showtime", argv[8]));
109122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  timewarp = (0 == strcmp ("timewarp", argv[9]));
109222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  leap = (0 == strcmp ("leapaway", argv[10]));
109322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
109422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
109522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (timewarp)
109622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
109722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
109822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
109922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         (unsigned long) CLOCK_SEC(&warp_time),
110022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans         (unsigned long) CLOCK_USEC(&warp_time));
110122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
110222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (1 == setclock) {
110322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
110422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    } else {
110522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: we'll do the time warp another time - we're not setting clock\n");
110622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
110722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
110822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
110922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* We are not going to set the clock, thus no need to stay root */
111022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 == setclock && 0 == timewarp)
111122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
1112aab9382297008c1d1b7cef361159a44885d52af0Gilad Arnold    drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
111322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
111422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans/*
111522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans	XXX: KILL ME
111622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // We cast the mmap value to remove this error when compiling with g++:
111722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // src/tlsdate-helper.c: In function ‘int main(int, char**)’:
111822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  // src/tlsdate-helper.c:822:41: error: invalid conversion from ‘void*’ to ‘uint32_t
111922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  time_map = (uint32_t *) mmap (NULL, sizeof (uint32_t),
112022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       PROT_READ | PROT_WRITE,
112122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
112222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans   if (MAP_FAILED == time_map)
112322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
112422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    fprintf (stderr, "mmap failed: %s\n",
112522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans             strerror (errno));
112622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    return 1;
112722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
112822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans*/
112922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Get the current time from the system clock. */
113022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != clock_get_real_time(&start_time))
113122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
113222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Failed to read current time of day: %s\n", strerror (errno));
113322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
113422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
113522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb ("V: time is currently %lu.%06lu\n",
113622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       (unsigned long) CLOCK_SEC(&start_time),
113722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       (unsigned long) CLOCK_NSEC(&start_time));
113822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
113922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
114022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
114122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
114222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (timewarp)
114322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    {
114422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: Attempting to warp local clock into the future\n");
114522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      if (0 != clock_set_real_time(&warp_time))
114622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
114722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
114822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        strerror (errno),
114922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        (unsigned long) CLOCK_SEC(&warp_time),
115022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        (unsigned long) CLOCK_SEC(&warp_time));
115122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
115222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      if (0 != clock_get_real_time(&start_time))
115322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      {
115422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans        die ("Failed to read current time of day: %s\n", strerror (errno));
115522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      }
115622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: time is currently %lu.%06lu\n",
115722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans           (unsigned long) CLOCK_SEC(&start_time),
115822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans           (unsigned long) CLOCK_NSEC(&start_time));
115922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      verb ("V: It's just a step to the left...\n");
116022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    }
116122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  } else {
116222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: time is greater than RECENT_COMPILE_DATE\n");
116322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
116422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
116522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* initialize to bogus value, just to be on the safe side */
116622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  *time_map = 0;
116722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
116822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* Run SSL interaction in separate process (and not as 'root') */
116922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  ssl_child = fork ();
117022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (-1 == ssl_child)
117122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("fork failed: %s\n", strerror (errno));
117222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 == ssl_child)
117322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
1174aab9382297008c1d1b7cef361159a44885d52af0Gilad Arnold    drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
117522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    run_ssl (time_map, leap);
117622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    /*
117722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    XXX: should be a pipe close
117822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    (void) munmap (time_map, sizeof (uint32_t));
117922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    */
118022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    _exit (0);
118122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
118222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (ssl_child != waitpid (ssl_child, &status, 0))
118322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("waitpid failed: %s\n", strerror (errno));
118422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
118522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("child process failed in SSL handshake\n");
118622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
118722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (0 != clock_get_real_time(&end_time))
118822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    die ("Failed to read current time of day: %s\n", strerror (errno));
118922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
119022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* calculate RTT */
119122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  rt_time_ms = (CLOCK_SEC(&end_time) - CLOCK_SEC(&start_time)) * 1000 + (CLOCK_USEC(&end_time) - CLOCK_USEC(&start_time)) / 1000;
119222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (rt_time_ms < 0)
119322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    rt_time_ms = 0; /* non-linear time... */
119422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#ifdef USE_POLARSSL
119522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  server_time_s = *time_map;
119622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#else
119722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  server_time_s = ntohl (*time_map);
119822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans#endif
119922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /*
120022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  XXX: should be a pipe close
120122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  munmap (time_map, sizeof (uint32_t));
120222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  */
120322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
120422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  (unsigned int) server_time_s,
120522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  CLOCK_SEC(&start_time) - server_time_s,
120622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  rt_time_ms);
120722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
120822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* warning if the handshake took too long */
120922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (rt_time_ms > TLS_RTT_THRESHOLD) {
121022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
121122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      "server or run it again\n", TLS_RTT_THRESHOLD);
121222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
121322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
121422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (showtime)
121522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
121622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     struct tm  ltm;
121722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     time_t tim = server_time_s;
121822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     char       buf[256];
121922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
122022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     localtime_r(&tim, &ltm);
122122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
122222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     {
122322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans       die ("strftime returned 0\n");
122422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     }
122522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     fprintf(stdout, "%s\n", buf);
122622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
122722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
122822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  /* finally, actually set the time */
122922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  if (setclock)
123022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  {
123122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    struct tlsdate_time server_time;
123222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
123322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    clock_init_time(&server_time,  server_time_s + (rt_time_ms / 2 / 1000),
123422ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans                   (rt_time_ms / 2) % 1000);
123522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans
123622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // We should never receive a time that is before the time we were last
123722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // compiled; we subscribe to the linear theory of time for this program
123822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    // and this program alone!
123922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
124022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die("remote server is a false ticker from the future!\n");
124122ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
124222ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans      die ("remote server is a false ticker!\n");
124322ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    if (0 != clock_set_real_time(&server_time))
1244196fe4b14121ac68e41f64f8b53ab9d597b3cd47Fabian Keil      die ("setting time failed: %s (Difference from server is about %d s)\n",
124522ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     strerror (errno),
124622ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans     CLOCK_SEC(&start_time) - server_time_s);
124722ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans    verb ("V: setting time succeeded\n");
124822ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  }
124922ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans  return 0;
125022ede40ad7f5b4d994ccbae7ef07b36bdf3fd497Noah Evans}
1251