LCOV - code coverage report
Current view: top level - feature/dirparse - sigcommon.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 55 67 82.1 %
Date: 2021-11-24 03:28:48 Functions: 6 6 100.0 %

          Line data    Source code
       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        6467 : 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        6467 :   const char *start, *end;
      34        6467 :   start = tor_memstr(s, s_len, start_str);
      35        6467 :   if (!start) {
      36         139 :     log_fn(log_severity,LD_DIR,
      37             :            "couldn't find start of hashed material \"%s\"",start_str);
      38         139 :     return -1;
      39             :   }
      40        6328 :   if (start != s && *(start-1) != '\n') {
      41          43 :     log_fn(log_severity,LD_DIR,
      42             :              "first occurrence of \"%s\" is not at the start of a line",
      43             :              start_str);
      44          43 :     return -1;
      45             :   }
      46       12570 :   end = tor_memstr(start+strlen(start_str),
      47        6285 :                    s_len - (start-s) - strlen(start_str), end_str);
      48        6285 :   if (!end) {
      49          98 :     log_fn(log_severity,LD_DIR,
      50             :            "couldn't find end of hashed material \"%s\"",end_str);
      51          98 :     return -1;
      52             :   }
      53        6187 :   end = memchr(end+strlen(end_str), end_c, s_len - (end-s) - strlen(end_str));
      54        6187 :   if (!end) {
      55           3 :     log_fn(log_severity,LD_DIR,
      56             :            "couldn't find EOL");
      57           3 :     return -1;
      58             :   }
      59        6184 :   ++end;
      60             : 
      61        6184 :   *start_out = start;
      62        6184 :   *end_out = end;
      63        6184 :   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         956 : 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         956 :   const char *start=NULL, *end=NULL;
      80         956 :   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         955 :   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         377 : 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         377 :   if (alg == DIGEST_SHA1) {
      96         377 :     if (crypto_digest(digest, start, len) < 0) {
      97           0 :       log_warn(LD_BUG,"couldn't compute digest");
      98           0 :       return -1;
      99             :     }
     100             :   } else {
     101           0 :     if (crypto_digest256(digest, start, len, alg) < 0) {
     102           0 :       log_warn(LD_BUG,"couldn't compute digest");
     103           0 :       return -1;
     104             :     }
     105             :   }
     106             : 
     107             :   return 0;
     108             : }
     109             : 
     110             : /** As router_get_hash_impl, but compute all hashes. */
     111             : int
     112        2500 : 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        2500 :   const char *start=NULL, *end=NULL;
     117        2500 :   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        2464 :   if (crypto_common_digests(digests, start, end-start)) {
     122           0 :     log_warn(LD_BUG,"couldn't compute digests");
     123           0 :     return -1;
     124             :   }
     125             : 
     126             :   return 0;
     127             : }
     128             : 
     129         332 : MOCK_IMPL(STATIC int,
     130             : signed_digest_equals, (const uint8_t *d1, const uint8_t *d2, size_t len))
     131             : {
     132         332 :   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         942 : 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         942 :   char *signed_digest;
     151         942 :   size_t keysize;
     152         942 :   const int check_objtype = ! (flags & CST_NO_CHECK_OBJTYPE);
     153             : 
     154         942 :   tor_assert(pkey);
     155         942 :   tor_assert(tok);
     156         942 :   tor_assert(digest);
     157         942 :   tor_assert(doctype);
     158             : 
     159         942 :   if (check_objtype) {
     160         537 :     if (strcmp(tok->object_type, "SIGNATURE")) {
     161           0 :       log_warn(LD_DIR, "Bad object type on %s signature", doctype);
     162           0 :       return -1;
     163             :     }
     164             :   }
     165             : 
     166         942 :   keysize = crypto_pk_keysize(pkey);
     167         942 :   signed_digest = tor_malloc(keysize);
     168         942 :   if (crypto_pk_public_checksig(pkey, signed_digest, keysize,
     169         942 :                                 tok->object_body, tok->object_size)
     170             :       < digest_len) {
     171           3 :     log_warn(LD_DIR, "Error reading %s: invalid signature.", doctype);
     172           3 :     tor_free(signed_digest);
     173           3 :     return -1;
     174             :   }
     175             :   //  log_debug(LD_DIR,"Signed %s hash starts %s", doctype,
     176             :   //            hex_str(signed_digest,4));
     177         939 :   if (! signed_digest_equals((const uint8_t *)digest,
     178             :                              (const uint8_t *)signed_digest, digest_len)) {
     179           0 :     log_warn(LD_DIR, "Error reading %s: signature does not match.", doctype);
     180           0 :     tor_free(signed_digest);
     181           0 :     return -1;
     182             :   }
     183         939 :   tor_free(signed_digest);
     184         939 :   return 0;
     185             : }

Generated by: LCOV version 1.14