LCOV - code coverage report
Current view: top level - lib/tls - tortls.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 175 190 92.1 %
Date: 2021-11-24 03:28:48 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /* Copyright (c) 2003, Roger Dingledine.
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * @file tortls.c
       8             :  * @brief Shared functionality for our TLS backends.
       9             :  **/
      10             : 
      11             : #define TORTLS_PRIVATE
      12             : #define TOR_X509_PRIVATE
      13             : #include "lib/tls/x509.h"
      14             : #include "lib/tls/x509_internal.h"
      15             : #include "lib/tls/tortls_sys.h"
      16             : #include "lib/tls/tortls.h"
      17             : #include "lib/tls/tortls_st.h"
      18             : #include "lib/tls/tortls_internal.h"
      19             : #include "lib/log/util_bug.h"
      20             : #include "lib/intmath/cmp.h"
      21             : #include "lib/crypt_ops/crypto_rsa.h"
      22             : #include "lib/crypt_ops/crypto_rand.h"
      23             : #include "lib/net/socket.h"
      24             : #include "lib/subsys/subsys.h"
      25             : 
      26             : #ifdef _WIN32
      27             :   #include <winsock2.h>
      28             :   #include <ws2tcpip.h>
      29             : #endif
      30             : 
      31             : #include <time.h>
      32             : 
      33             : /** Global TLS contexts. We keep them here because nobody else needs
      34             :  * to touch them.
      35             :  *
      36             :  * @{ */
      37             : STATIC tor_tls_context_t *server_tls_context = NULL;
      38             : STATIC tor_tls_context_t *client_tls_context = NULL;
      39             : /**@}*/
      40             : 
      41             : /**
      42             :  * Return the appropriate TLS context.
      43             :  */
      44             : tor_tls_context_t *
      45         252 : tor_tls_context_get(int is_server)
      46             : {
      47         252 :   return is_server ? server_tls_context : client_tls_context;
      48             : }
      49             : 
      50             : /** Convert an errno (or a WSAerrno on windows) into a TOR_TLS_* error
      51             :  * code. */
      52             : int
      53           6 : tor_errno_to_tls_error(int e)
      54             : {
      55           6 :   switch (e) {
      56             :     case SOCK_ERRNO(ECONNRESET): // most common
      57             :       return TOR_TLS_ERROR_CONNRESET;
      58             :     case SOCK_ERRNO(ETIMEDOUT):
      59             :       return TOR_TLS_ERROR_TIMEOUT;
      60             :     case SOCK_ERRNO(EHOSTUNREACH):
      61             :     case SOCK_ERRNO(ENETUNREACH):
      62             :       return TOR_TLS_ERROR_NO_ROUTE;
      63             :     case SOCK_ERRNO(ECONNREFUSED):
      64             :       return TOR_TLS_ERROR_CONNREFUSED; // least common
      65             :     default:
      66             :       return TOR_TLS_ERROR_MISC;
      67             :   }
      68             : }
      69             : 
      70             : /** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
      71             :  * and ID certificate that we're currently using for our V3 in-protocol
      72             :  * handshake's certificate chain.  If <b>server</b> is true, provide the certs
      73             :  * that we use in server mode (auth, ID); otherwise, provide the certs that we
      74             :  * use in client mode. (link, ID) */
      75             : int
      76         196 : tor_tls_get_my_certs(int server,
      77             :                      const tor_x509_cert_t **link_cert_out,
      78             :                      const tor_x509_cert_t **id_cert_out)
      79             : {
      80         196 :   tor_tls_context_t *ctx = tor_tls_context_get(server);
      81         196 :   int rv = -1;
      82         196 :   const tor_x509_cert_t *link_cert = NULL;
      83         196 :   const tor_x509_cert_t *id_cert = NULL;
      84         196 :   if (ctx) {
      85         193 :     rv = 0;
      86         193 :     link_cert = server ? ctx->my_link_cert : ctx->my_auth_cert;
      87         193 :     id_cert = ctx->my_id_cert;
      88             :   }
      89         196 :   if (link_cert_out)
      90         161 :     *link_cert_out = link_cert;
      91         196 :   if (id_cert_out)
      92         191 :     *id_cert_out = id_cert;
      93         196 :   return rv;
      94             : }
      95             : 
      96             : /**
      97             :  * Return the authentication key that we use to authenticate ourselves as a
      98             :  * client in the V3 in-protocol handshake.
      99             :  */
     100             : crypto_pk_t *
     101          22 : tor_tls_get_my_client_auth_key(void)
     102             : {
     103          22 :   tor_tls_context_t *context = tor_tls_context_get(0);
     104          22 :   if (! context)
     105             :     return NULL;
     106          21 :   return context->auth_key;
     107             : }
     108             : 
     109             : /** Increase the reference count of <b>ctx</b>. */
     110             : void
     111         122 : tor_tls_context_incref(tor_tls_context_t *ctx)
     112             : {
     113         122 :   ++ctx->refcnt;
     114         122 : }
     115             : 
     116             : /** Remove a reference to <b>ctx</b>, and free it if it has no more
     117             :  * references. */
     118             : void
     119          37 : tor_tls_context_decref(tor_tls_context_t *ctx)
     120             : {
     121          37 :   tor_assert(ctx);
     122          37 :   if (--ctx->refcnt == 0) {
     123           6 :     tor_tls_context_impl_free(ctx->ctx);
     124           6 :     tor_x509_cert_free(ctx->my_link_cert);
     125           6 :     tor_x509_cert_free(ctx->my_id_cert);
     126           6 :     tor_x509_cert_free(ctx->my_auth_cert);
     127           6 :     crypto_pk_free(ctx->link_key);
     128           6 :     crypto_pk_free(ctx->auth_key);
     129             :     /* LCOV_EXCL_BR_START since ctx will never be NULL here */
     130           6 :     tor_free(ctx);
     131             :     /* LCOV_EXCL_BR_STOP */
     132             :   }
     133          37 : }
     134             : 
     135             : /** Free all global TLS structures. */
     136             : void
     137           1 : tor_tls_free_all(void)
     138             : {
     139           1 :   check_no_tls_errors();
     140             : 
     141           1 :   if (server_tls_context) {
     142           1 :     tor_tls_context_t *ctx = server_tls_context;
     143           1 :     server_tls_context = NULL;
     144           1 :     tor_tls_context_decref(ctx);
     145             :   }
     146           1 :   if (client_tls_context) {
     147           1 :     tor_tls_context_t *ctx = client_tls_context;
     148           1 :     client_tls_context = NULL;
     149           1 :     tor_tls_context_decref(ctx);
     150             :   }
     151           1 : }
     152             : 
     153             : /** Given a TOR_TLS_* error code, return a string equivalent. */
     154             : const char *
     155          11 : tor_tls_err_to_string(int err)
     156             : {
     157          11 :   if (err >= 0)
     158             :     return "[Not an error.]";
     159          10 :   switch (err) {
     160             :     case TOR_TLS_ERROR_MISC: return "misc error";
     161           1 :     case TOR_TLS_ERROR_IO: return "unexpected close";
     162           1 :     case TOR_TLS_ERROR_CONNREFUSED: return "connection refused";
     163           1 :     case TOR_TLS_ERROR_CONNRESET: return "connection reset";
     164           1 :     case TOR_TLS_ERROR_NO_ROUTE: return "host unreachable";
     165           1 :     case TOR_TLS_ERROR_TIMEOUT: return "connection timed out";
     166           1 :     case TOR_TLS_CLOSE: return "closed";
     167           1 :     case TOR_TLS_WANTREAD: return "want to read";
     168           1 :     case TOR_TLS_WANTWRITE: return "want to write";
     169           1 :     default: return "(unknown error code)";
     170             :   }
     171             : }
     172             : 
     173             : /** Create new global client and server TLS contexts.
     174             :  *
     175             :  * If <b>server_identity</b> is NULL, this will not generate a server
     176             :  * TLS context. If TOR_TLS_CTX_IS_PUBLIC_SERVER is set in <b>flags</b>, use
     177             :  * the same TLS context for incoming and outgoing connections, and
     178             :  * ignore <b>client_identity</b>. If one of TOR_TLS_CTX_USE_ECDHE_P{224,256}
     179             :  * is set in <b>flags</b>, use that ECDHE group if possible; otherwise use
     180             :  * the default ECDHE group. */
     181             : int
     182          98 : tor_tls_context_init(unsigned flags,
     183             :                      crypto_pk_t *client_identity,
     184             :                      crypto_pk_t *server_identity,
     185             :                      unsigned int key_lifetime)
     186             : {
     187          98 :   int rv1 = 0;
     188          98 :   int rv2 = 0;
     189          98 :   const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER;
     190          98 :   check_no_tls_errors();
     191             : 
     192          98 :   if (is_public_server) {
     193          93 :     tor_tls_context_t *new_ctx;
     194          93 :     tor_tls_context_t *old_ctx;
     195             : 
     196          93 :     tor_assert(server_identity != NULL);
     197             : 
     198          93 :     rv1 = tor_tls_context_init_one(&server_tls_context,
     199             :                                    server_identity,
     200             :                                    key_lifetime, flags, 0);
     201             : 
     202          93 :     if (rv1 >= 0) {
     203          93 :       new_ctx = server_tls_context;
     204          93 :       tor_tls_context_incref(new_ctx);
     205          93 :       old_ctx = client_tls_context;
     206          93 :       client_tls_context = new_ctx;
     207             : 
     208          93 :       if (old_ctx != NULL) {
     209           1 :         tor_tls_context_decref(old_ctx);
     210             :       }
     211             :     } else {
     212           0 :       tls_log_errors(NULL, LOG_WARN, LD_CRYPTO,
     213             :                      "constructing a TLS context");
     214             :     }
     215             :   } else {
     216           5 :     if (server_identity != NULL) {
     217           1 :       rv1 = tor_tls_context_init_one(&server_tls_context,
     218             :                                      server_identity,
     219             :                                      key_lifetime,
     220             :                                      flags,
     221             :                                      0);
     222           1 :       if (rv1 < 0)
     223           0 :         tls_log_errors(NULL, LOG_WARN, LD_CRYPTO,
     224             :                        "constructing a server TLS context");
     225             :     } else {
     226           4 :       tor_tls_context_t *old_ctx = server_tls_context;
     227           4 :       server_tls_context = NULL;
     228             : 
     229           4 :       if (old_ctx != NULL) {
     230           0 :         tor_tls_context_decref(old_ctx);
     231             :       }
     232             :     }
     233             : 
     234           5 :     rv2 = tor_tls_context_init_one(&client_tls_context,
     235             :                                    client_identity,
     236             :                                    key_lifetime,
     237             :                                    flags,
     238             :                                    1);
     239           5 :     if (rv2 < 0)
     240           0 :         tls_log_errors(NULL, LOG_WARN, LD_CRYPTO,
     241             :                        "constructing a client TLS context");
     242             :   }
     243             : 
     244          98 :   return MIN(rv1, rv2);
     245             : }
     246             : 
     247             : /** Create a new global TLS context.
     248             :  *
     249             :  * You can call this function multiple times.  Each time you call it,
     250             :  * it generates new certificates; all new connections will use
     251             :  * the new SSL context.
     252             :  */
     253             : int
     254         100 : tor_tls_context_init_one(tor_tls_context_t **ppcontext,
     255             :                          crypto_pk_t *identity,
     256             :                          unsigned int key_lifetime,
     257             :                          unsigned int flags,
     258             :                          int is_client)
     259             : {
     260         100 :   tor_tls_context_t *new_ctx = tor_tls_context_new(identity,
     261             :                                                    key_lifetime,
     262             :                                                    flags,
     263             :                                                    is_client);
     264         100 :   tor_tls_context_t *old_ctx = *ppcontext;
     265             : 
     266         100 :   if (new_ctx != NULL) {
     267          99 :     *ppcontext = new_ctx;
     268             : 
     269             :     /* Free the old context if one existed. */
     270          99 :     if (old_ctx != NULL) {
     271             :       /* This is safe even if there are open connections: we reference-
     272             :        * count tor_tls_context_t objects. */
     273           4 :       tor_tls_context_decref(old_ctx);
     274             :     }
     275             :   }
     276             : 
     277         100 :   return ((new_ctx != NULL) ? 0 : -1);
     278             : }
     279             : 
     280             : /** Size of the RSA key to use for our TLS link keys */
     281             : #define RSA_LINK_KEY_BITS 2048
     282             : 
     283             : /** How long do identity certificates live? (sec) */
     284             : #define IDENTITY_CERT_LIFETIME  (365*24*60*60)
     285             : 
     286             : /**
     287             :  * Initialize the certificates and keys for a TLS context <b>result</b>
     288             :  *
     289             :  * Other arguments as for tor_tls_context_new().
     290             :  */
     291             : int
     292          95 : tor_tls_context_init_certificates(tor_tls_context_t *result,
     293             :                                   crypto_pk_t *identity,
     294             :                                   unsigned key_lifetime,
     295             :                                   unsigned flags)
     296             : {
     297          95 :   (void)flags;
     298          95 :   int rv = -1;
     299          95 :   char *nickname = NULL, *nn2 = NULL;
     300          95 :   crypto_pk_t *rsa = NULL, *rsa_auth = NULL;
     301          95 :   tor_x509_cert_impl_t *cert = NULL, *idcert = NULL, *authcert = NULL;
     302             : 
     303          95 :   nickname = crypto_random_hostname(8, 20, "www.", ".net");
     304             : 
     305             : #ifdef DISABLE_V3_LINKPROTO_SERVERSIDE
     306             :   nn2 = crypto_random_hostname(8, 20, "www.", ".net");
     307             : #else
     308          95 :   nn2 = crypto_random_hostname(8, 20, "www.", ".com");
     309             : #endif
     310             : 
     311             :   /* Generate short-term RSA key for use with TLS. */
     312          95 :   if (!(rsa = crypto_pk_new()))
     313           1 :     goto error;
     314          94 :   if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
     315           0 :     goto error;
     316             : 
     317             :   /* Generate short-term RSA key for use in the in-protocol ("v3")
     318             :    * authentication handshake. */
     319          94 :   if (!(rsa_auth = crypto_pk_new()))
     320           0 :     goto error;
     321          94 :   if (crypto_pk_generate_key(rsa_auth)<0)
     322           0 :     goto error;
     323             : 
     324             :   /* Create a link certificate signed by identity key. */
     325          94 :   cert = tor_tls_create_certificate(rsa, identity, nickname, nn2,
     326             :                                     key_lifetime);
     327             :   /* Create self-signed certificate for identity key. */
     328          94 :   idcert = tor_tls_create_certificate(identity, identity, nn2, nn2,
     329             :                                       IDENTITY_CERT_LIFETIME);
     330             :   /* Create an authentication certificate signed by identity key. */
     331          94 :   authcert = tor_tls_create_certificate(rsa_auth, identity, nickname, nn2,
     332             :                                         key_lifetime);
     333          94 :   if (!cert || !idcert || !authcert) {
     334           0 :     log_warn(LD_CRYPTO, "Error creating certificate");
     335           0 :     goto error;
     336             :   }
     337             : 
     338          94 :   result->my_link_cert = tor_x509_cert_new(cert);
     339          94 :   cert = NULL;
     340          94 :   result->my_id_cert = tor_x509_cert_new(idcert);
     341          94 :   idcert = NULL;
     342          94 :   result->my_auth_cert = tor_x509_cert_new(authcert);
     343          94 :   authcert = NULL;
     344          94 :   if (!result->my_link_cert || !result->my_id_cert || !result->my_auth_cert)
     345           0 :     goto error;
     346          94 :   result->link_key = rsa;
     347          94 :   rsa = NULL;
     348          94 :   result->auth_key = rsa_auth;
     349          94 :   rsa_auth = NULL;
     350             : 
     351          94 :   rv = 0;
     352          95 :  error:
     353             : 
     354          95 :   tor_free(nickname);
     355          95 :   tor_free(nn2);
     356             : 
     357          95 :   tor_x509_cert_impl_free(cert);
     358          95 :   tor_x509_cert_impl_free(idcert);
     359          95 :   tor_x509_cert_impl_free(authcert);
     360          95 :   crypto_pk_free(rsa);
     361          95 :   crypto_pk_free(rsa_auth);
     362             : 
     363          95 :   return rv;
     364             : }
     365             : /** Make future log messages about <b>tls</b> display the address
     366             :  * <b>address</b>.
     367             :  */
     368             : void
     369           4 : tor_tls_set_logged_address(tor_tls_t *tls, const char *address)
     370             : {
     371           4 :   tor_assert(tls);
     372           4 :   tor_free(tls->address);
     373           4 :   tls->address = tor_strdup(address);
     374           4 : }
     375             : 
     376             : /** Return whether this tls initiated the connect (client) or
     377             :  * received it (server). */
     378             : int
     379           3 : tor_tls_is_server(tor_tls_t *tls)
     380             : {
     381           3 :   tor_assert(tls);
     382           3 :   return tls->isServer;
     383             : }
     384             : 
     385             : /** Release resources associated with a TLS object.  Does not close the
     386             :  * underlying file descriptor.
     387             :  */
     388             : void
     389          30 : tor_tls_free_(tor_tls_t *tls)
     390             : {
     391          30 :   if (!tls)
     392             :     return;
     393          29 :   tor_assert(tls->ssl);
     394             :   {
     395          29 :     size_t r,w;
     396          29 :     tor_tls_get_n_raw_bytes(tls,&r,&w); /* ensure written_by_tls is updated */
     397             :   }
     398          29 :   tor_tls_impl_free(tls->ssl);
     399          29 :   tls->ssl = NULL;
     400             : #ifdef ENABLE_OPENSSL
     401          29 :   tls->negotiated_callback = NULL;
     402             : #endif
     403          29 :   if (tls->context)
     404          29 :     tor_tls_context_decref(tls->context);
     405          29 :   tor_free(tls->address);
     406          29 :   tls->magic = 0x99999999;
     407          29 :   tor_free(tls);
     408             : }
     409             : 
     410             : /** If the provided tls connection is authenticated and has a
     411             :  * certificate chain that is currently valid and signed, then set
     412             :  * *<b>identity_key</b> to the identity certificate's key and return
     413             :  * 0.  Else, return -1 and log complaints with log-level <b>severity</b>.
     414             :  */
     415             : int
     416           4 : tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity)
     417             : {
     418           4 :   tor_x509_cert_impl_t *cert = NULL, *id_cert = NULL;
     419           4 :   tor_x509_cert_t *peer_x509 = NULL, *id_x509 = NULL;
     420           4 :   tor_assert(tls);
     421           4 :   tor_assert(identity);
     422           4 :   int rv = -1;
     423             : 
     424           4 :   try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
     425           4 :   if (!cert)
     426           2 :     goto done;
     427           2 :   if (!id_cert) {
     428           0 :     log_fn(severity,LD_PROTOCOL,"No distinct identity certificate found");
     429           0 :     goto done;
     430             :   }
     431           2 :   peer_x509 = tor_x509_cert_new(cert);
     432           2 :   id_x509 = tor_x509_cert_new(id_cert);
     433           2 :   cert = id_cert = NULL; /* Prevent double-free */
     434             : 
     435           2 :   if (! tor_tls_cert_is_valid(severity, peer_x509, id_x509, time(NULL), 0)) {
     436           1 :     goto done;
     437             :   }
     438             : 
     439           1 :   *identity = tor_tls_cert_get_key(id_x509);
     440           1 :   rv = 0;
     441             : 
     442           4 :  done:
     443           4 :   tor_x509_cert_impl_free(cert);
     444           4 :   tor_x509_cert_impl_free(id_cert);
     445           4 :   tor_x509_cert_free(peer_x509);
     446           4 :   tor_x509_cert_free(id_x509);
     447             : 
     448           4 :   return rv;
     449             : }
     450             : 
     451             : static void
     452           0 : subsys_tortls_shutdown(void)
     453             : {
     454           0 :   tor_tls_free_all();
     455           0 : }
     456             : 
     457             : const subsys_fns_t sys_tortls = {
     458             :   .name = "tortls",
     459             :   SUBSYS_DECLARE_LOCATION(),
     460             :   .level = -50,
     461             :   .shutdown = subsys_tortls_shutdown
     462             : };

Generated by: LCOV version 1.14