Tor 0.4.9.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 */
26int
27router_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 */
73int
74router_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. */
91router_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. */
111int
112router_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
129MOCK_IMPL(STATIC int,
130signed_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 */
142MOCK_IMPL(int,
143check_signature_token,(const char *digest,
144 ssize_t digest_len,
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:56
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:103