Tor  0.4.7.0-alpha-dev
sigcommon.c
Go to the documentation of this file.
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"
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,
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,
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 }
int crypto_common_digests(common_digests_t *ds_out, const char *m, size_t len)
Definition: crypto_digest.c:30
digest_algorithm_t
Definition: crypto_digest.h:44
int crypto_digest256(char *digest, const char *m, size_t len, digest_algorithm_t algorithm)
int crypto_digest(char *digest, const char *m, size_t len)
size_t crypto_pk_keysize(const crypto_pk_t *env)
int crypto_pk_public_checksig(const crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen)
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_BUG
Definition: log.h:86
#define LD_DIR
Definition: log.h:88
#define LOG_WARN
Definition: log.h:53
#define tor_free(p)
Definition: malloc.h:52
Master header file for Tor-specific functionality.
Header file for parsecommon.c.
STATIC int router_compute_hash_final(char *digest, const char *start, size_t len, digest_algorithm_t alg)
Definition: sigcommon.c:93
int check_signature_token(const char *digest, ssize_t digest_len, directory_token_t *tok, crypto_pk_t *pkey, int flags, const char *doctype)
Definition: sigcommon.c:148
int router_get_hash_impl_helper(const char *s, size_t s_len, const char *start_str, const char *end_str, char end_c, int log_severity, const char **start_out, const char **end_out)
Definition: sigcommon.c:27
int router_get_hash_impl(const char *s, size_t s_len, char *digest, const char *start_str, const char *end_str, char end_c, digest_algorithm_t alg)
Definition: sigcommon.c:74
int router_get_hashes_impl(const char *s, size_t s_len, common_digests_t *digests, const char *start_str, const char *end_str, char end_c)
Definition: sigcommon.c:112
Header file for sigcommon.c.
#define STATIC
Definition: testsupport.h:32
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define tor_assert(expr)
Definition: util_bug.h:102