tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

sigcommon.c (5907B)


      1 /* Copyright (c) 2001 Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * \file sigcommon.c
      9 * \brief Shared hashing, signing, and signature-checking code for directory
     10 *    objects.
     11 **/
     12 
     13 #define SIGCOMMON_PRIVATE
     14 
     15 #include "core/or/or.h"
     16 #include "feature/dirparse/parsecommon.h"
     17 #include "feature/dirparse/sigcommon.h"
     18 
     19 /** Helper function for <b>router_get_hash_impl</b>: given <b>s</b>,
     20 * <b>s_len</b>, <b>start_str</b>, <b>end_str</b>, and <b>end_c</b> with the
     21 * same semantics as in that function, set *<b>start_out</b> (inclusive) and
     22 * *<b>end_out</b> (exclusive) to the boundaries of the string to be hashed.
     23 *
     24 * Return 0 on success and -1 on failure.
     25 */
     26 int
     27 router_get_hash_impl_helper(const char *s, size_t s_len,
     28                            const char *start_str,
     29                            const char *end_str, char end_c,
     30                            int log_severity,
     31                            const char **start_out, const char **end_out)
     32 {
     33  const char *start, *end;
     34  start = tor_memstr(s, s_len, start_str);
     35  if (!start) {
     36    log_fn(log_severity,LD_DIR,
     37           "couldn't find start of hashed material \"%s\"",start_str);
     38    return -1;
     39  }
     40  if (start != s && *(start-1) != '\n') {
     41    log_fn(log_severity,LD_DIR,
     42             "first occurrence of \"%s\" is not at the start of a line",
     43             start_str);
     44    return -1;
     45  }
     46  end = tor_memstr(start+strlen(start_str),
     47                   s_len - (start-s) - strlen(start_str), end_str);
     48  if (!end) {
     49    log_fn(log_severity,LD_DIR,
     50           "couldn't find end of hashed material \"%s\"",end_str);
     51    return -1;
     52  }
     53  end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
     54  if (!end) {
     55    log_fn(log_severity,LD_DIR,
     56           "couldn't find EOL");
     57    return -1;
     58  }
     59  ++end;
     60 
     61  *start_out = start;
     62  *end_out = end;
     63  return 0;
     64 }
     65 
     66 /** Compute the digest of the substring of <b>s</b> taken from the first
     67 * occurrence of <b>start_str</b> through the first instance of c after the
     68 * first subsequent occurrence of <b>end_str</b>; store the 20-byte or 32-byte
     69 * result in <b>digest</b>; return 0 on success.
     70 *
     71 * If no such substring exists, return -1.
     72 */
     73 int
     74 router_get_hash_impl(const char *s, size_t s_len, char *digest,
     75                     const char *start_str,
     76                     const char *end_str, char end_c,
     77                     digest_algorithm_t alg)
     78 {
     79  const char *start=NULL, *end=NULL;
     80  if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
     81                                  &start,&end)<0)
     82    return -1;
     83 
     84  return router_compute_hash_final(digest, start, end-start, alg);
     85 }
     86 
     87 /** Compute the digest of the <b>len</b>-byte directory object at
     88 * <b>start</b>, using <b>alg</b>. Store the result in <b>digest</b>, which
     89 * must be long enough to hold it. */
     90 MOCK_IMPL(STATIC int,
     91 router_compute_hash_final,(char *digest,
     92                           const char *start, size_t len,
     93                           digest_algorithm_t alg))
     94 {
     95  if (alg == DIGEST_SHA1) {
     96    if (crypto_digest(digest, start, len) < 0) {
     97      log_warn(LD_BUG,"couldn't compute digest");
     98      return -1;
     99    }
    100  } else {
    101    if (crypto_digest256(digest, start, len, alg) < 0) {
    102      log_warn(LD_BUG,"couldn't compute digest");
    103      return -1;
    104    }
    105  }
    106 
    107  return 0;
    108 }
    109 
    110 /** As router_get_hash_impl, but compute all hashes. */
    111 int
    112 router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests,
    113                       const char *start_str,
    114                       const char *end_str, char end_c)
    115 {
    116  const char *start=NULL, *end=NULL;
    117  if (router_get_hash_impl_helper(s,s_len,start_str,end_str,end_c,LOG_WARN,
    118                                  &start,&end)<0)
    119    return -1;
    120 
    121  if (crypto_common_digests(digests, start, end-start)) {
    122    log_warn(LD_BUG,"couldn't compute digests");
    123    return -1;
    124  }
    125 
    126  return 0;
    127 }
    128 
    129 MOCK_IMPL(STATIC int,
    130 signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
    131 {
    132  return tor_memeq(d1, d2, len);
    133 }
    134 
    135 /** Check whether the object body of the token in <b>tok</b> has a good
    136 * signature for <b>digest</b> using key <b>pkey</b>.
    137 * If <b>CST_NO_CHECK_OBJTYPE</b> is set, do not check
    138 * the object type of the signature object. Use <b>doctype</b> as the type of
    139 * the document when generating log messages.  Return 0 on success, negative
    140 * on failure.
    141 */
    142 MOCK_IMPL(int,
    143 check_signature_token,(const char *digest,
    144                      ssize_t digest_len,
    145                      directory_token_t *tok,
    146                      crypto_pk_t *pkey,
    147                      int flags,
    148                      const char *doctype))
    149 {
    150  char *signed_digest;
    151  size_t keysize;
    152  const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
    153 
    154  tor_assert(pkey);
    155  tor_assert(tok);
    156  tor_assert(digest);
    157  tor_assert(doctype);
    158 
    159  if (check_objtype) {
    160    if (strcmp(tok->object_type, "SIGNATURE")) {
    161      log_warn(LD_DIR, "Bad object type on %s signature", doctype);
    162      return -1;
    163    }
    164  }
    165 
    166  keysize = crypto_pk_keysize(pkey);
    167  signed_digest = tor_malloc(keysize);
    168  if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
    169                                tok->object_body, tok->object_size)
    170      < digest_len) {
    171    log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
    172    tor_free(signed_digest);
    173    return -1;
    174  }
    175  //  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
    176  //            hex_str(signed_digest,4));
    177  if (! signed_digest_equals((const uint8_t *)digest,
    178                             (const uint8_t *)signed_digest, digest_len)) {
    179    log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
    180    tor_free(signed_digest);
    181    return -1;
    182  }
    183  tor_free(signed_digest);
    184  return 0;
    185 }