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 : }
|