Home | History | Annotate | Download | only in src
      1 /* Copyright (c) 2012, Jacob Appelbaum.
      2  * Copyright (c) 2012, The Tor Project, Inc.
      3  * Copyright (c) 2012, Christian Grothoff. */
      4 /* See LICENSE for licensing information */
      5 /*
      6                     This file contains the license for tlsdate,
      7         a free software project to set your system clock securely.
      8 
      9         It also lists the licenses for other components used by tlsdate.
     10 
     11       For more information about tlsdate, see https://github.com/ioerror/tlsdate
     12 
     13              If you got this file as a part of a larger bundle,
     14         there may be other license terms that you should be aware of.
     15 
     16 ===============================================================================
     17 tlsdate is distributed under this license:
     18 
     19 Copyright (c) 2011-2012, Jacob Appelbaum <jacob (at) appelbaum.net>
     20 Copyright (c) 2011-2012, The Tor Project, Inc.
     21 
     22 Redistribution and use in source and binary forms, with or without
     23 modification, are permitted provided that the following conditions are
     24 met:
     25 
     26     * Redistributions of source code must retain the above copyright
     27 notice, this list of conditions and the following disclaimer.
     28 
     29     * Redistributions in binary form must reproduce the above
     30 copyright notice, this list of conditions and the following disclaimer
     31 in the documentation and/or other materials provided with the
     32 distribution.
     33 
     34     * Neither the names of the copyright owners nor the names of its
     35 contributors may be used to endorse or promote products derived from
     36 this software without specific prior written permission.
     37 
     38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     39 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     40 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     41 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     42 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     43 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     44 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     45 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     46 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     47 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     48 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     49 ===============================================================================
     50 If you got tlsdate as a static binary with OpenSSL included, then you should
     51 know:
     52 
     53  "This product includes software developed by the OpenSSL Project for use in
     54   the OpenSSL Toolkit (http://www.openssl.org/)"
     55 
     56 ===============================================================================
     57 */
     58 
     59 /**
     60  * \file tlsdate-helper.c
     61  * \brief Helper program that does the actual work of setting the system clock.
     62  **/
     63 
     64 /*
     65  * tlsdate is a tool for setting the system clock by hand or by communication
     66  * with the network. It does not set the RTC. It is designed to be as secure as
     67  * TLS (RFC 2246) but of course the security of TLS is often reduced to
     68  * whichever CA racket you believe is trustworthy. By default, tlsdate trusts
     69  * your local CA root store - so any of these companies could assist in a MITM
     70  * attack against you and you'd be screwed.
     71 
     72  * This tool is designed to be run by hand or as a system daemon. It must be
     73  * run as root or otherwise have the proper caps; it will not be able to set
     74  * the system time without running as root or another privileged user.
     75  */
     76 
     77 #include "config.h"
     78 #include "src/tlsdate-helper-plan9.h"
     79 
     80 #ifndef USE_POLARSSL
     81 #include "src/proxy-bio-plan9.h"
     82 #else
     83 #include "src/proxy-polarssl.h"
     84 #endif
     85 
     86 #include "src/compat/clock-plan9.h"
     87 
     88 #ifndef MAP_ANONYMOUS
     89 #define MAP_ANONYMOUS MAP_ANON
     90 #endif
     91 
     92 #ifdef USE_POLARSSL
     93 #include "polarssl/entropy.h"
     94 #include "polarssl/ctr_drbg.h"
     95 #include "polarssl/ssl.h"
     96 #endif
     97 
     98 static void
     99 validate_proxy_scheme(const char *scheme)
    100 {
    101   if (!strcmp(scheme, "http"))
    102     return;
    103   if (!strcmp(scheme, "socks4"))
    104     return;
    105   if (!strcmp(scheme, "socks5"))
    106     return;
    107   die("invalid proxy scheme\n");
    108 }
    109 
    110 static void
    111 validate_proxy_host(const char *host)
    112 {
    113   const char *kValid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    114                        "abcdefghijklmnopqrstuvwxyz"
    115                        "0123456789"
    116                        ".-";
    117   if (strspn(host, kValid) != strlen(host))
    118     die("invalid char in host\n");
    119 }
    120 
    121 static void
    122 validate_proxy_port(const char *port)
    123 {
    124   while (*port)
    125     if (!isdigit(*port++))
    126       die("invalid char in port\n");
    127 }
    128 
    129 static void
    130 parse_proxy_uri(char *proxy, char **scheme, char **host, char **port)
    131 {
    132   /* Expecting a URI, so: <scheme> '://' <host> ':' <port> */
    133   *scheme = proxy;
    134   proxy = strstr(proxy, "://");
    135   if (!proxy)
    136     die("malformed proxy URI\n");
    137   *proxy = '\0'; /* terminate scheme string */
    138   proxy += strlen("://");
    139 
    140   *host = proxy;
    141   proxy = strchr(proxy, ':');
    142   if (!proxy)
    143     die("malformed proxy URI\n");
    144   *proxy++ = '\0';
    145 
    146   *port = proxy;
    147 
    148   validate_proxy_scheme(*scheme);
    149   validate_proxy_host(*host);
    150   validate_proxy_port(*port);
    151 }
    152 
    153 #ifndef USE_POLARSSL
    154 static void
    155 setup_proxy(BIO *ssl)
    156 {
    157   BIO *bio;
    158   char *scheme;
    159   char *proxy_host;
    160   char *proxy_port;
    161 
    162   if (!proxy)
    163     return;
    164   /*
    165    * grab the proxy's host and port out of the URI we have for it. We want the
    166    * underlying connect BIO to connect to this, not the target host and port, so
    167    * we squirrel away the target host and port in the proxy BIO (as the proxy
    168    * target) and swap out the connect BIO's target host and port so it'll
    169    * connect to the proxy instead.
    170    */
    171   parse_proxy_uri(proxy, &scheme, &proxy_host, &proxy_port);
    172   bio = BIO_new_proxy();
    173   BIO_proxy_set_type(bio, scheme);
    174   BIO_proxy_set_host(bio, host);
    175   BIO_proxy_set_port(bio, atoi(port));
    176   host = proxy_host;
    177   port = proxy_port;
    178   BIO_push(ssl, bio);
    179 }
    180 
    181 static BIO *
    182 make_ssl_bio(SSL_CTX *ctx)
    183 {
    184   BIO *con = NULL;
    185   BIO *ssl = NULL;
    186 
    187   if (!(con = BIO_new(BIO_s_connect())))
    188     die("BIO_s_connect failed\n");
    189   if (!(ssl = BIO_new_ssl(ctx, 1)))
    190     die("BIO_new_ssl failed\n");
    191   setup_proxy(ssl);
    192   BIO_push(ssl, con);
    193   return ssl;
    194 }
    195 
    196 /** helper function for 'malloc' */
    197 static void *
    198 xmalloc (size_t size)
    199 {
    200   void *ptr;
    201 
    202   if (0 == size)
    203     die("xmalloc: zero size\n");
    204 
    205   ptr = malloc(size);
    206   if (NULL == ptr)
    207     die("xmalloc: out of memory (allocating %zu bytes)\n", size);
    208 
    209   return ptr;
    210 }
    211 
    212 
    213 /** helper function for 'free' */
    214 static void
    215 xfree (void *ptr)
    216 {
    217   if (NULL == ptr)
    218     die("xfree: NULL pointer given as argument\n");
    219 
    220   free(ptr);
    221 }
    222 
    223 void
    224 openssl_time_callback (const SSL* ssl, int where, int ret)
    225 {
    226   if (where == SSL_CB_CONNECT_LOOP &&
    227       (ssl->state == SSL3_ST_CR_SRVR_HELLO_A || ssl->state == SSL3_ST_CR_SRVR_HELLO_B))
    228   {
    229   /*
    230     // XXX TODO: If we want to trust the remote system for time,
    231     // can we just read that time out of the remote system and if the
    232     // cert verifies, decide that the time is reasonable?
    233     // Such a process seems to indicate that a once valid cert would be
    234     // forever valid - we stopgap that by ensuring it isn't less than
    235     // the latest compiled_time and isn't above max_reasonable_time...
    236     // XXX TODO: Solve eternal question about the Chicken and the Egg...
    237    */
    238     uint32_t compiled_time = RECENT_COMPILE_DATE;
    239     uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
    240     uint32_t server_time;
    241     verb("V: freezing time for x509 verification\n");
    242     memcpy(&server_time, ssl->s3->server_random, sizeof(uint32_t));
    243     if (compiled_time < ntohl(server_time)
    244         &&
    245         ntohl(server_time) < max_reasonable_time)
    246     {
    247       verb("V: remote peer provided: %d, preferred over compile time: %d\n",
    248             ntohl(server_time), compiled_time);
    249       verb("V: freezing time with X509_VERIFY_PARAM_set_time\n");
    250       X509_VERIFY_PARAM_set_time(ssl->ctx->cert_store->param,
    251                                  (time_t) ntohl(server_time) + 86400);
    252     } else {
    253       die("V: the remote server is a false ticker! server: %d compile: %d\n",
    254            ntohl(server_time), compiled_time);
    255     }
    256   }
    257 }
    258 
    259 uint32_t
    260 get_certificate_keybits (EVP_PKEY *public_key)
    261 {
    262   /*
    263     In theory, we could use check_bitlen_dsa() and check_bitlen_rsa()
    264    */
    265   uint32_t key_bits;
    266   switch (public_key->type)
    267   {
    268     case EVP_PKEY_RSA:
    269       verb("V: key type: EVP_PKEY_RSA\n");
    270       key_bits = BN_num_bits(public_key->pkey.rsa->n);
    271       break;
    272     case EVP_PKEY_RSA2:
    273       verb("V: key type: EVP_PKEY_RSA2\n");
    274       key_bits = BN_num_bits(public_key->pkey.rsa->n);
    275       break;
    276     case EVP_PKEY_DSA:
    277       verb("V: key type: EVP_PKEY_DSA\n");
    278       key_bits = BN_num_bits(public_key->pkey.dsa->p);
    279       break;
    280     case EVP_PKEY_DSA1:
    281       verb("V: key type: EVP_PKEY_DSA1\n");
    282       key_bits = BN_num_bits(public_key->pkey.dsa->p);
    283       break;
    284     case EVP_PKEY_DSA2:
    285       verb("V: key type: EVP_PKEY_DSA2\n");
    286       key_bits = BN_num_bits(public_key->pkey.dsa->p);
    287       break;
    288     case EVP_PKEY_DSA3:
    289       verb("V: key type: EVP_PKEY_DSA3\n");
    290       key_bits = BN_num_bits(public_key->pkey.dsa->p);
    291       break;
    292     case EVP_PKEY_DSA4:
    293       verb("V: key type: EVP_PKEY_DSA4\n");
    294       key_bits = BN_num_bits(public_key->pkey.dsa->p);
    295       break;
    296     case EVP_PKEY_DH:
    297       verb("V: key type: EVP_PKEY_DH\n");
    298       key_bits = BN_num_bits(public_key->pkey.dh->pub_key);
    299       break;
    300     case EVP_PKEY_EC:
    301       verb("V: key type: EVP_PKEY_EC\n");
    302       key_bits = EVP_PKEY_bits(public_key);
    303       break;
    304     // Should we also care about EVP_PKEY_HMAC and EVP_PKEY_CMAC?
    305     default:
    306       key_bits = 0;
    307       die ("unknown public key type\n");
    308       break;
    309   }
    310   verb ("V: keybits: %d\n", key_bits);
    311   return key_bits;
    312 }
    313 
    314 uint32_t
    315 dns_label_count(char *label, char *delim)
    316 {
    317   char *label_tmp;
    318   char *saveptr;
    319   char *saveptr_tmp;
    320   uint32_t label_count;
    321 
    322   label_tmp = strdup(label);
    323   label_count = 0;
    324   saveptr = NULL;
    325   saveptr_tmp = NULL;
    326   saveptr = strtok_r(label_tmp, delim, &saveptr);
    327   if (NULL != saveptr)
    328   {
    329     // Did we find our first label?
    330     if (saveptr[0] != delim[0])
    331     {
    332       label_count++;
    333       verb ("V: label found; total label count: %d\n", label_count);
    334     }
    335     do
    336     {
    337       // Find all subsequent labels
    338       label_count++;
    339       saveptr_tmp = strtok_r(NULL, delim, &saveptr);
    340       verb ("V: label found; total label count: %d\n", label_count);
    341     } while (NULL != saveptr_tmp);
    342   }
    343   free(label_tmp);
    344   return label_count;
    345 }
    346 
    347 // first we split strings on '.'
    348 // then we call each split string a 'label'
    349 // Do not allow '*' for the top level domain label; eg never allow *.*.com
    350 // Do not allow '*' for subsequent subdomains; eg never allow *.foo.example.com
    351 // Do allow *.example.com
    352 uint32_t
    353 check_wildcard_match_rfc2595 (const char *orig_hostname,
    354                       const char *orig_cert_wild_card)
    355 {
    356   char *hostname;
    357   char *hostname_to_free;
    358   char *cert_wild_card;
    359   char *cert_wild_card_to_free;
    360   char *expected_label;
    361   char *wildcard_label;
    362   char *delim;
    363   char *wildchar;
    364   uint32_t ok;
    365   uint32_t wildcard_encountered;
    366   uint32_t label_count;
    367 
    368   // First we copy the original strings
    369   hostname = strdup(orig_hostname);
    370   cert_wild_card = strdup(orig_cert_wild_card);
    371   hostname_to_free = hostname;
    372   cert_wild_card_to_free = cert_wild_card;
    373   delim = strdup(".");
    374   wildchar = strdup("*");
    375 
    376   verb ("V: Inspecting '%s' for possible wildcard match against '%s'\n",
    377          hostname, cert_wild_card);
    378 
    379   // By default we have not processed any labels
    380   label_count = dns_label_count(cert_wild_card, delim);
    381 
    382   // By default we have no match
    383   ok = 0;
    384   wildcard_encountered = 0;
    385   // First - do we have labels? If not, we refuse to even try to match
    386   if ((NULL != strpbrk(cert_wild_card, delim)) &&
    387       (NULL != strpbrk(hostname, delim)) &&
    388       (label_count <= ((uint32_t)RFC2595_MIN_LABEL_COUNT)))
    389   {
    390     if (wildchar[0] == cert_wild_card[0])
    391     {
    392       verb ("V: Found wildcard in at start of provided certificate name\n");
    393       do
    394       {
    395         // Skip over the bytes between the first char and until the next label
    396         wildcard_label = strtok(cert_wild_card, delim);
    397         expected_label = strtok(hostname, delim);
    398         if (NULL != wildcard_label &&
    399             NULL != expected_label &&
    400             NULL != hostname &&
    401             NULL != cert_wild_card)
    402         {
    403           // Now we only consider this wildcard valid if the rest of the
    404           // hostnames match verbatim
    405           verb ("V: Attempting match of '%s' against '%s'\n",
    406                  expected_label, wildcard_label);
    407           // This is the case where we have a label that begins with wildcard
    408           // Furthermore, we only allow this for the first label
    409           if (wildcard_label[0] == wildchar[0] &&
    410               0 == wildcard_encountered && 0 == ok)
    411           {
    412             verb ("V: Forced match of '%s' against '%s'\n", expected_label, wildcard_label);
    413             wildcard_encountered = 1;
    414           } else {
    415             verb ("V: Attempting match of '%s' against '%s'\n",
    416                    hostname, cert_wild_card);
    417             if (0 == strcasecmp (expected_label, wildcard_label) &&
    418                 label_count >= ((uint32_t)RFC2595_MIN_LABEL_COUNT))
    419             {
    420               ok = 1;
    421               verb ("V: remaining labels match!\n");
    422               break;
    423             } else {
    424               ok = 0;
    425               verb ("V: remaining labels do not match!\n");
    426               break;
    427             }
    428           }
    429         } else {
    430           // We hit this case when we have a mismatched number of labels
    431           verb("V: NULL label; no wildcard here\n");
    432           break;
    433         }
    434       } while (0 != wildcard_encountered && label_count <= RFC2595_MIN_LABEL_COUNT);
    435     } else {
    436       verb ("V: Not a RFC 2595 wildcard\n");
    437     }
    438   } else {
    439     verb ("V: Not a valid wildcard certificate\n");
    440     ok = 0;
    441   }
    442   // Free our copies
    443   free(wildchar);
    444   free(delim);
    445   free(hostname_to_free);
    446   free(cert_wild_card_to_free);
    447   if (wildcard_encountered & ok && label_count >= RFC2595_MIN_LABEL_COUNT)
    448   {
    449     verb ("V: wildcard match of %s against %s\n",
    450           orig_hostname, orig_cert_wild_card);
    451     return (wildcard_encountered & ok);
    452   } else {
    453     verb ("V: wildcard match failure of %s against %s\n",
    454           orig_hostname, orig_cert_wild_card);
    455     return 0;
    456   }
    457 }
    458 #endif
    459 
    460 #ifndef USE_POLARSSL
    461 /**
    462  This extracts the first commonName and checks it against hostname.
    463 */
    464 uint32_t
    465 check_cn (SSL *ssl, const char *hostname)
    466 {
    467   int ok = 0;
    468   int ret;
    469   char *cn_buf;
    470   X509 *certificate;
    471   X509_NAME *xname;
    472 
    473   // We cast this to cast away g++ complaining about the following:
    474   // error: invalid conversion from void* to char*
    475   cn_buf = (char *) xmalloc(TLSDATE_HOST_NAME_MAX + 1);
    476 
    477   certificate = SSL_get_peer_certificate(ssl);
    478   if (NULL == certificate)
    479   {
    480     die ("Unable to extract certificate\n");
    481   }
    482 
    483   memset(cn_buf, '\0', (TLSDATE_HOST_NAME_MAX + 1));
    484   xname = X509_get_subject_name(certificate);
    485   ret = X509_NAME_get_text_by_NID(xname, NID_commonName,
    486                                   cn_buf, TLSDATE_HOST_NAME_MAX);
    487 
    488   if (-1 == ret || ret != (int) strlen(cn_buf))
    489   {
    490     die ("Unable to extract commonName\n");
    491   }
    492   if (strcasecmp(cn_buf, hostname))
    493   {
    494     verb ("V: commonName mismatch! Expected: %s - received: %s\n",
    495           hostname, cn_buf);
    496   } else {
    497     verb ("V: commonName matched: %s\n", cn_buf);
    498     ok = 1;
    499   }
    500 
    501   X509_NAME_free(xname);
    502   X509_free(certificate);
    503   xfree(cn_buf);
    504 
    505   return ok;
    506 }
    507 
    508 /**
    509  Search for a hostname match in the SubjectAlternativeNames.
    510 */
    511 uint32_t
    512 check_san (SSL *ssl, const char *hostname)
    513 {
    514   X509 *cert;
    515   int extcount, ok = 0;
    516   /* What an OpenSSL mess ... */
    517   if (NULL == (cert = SSL_get_peer_certificate(ssl)))
    518   {
    519     die ("Getting certificate failed\n");
    520   }
    521 
    522   if ((extcount = X509_get_ext_count(cert)) > 0)
    523   {
    524     int i;
    525     for (i = 0; i < extcount; ++i)
    526     {
    527       const char *extstr;
    528       X509_EXTENSION *ext;
    529       ext = X509_get_ext(cert, i);
    530       extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
    531 
    532       if (!strcmp(extstr, "subjectAltName"))
    533       {
    534 
    535         int j;
    536         void *extvalstr;
    537         const unsigned char *tmp;
    538 
    539         STACK_OF(CONF_VALUE) *val;
    540         CONF_VALUE *nval;
    541 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
    542         const
    543 #endif
    544         X509V3_EXT_METHOD *method;
    545 
    546         if (!(method = X509V3_EXT_get(ext)))
    547         {
    548           break;
    549         }
    550 
    551         tmp = ext->value->data;
    552         if (method->it)
    553         {
    554           extvalstr = ASN1_item_d2i(NULL, &tmp, ext->value->length,
    555                                     ASN1_ITEM_ptr(method->it));
    556         } else {
    557           extvalstr = method->d2i(NULL, &tmp, ext->value->length);
    558         }
    559 
    560         if (!extvalstr)
    561         {
    562           break;
    563         }
    564 
    565         if (method->i2v)
    566         {
    567           val = method->i2v(method, extvalstr, NULL);
    568           for (j = 0; j < sk_CONF_VALUE_num(val); ++j)
    569           {
    570             nval = sk_CONF_VALUE_value(val, j);
    571             if ((!strcasecmp(nval->name, "DNS") &&
    572                 !strcasecmp(nval->value, hostname) ) ||
    573                 (!strcasecmp(nval->name, "iPAddress") &&
    574                 !strcasecmp(nval->value, hostname)))
    575             {
    576               verb ("V: subjectAltName matched: %s, type: %s\n", nval->value, nval->name); /* We matched this; so it's safe to print */
    577               ok = 1;
    578               break;
    579             }
    580             // Attempt to match subjectAltName DNS names
    581             if (!strcasecmp(nval->name, "DNS"))
    582             {
    583               ok = check_wildcard_match_rfc2595(hostname, nval->value);
    584               if (ok)
    585               {
    586                 break;
    587               }
    588             }
    589             verb ("V: subjectAltName found but not matched: %s, type: %s\n", nval->value, nval->name); // XXX: Clean this string!
    590           }
    591         }
    592       } else {
    593         verb ("V: found non subjectAltName extension\n");
    594       }
    595       if (ok)
    596       {
    597         break;
    598       }
    599     }
    600   } else {
    601     verb ("V: no X509_EXTENSION field(s) found\n");
    602   }
    603   X509_free(cert);
    604   return ok;
    605 }
    606 
    607 uint32_t
    608 check_name (SSL *ssl, const char *hostname)
    609 {
    610   uint32_t ret;
    611   ret = check_cn(ssl, hostname);
    612   ret += check_san(ssl, hostname);
    613   if (0 != ret && 0 < ret)
    614   {
    615     verb ("V: hostname verification passed\n");
    616   } else {
    617     die ("hostname verification failed for host %s!\n", host);
    618   }
    619   return ret;
    620 }
    621 #endif
    622 
    623 #ifdef USE_POLARSSL
    624 uint32_t
    625 verify_signature (ssl_context *ssl, const char *hostname)
    626 {
    627   int ssl_verify_result;
    628 
    629   ssl_verify_result = ssl_get_verify_result (ssl);
    630   if (ssl_verify_result & BADCERT_EXPIRED)
    631   {
    632     die ("certificate has expired\n");
    633   }
    634   if (ssl_verify_result & BADCERT_REVOKED)
    635   {
    636     die ("certificate has been revoked\n");
    637   }
    638   if (ssl_verify_result & BADCERT_CN_MISMATCH)
    639   {
    640     die ("CN and subject AltName mismatch for certificate\n");
    641   }
    642   if (ssl_verify_result & BADCERT_NOT_TRUSTED)
    643   {
    644     die ("certificate is self-signed or not signed by a trusted CA\n");
    645   }
    646 
    647   if (0 == ssl_verify_result)
    648   {
    649     verb ("V: verify success\n");
    650   }
    651   else
    652   {
    653     die ("certificate verification error: -0x%04x\n", -ssl_verify_result);
    654   }
    655   return 0;
    656 }
    657 #else
    658 uint32_t
    659 verify_signature (SSL *ssl, const char *hostname)
    660 {
    661   long ssl_verify_result;
    662   X509 *certificate;
    663 
    664   certificate = SSL_get_peer_certificate(ssl);
    665   if (NULL == certificate)
    666   {
    667     die ("Getting certificate failed\n");
    668   }
    669   // In theory, we verify that the cert is valid
    670   ssl_verify_result = SSL_get_verify_result(ssl);
    671   switch (ssl_verify_result)
    672   {
    673   case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
    674   case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
    675     die ("certificate is self signed\n");
    676   case X509_V_OK:
    677     verb ("V: certificate verification passed\n");
    678     break;
    679   default:
    680     die ("certification verification error: %ld\n",
    681          ssl_verify_result);
    682   }
    683  return 0;
    684 }
    685 #endif
    686 
    687 #ifdef USE_POLARSSL
    688 void
    689 check_key_length (ssl_context *ssl)
    690 {
    691   uint32_t key_bits;
    692   const x509_cert *certificate;
    693   const rsa_context *public_key;
    694   char buf[1024];
    695 
    696   certificate = ssl_get_peer_cert (ssl);
    697   if (NULL == certificate)
    698   {
    699     die ("Getting certificate failed\n");
    700   }
    701 
    702   x509parse_dn_gets(buf, 1024, &certificate->subject);
    703   verb ("V: Certificate for subject '%s'\n", buf);
    704 
    705   public_key = &certificate->rsa;
    706   if (NULL == public_key)
    707   {
    708     die ("public key extraction failure\n");
    709   } else {
    710     verb ("V: public key is ready for inspection\n");
    711   }
    712   key_bits = mpi_msb (&public_key->N);
    713   if (MIN_PUB_KEY_LEN >= key_bits)
    714   {
    715     die ("Unsafe public key size: %d bits\n", key_bits);
    716   } else {
    717     verb ("V: key length appears safe\n");
    718   }
    719 }
    720 #else
    721 void
    722 check_key_length (SSL *ssl)
    723 {
    724   uint32_t key_bits;
    725   X509 *certificate;
    726   EVP_PKEY *public_key;
    727   certificate = SSL_get_peer_certificate (ssl);
    728   if (NULL == certificate)
    729   {
    730     die ("Getting certificate failed\n");
    731   }
    732   public_key = X509_get_pubkey (certificate);
    733   if (NULL == public_key)
    734   {
    735     die ("public key extraction failure\n");
    736   } else {
    737     verb ("V: public key is ready for inspection\n");
    738   }
    739 
    740   key_bits = get_certificate_keybits (public_key);
    741   if (MIN_PUB_KEY_LEN >= key_bits && public_key->type != EVP_PKEY_EC)
    742   {
    743     die ("Unsafe public key size: %d bits\n", key_bits);
    744   } else {
    745      if (public_key->type == EVP_PKEY_EC)
    746        if(key_bits >= MIN_ECC_PUB_KEY_LEN
    747           && key_bits <= MAX_ECC_PUB_KEY_LEN)
    748        {
    749          verb ("V: ECC key length appears safe\n");
    750        } else {
    751          die ("Unsafe ECC key size: %d bits\n", key_bits);
    752      } else {
    753        verb ("V: key length appears safe\n");
    754      }
    755   }
    756   EVP_PKEY_free (public_key);
    757 }
    758 #endif
    759 
    760 #ifdef USE_POLARSSL
    761 void
    762 inspect_key (ssl_context *ssl, const char *hostname)
    763 {
    764   verify_signature (ssl, hostname);
    765 
    766   // ssl_get_verify_result() already checks for CN / subjectAltName match
    767   // and reports the mismatch as error. So check_name() is not called
    768 }
    769 #else
    770 void
    771 inspect_key (SSL *ssl, const char *hostname)
    772 {
    773 
    774     verify_signature (ssl, hostname);
    775     check_name (ssl, hostname);
    776 }
    777 #endif
    778 
    779 #ifdef USE_POLARSSL
    780 void
    781 check_timestamp (uint32_t server_time)
    782 {
    783   uint32_t compiled_time = RECENT_COMPILE_DATE;
    784   uint32_t max_reasonable_time = MAX_REASONABLE_TIME;
    785   if (compiled_time < server_time
    786       &&
    787       server_time < max_reasonable_time)
    788   {
    789     verb("V: remote peer provided: %d, preferred over compile time: %d\n",
    790           server_time, compiled_time);
    791   } else {
    792     die("V: the remote server is a false ticker! server: %d compile: %d\n",
    793          server_time, compiled_time);
    794   }
    795 }
    796 
    797 static int ssl_do_handshake_part(ssl_context *ssl)
    798 {
    799   int ret = 0;
    800 
    801   /* Only do steps till ServerHello is received */
    802   while (ssl->state != SSL_SERVER_HELLO)
    803   {
    804     ret = ssl_handshake_step (ssl);
    805     if (0 != ret)
    806     {
    807       die("SSL handshake failed\n");
    808     }
    809   }
    810   /* Do ServerHello so we can skim the timestamp */
    811   ret = ssl_handshake_step (ssl);
    812   if (0 != ret)
    813   {
    814     die("SSL handshake failed\n");
    815   }
    816 
    817   return 0;
    818 }
    819 
    820 /**
    821  * Run SSL handshake and store the resulting time value in the
    822  * 'time_map'.
    823  *
    824  * @param time_map where to store the current time
    825  */
    826 static void
    827 run_ssl (uint32_t *time_map, int time_is_an_illusion)
    828 {
    829   entropy_context entropy;
    830   ctr_drbg_context ctr_drbg;
    831   ssl_context ssl;
    832   proxy_polarssl_ctx proxy_ctx;
    833   x509_cert cacert;
    834   struct stat statbuf;
    835   int ret = 0, server_fd = 0;
    836   char *pers = "tlsdate-helper";
    837 
    838   memset (&ssl, 0, sizeof(ssl_context));
    839   memset (&cacert, 0, sizeof(x509_cert));
    840 
    841   verb("V: Using PolarSSL for SSL\n");
    842   if (ca_racket)
    843   {
    844     if (-1 == stat (ca_cert_container, &statbuf))
    845     {
    846       die("Unable to stat CA certficate container %s\n", ca_cert_container);
    847     }
    848     else
    849     {
    850       switch (statbuf.st_mode & S_IFMT)
    851       {
    852       case S_IFREG:
    853         if (0 > x509parse_crtfile(&cacert, ca_cert_container))
    854           fprintf(stderr, "x509parse_crtfile failed\n");
    855         break;
    856       case S_IFDIR:
    857         if (0 > x509parse_crtpath(&cacert, ca_cert_container))
    858           fprintf(stderr, "x509parse_crtpath failed\n");
    859         break;
    860       default:
    861         die("Unable to load CA certficate container %s\n", ca_cert_container);
    862       }
    863     }
    864   }
    865 
    866   entropy_init (&entropy);
    867   if (0 != ctr_drbg_init (&ctr_drbg, entropy_func, &entropy,
    868                          (unsigned char *) pers, strlen(pers)))
    869   {
    870     die("Failed to initialize CTR_DRBG\n");
    871   }
    872 
    873   if (0 != ssl_init (&ssl))
    874   {
    875     die("SSL initialization failed\n");
    876   }
    877   ssl_set_endpoint (&ssl, SSL_IS_CLIENT);
    878   ssl_set_rng (&ssl, ctr_drbg_random, &ctr_drbg);
    879   ssl_set_ca_chain (&ssl, &cacert, NULL, hostname_to_verify);
    880   if (ca_racket)
    881   {
    882       // You can do SSL_VERIFY_REQUIRED here, but then the check in
    883       // inspect_key() never happens as the ssl_handshake() will fail.
    884       ssl_set_authmode (&ssl, SSL_VERIFY_OPTIONAL);
    885   }
    886 
    887   if (proxy)
    888   {
    889     char *scheme;
    890     char *proxy_host;
    891     char *proxy_port;
    892 
    893     parse_proxy_uri (proxy, &scheme, &proxy_host, &proxy_port);
    894 
    895     verb("V: opening socket to proxy %s:%s\n", proxy_host, proxy_port);
    896     if (0 != net_connect (&server_fd, proxy_host, atoi(proxy_port)))
    897     {
    898       die ("SSL connection failed\n");
    899     }
    900 
    901     proxy_polarssl_init (&proxy_ctx);
    902     proxy_polarssl_set_bio (&proxy_ctx, net_recv, &server_fd, net_send, &server_fd);
    903     proxy_polarssl_set_host (&proxy_ctx, host);
    904     proxy_polarssl_set_port (&proxy_ctx, atoi(port));
    905     proxy_polarssl_set_scheme (&proxy_ctx, scheme);
    906 
    907     ssl_set_bio (&ssl, proxy_polarssl_recv, &proxy_ctx, proxy_polarssl_send, &proxy_ctx);
    908 
    909     verb("V: Handle proxy connection\n");
    910     if (0 == proxy_ctx.f_connect (&proxy_ctx))
    911       die("Proxy connection failed\n");
    912   }
    913   else
    914   {
    915     verb("V: opening socket to %s:%s\n", host, port);
    916     if (0 != net_connect (&server_fd, host, atoi(port)))
    917     {
    918       die ("SSL connection failed\n");
    919     }
    920 
    921     ssl_set_bio (&ssl, net_recv, &server_fd, net_send, &server_fd);
    922   }
    923 
    924   verb("V: starting handshake\n");
    925   if (0 != ssl_do_handshake_part (&ssl))
    926     die("SSL handshake first part failed\n");
    927 
    928   uint32_t timestamp = ( (uint32_t) ssl.in_msg[6] << 24 )
    929                      | ( (uint32_t) ssl.in_msg[7] << 16 )
    930                      | ( (uint32_t) ssl.in_msg[8] <<  8 )
    931                      | ( (uint32_t) ssl.in_msg[9]       );
    932   check_timestamp (timestamp);
    933 
    934   verb("V: continuing handshake\n");
    935   /* Continue with handshake */
    936   while (0 != (ret = ssl_handshake (&ssl)))
    937   {
    938     if (POLARSSL_ERR_NET_WANT_READ  != ret &&
    939         POLARSSL_ERR_NET_WANT_WRITE != ret)
    940     {
    941       die("SSL handshake failed\n");
    942     }
    943   }
    944 
    945   // Verify the peer certificate against the CA certs on the local system
    946   if (ca_racket) {
    947     inspect_key (&ssl, hostname_to_verify);
    948   } else {
    949     verb ("V: Certificate verification skipped!\n");
    950   }
    951   check_key_length (&ssl);
    952 
    953   memcpy (time_map, &timestamp, sizeof(uint32_t));
    954   proxy_polarssl_free (&proxy_ctx);
    955   ssl_free (&ssl);
    956   x509_free (&cacert);
    957 }
    958 #else /* USE_POLARSSL */
    959 /**
    960  * Run SSL handshake and store the resulting time value in the
    961  * 'time_map'.
    962  *
    963  * @param time_map where to store the current time
    964  */
    965 static void
    966 run_ssl (uint32_t *time_map, int time_is_an_illusion)
    967 {
    968   BIO *s_bio;
    969   SSL_CTX *ctx;
    970   SSL *ssl;
    971   struct stat statbuf;
    972 
    973   SSL_load_error_strings();
    974   SSL_library_init();
    975 
    976   ctx = NULL;
    977   if (0 == strcmp("sslv23", protocol))
    978   {
    979     verb ("V: using SSLv23_client_method()\n");
    980     ctx = SSL_CTX_new(SSLv23_client_method());
    981   } else if (0 == strcmp("sslv3", protocol))
    982   {
    983     verb ("V: using SSLv3_client_method()\n");
    984     ctx = SSL_CTX_new(SSLv3_client_method());
    985   } else if (0 == strcmp("tlsv1", protocol))
    986   {
    987     verb ("V: using TLSv1_client_method()\n");
    988     ctx = SSL_CTX_new(TLSv1_client_method());
    989   } else
    990     die("Unsupported protocol `%s'\n", protocol);
    991 
    992   if (ctx == NULL)
    993     die("OpenSSL failed to support protocol `%s'\n", protocol);
    994 
    995   verb("V: Using OpenSSL for SSL\n");
    996   if (ca_racket)
    997   {
    998     if (-1 == stat(ca_cert_container, &statbuf))
    999     {
   1000       die("Unable to stat CA certficate container %s\n", ca_cert_container);
   1001     } else
   1002     {
   1003       switch (statbuf.st_mode & S_IFMT)
   1004       {
   1005       case S_IFREG:
   1006         if (1 != SSL_CTX_load_verify_locations(ctx, ca_cert_container, NULL))
   1007           fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
   1008         break;
   1009       case S_IFDIR:
   1010         if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
   1011           fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
   1012         break;
   1013       default:
   1014         if (1 != SSL_CTX_load_verify_locations(ctx, NULL, ca_cert_container))
   1015         {
   1016           fprintf(stderr, "SSL_CTX_load_verify_locations failed\n");
   1017           die("Unable to load CA certficate container %s\n", ca_cert_container);
   1018         }
   1019       }
   1020     }
   1021   }
   1022 
   1023   if (NULL == (s_bio = make_ssl_bio(ctx)))
   1024     die ("SSL BIO setup failed\n");
   1025   BIO_get_ssl(s_bio, &ssl);
   1026   if (NULL == ssl)
   1027     die ("SSL setup failed\n");
   1028 
   1029   if (time_is_an_illusion)
   1030   {
   1031     SSL_set_info_callback(ssl, openssl_time_callback);
   1032   }
   1033 
   1034   SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
   1035   verb("V: opening socket to %s:%s\n", host, port);
   1036   if ( (1 != BIO_set_conn_hostname(s_bio, host)) ||
   1037        (1 != BIO_set_conn_port(s_bio, port)) )
   1038     die ("Failed to initialize connection to `%s:%s'\n", host, port);
   1039 
   1040   if (NULL == BIO_new_fp(stdout, BIO_NOCLOSE))
   1041     die ("BIO_new_fp returned error, possibly: %s", strerror(errno));
   1042 
   1043   // This should run in seccomp
   1044   // eg:     prctl(PR_SET_SECCOMP, 1);
   1045   if (1 != BIO_do_connect(s_bio)) /* XXX TODO: BIO_should_retry() later? */
   1046     die ("SSL connection failed\n");
   1047   if (1 != BIO_do_handshake(s_bio))
   1048     die ("SSL handshake failed\n");
   1049 
   1050   // Verify the peer certificate against the CA certs on the local system
   1051   if (ca_racket) {
   1052     inspect_key (ssl, hostname_to_verify);
   1053   } else {
   1054     verb ("V: Certificate verification skipped!\n");
   1055   }
   1056   check_key_length(ssl);
   1057   // from /usr/include/openssl/ssl3.h
   1058   //  ssl->s3->server_random is an unsigned char of 32 bits
   1059   memcpy(time_map, ssl->s3->server_random, sizeof (uint32_t));
   1060   SSL_free(ssl);
   1061   SSL_CTX_free(ctx);
   1062 }
   1063 #endif /* USE_POLARSSL */
   1064 /** drop root rights and become 'nobody' */
   1065 
   1066 int
   1067 main(int argc, char **argv)
   1068 {
   1069   uint32_t *time_map;
   1070   struct tlsdate_time start_time, end_time, warp_time;
   1071   int status;
   1072   pid_t ssl_child;
   1073   long long rt_time_ms;
   1074   uint32_t server_time_s;
   1075   int setclock;
   1076   int showtime;
   1077   int timewarp;
   1078   int leap;
   1079 
   1080   if (argc != 12)
   1081     return 1;
   1082   host = argv[1];
   1083   hostname_to_verify = argv[1];
   1084   port = argv[2];
   1085   protocol = argv[3];
   1086   ca_cert_container = argv[6];
   1087   ca_racket = (0 != strcmp ("unchecked", argv[4]));
   1088   verbose = (0 != strcmp ("quiet", argv[5]));
   1089   setclock = (0 == strcmp ("setclock", argv[7]));
   1090   showtime = (0 == strcmp ("showtime", argv[8]));
   1091   timewarp = (0 == strcmp ("timewarp", argv[9]));
   1092   leap = (0 == strcmp ("leapaway", argv[10]));
   1093   proxy = (0 == strcmp ("none", argv[11]) ? NULL : argv[11]);
   1094 
   1095   if (timewarp)
   1096   {
   1097 
   1098     verb ("V: RECENT_COMPILE_DATE is %lu.%06lu\n",
   1099          (unsigned long) CLOCK_SEC(&warp_time),
   1100          (unsigned long) CLOCK_USEC(&warp_time));
   1101 
   1102     if (1 == setclock) {
   1103       clock_init_time(&warp_time, RECENT_COMPILE_DATE, 0);
   1104     } else {
   1105       verb ("V: we'll do the time warp another time - we're not setting clock\n");
   1106     }
   1107   }
   1108 
   1109   /* We are not going to set the clock, thus no need to stay root */
   1110   if (0 == setclock && 0 == timewarp)
   1111   {
   1112     drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
   1113   }
   1114 /*
   1115 	XXX: KILL ME
   1116   // We cast the mmap value to remove this error when compiling with g++:
   1117   // src/tlsdate-helper.c: In function int main(int, char**):
   1118   // src/tlsdate-helper.c:822:41: error: invalid conversion from void* to uint32_t
   1119   time_map = (uint32_t *) mmap (NULL, sizeof (uint32_t),
   1120        PROT_READ | PROT_WRITE,
   1121        MAP_SHARED | MAP_ANONYMOUS, -1, 0);
   1122    if (MAP_FAILED == time_map)
   1123   {
   1124     fprintf (stderr, "mmap failed: %s\n",
   1125              strerror (errno));
   1126     return 1;
   1127   }
   1128 */
   1129   /* Get the current time from the system clock. */
   1130   if (0 != clock_get_real_time(&start_time))
   1131   {
   1132     die ("Failed to read current time of day: %s\n", strerror (errno));
   1133   }
   1134 
   1135   verb ("V: time is currently %lu.%06lu\n",
   1136        (unsigned long) CLOCK_SEC(&start_time),
   1137        (unsigned long) CLOCK_NSEC(&start_time));
   1138 
   1139   if (((unsigned long) CLOCK_SEC(&start_time)) < ((unsigned long) CLOCK_SEC(&warp_time)))
   1140   {
   1141     verb ("V: local clock time is less than RECENT_COMPILE_DATE\n");
   1142     if (timewarp)
   1143     {
   1144       verb ("V: Attempting to warp local clock into the future\n");
   1145       if (0 != clock_set_real_time(&warp_time))
   1146       {
   1147         die ("setting time failed: %s (Attempted to set clock to %lu.%06lu)\n",
   1148         strerror (errno),
   1149         (unsigned long) CLOCK_SEC(&warp_time),
   1150         (unsigned long) CLOCK_SEC(&warp_time));
   1151       }
   1152       if (0 != clock_get_real_time(&start_time))
   1153       {
   1154         die ("Failed to read current time of day: %s\n", strerror (errno));
   1155       }
   1156       verb ("V: time is currently %lu.%06lu\n",
   1157            (unsigned long) CLOCK_SEC(&start_time),
   1158            (unsigned long) CLOCK_NSEC(&start_time));
   1159       verb ("V: It's just a step to the left...\n");
   1160     }
   1161   } else {
   1162     verb ("V: time is greater than RECENT_COMPILE_DATE\n");
   1163   }
   1164 
   1165   /* initialize to bogus value, just to be on the safe side */
   1166   *time_map = 0;
   1167 
   1168   /* Run SSL interaction in separate process (and not as 'root') */
   1169   ssl_child = fork ();
   1170   if (-1 == ssl_child)
   1171     die ("fork failed: %s\n", strerror (errno));
   1172   if (0 == ssl_child)
   1173   {
   1174     drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
   1175     run_ssl (time_map, leap);
   1176     /*
   1177     XXX: should be a pipe close
   1178     (void) munmap (time_map, sizeof (uint32_t));
   1179     */
   1180     _exit (0);
   1181   }
   1182   if (ssl_child != waitpid (ssl_child, &status, 0))
   1183     die ("waitpid failed: %s\n", strerror (errno));
   1184   if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)) ))
   1185     die ("child process failed in SSL handshake\n");
   1186 
   1187   if (0 != clock_get_real_time(&end_time))
   1188     die ("Failed to read current time of day: %s\n", strerror (errno));
   1189 
   1190   /* calculate RTT */
   1191   rt_time_ms = (CLOCK_SEC(&end_time) - CLOCK_SEC(&start_time)) * 1000 + (CLOCK_USEC(&end_time) - CLOCK_USEC(&start_time)) / 1000;
   1192   if (rt_time_ms < 0)
   1193     rt_time_ms = 0; /* non-linear time... */
   1194 #ifdef USE_POLARSSL
   1195   server_time_s = *time_map;
   1196 #else
   1197   server_time_s = ntohl (*time_map);
   1198 #endif
   1199   /*
   1200   XXX: should be a pipe close
   1201   munmap (time_map, sizeof (uint32_t));
   1202   */
   1203   verb ("V: server time %u (difference is about %d s) was fetched in %lld ms\n",
   1204   (unsigned int) server_time_s,
   1205   CLOCK_SEC(&start_time) - server_time_s,
   1206   rt_time_ms);
   1207 
   1208   /* warning if the handshake took too long */
   1209   if (rt_time_ms > TLS_RTT_THRESHOLD) {
   1210     verb ("V: the TLS handshake took more than %d msecs - consider using a different " \
   1211       "server or run it again\n", TLS_RTT_THRESHOLD);
   1212   }
   1213 
   1214   if (showtime)
   1215   {
   1216      struct tm  ltm;
   1217      time_t tim = server_time_s;
   1218      char       buf[256];
   1219 
   1220      localtime_r(&tim, &ltm);
   1221      if (0 == strftime(buf, sizeof buf, "%a %b %e %H:%M:%S %Z %Y", &ltm))
   1222      {
   1223        die ("strftime returned 0\n");
   1224      }
   1225      fprintf(stdout, "%s\n", buf);
   1226   }
   1227 
   1228   /* finally, actually set the time */
   1229   if (setclock)
   1230   {
   1231     struct tlsdate_time server_time;
   1232 
   1233     clock_init_time(&server_time,  server_time_s + (rt_time_ms / 2 / 1000),
   1234                    (rt_time_ms / 2) % 1000);
   1235 
   1236     // We should never receive a time that is before the time we were last
   1237     // compiled; we subscribe to the linear theory of time for this program
   1238     // and this program alone!
   1239     if (CLOCK_SEC(&server_time) >= MAX_REASONABLE_TIME)
   1240       die("remote server is a false ticker from the future!\n");
   1241     if (CLOCK_SEC(&server_time) <= RECENT_COMPILE_DATE)
   1242       die ("remote server is a false ticker!\n");
   1243     if (0 != clock_set_real_time(&server_time))
   1244       die ("setting time failed: %s (Difference from server is about %d s)\n",
   1245      strerror (errno),
   1246      CLOCK_SEC(&start_time) - server_time_s);
   1247     verb ("V: setting time succeeded\n");
   1248   }
   1249   return 0;
   1250 }
   1251