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 */
9 * \brief Code to parse and validate detached-signature objects
12 #include "core/or/or.h"
13 #include "feature/dirparse/parsecommon.h"
14 #include "feature/dirparse/unparseable.h"
15 #include "feature/nodelist/networkstatus.h"
16 #include "lib/memarea/memarea.h"
18 #include "feature/dirauth/dsigs_parse.h"
19 #include "feature/dirauth/ns_detached_signatures_st.h"
20 #include "feature/nodelist/document_signature_st.h"
22 /** List of tokens recognized in detached networkstatus signature documents. */
23 static token_rule_t networkstatus_detached_signature_token_table
[] = {
24 T1_START("consensus-digest", K_CONSENSUS_DIGEST
, GE(1), NO_OBJ
),
25 T("additional-digest", K_ADDITIONAL_DIGEST
,GE(3), NO_OBJ
),
26 T1("valid-after", K_VALID_AFTER
, CONCAT_ARGS
, NO_OBJ
),
27 T1("fresh-until", K_FRESH_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
28 T1("valid-until", K_VALID_UNTIL
, CONCAT_ARGS
, NO_OBJ
),
29 T("additional-signature", K_ADDITIONAL_SIGNATURE
, GE(4), NEED_OBJ
),
30 T1N("directory-signature", K_DIRECTORY_SIGNATURE
, GE(2), NEED_OBJ
),
34 /** Return the common_digests_t that holds the digests of the
35 * <b>flavor_name</b>-flavored networkstatus according to the detached
36 * signatures document <b>sigs</b>, allocating a new common_digests_t as
38 static common_digests_t
*
39 detached_get_digests(ns_detached_signatures_t
*sigs
, const char *flavor_name
)
41 common_digests_t
*d
= strmap_get(sigs
->digests
, flavor_name
);
43 d
= tor_malloc_zero(sizeof(common_digests_t
));
44 strmap_set(sigs
->digests
, flavor_name
, d
);
49 /** Return the list of signatures of the <b>flavor_name</b>-flavored
50 * networkstatus according to the detached signatures document <b>sigs</b>,
51 * allocating a new common_digests_t as needed. */
53 detached_get_signatures(ns_detached_signatures_t
*sigs
,
54 const char *flavor_name
)
56 smartlist_t
*sl
= strmap_get(sigs
->signatures
, flavor_name
);
59 strmap_set(sigs
->signatures
, flavor_name
, sl
);
64 /** Parse a detached v3 networkstatus signature document between <b>s</b> and
65 * <b>eos</b> and return the result. Return -1 on failure. */
66 ns_detached_signatures_t
*
67 networkstatus_parse_detached_signatures(const char *s
, const char *eos
)
69 /* XXXX there is too much duplicate shared between this function and
70 * networkstatus_parse_vote_from_string(). */
71 directory_token_t
*tok
;
72 memarea_t
*area
= NULL
;
73 common_digests_t
*digests
;
75 smartlist_t
*tokens
= smartlist_new();
76 ns_detached_signatures_t
*sigs
=
77 tor_malloc_zero(sizeof(ns_detached_signatures_t
));
78 sigs
->digests
= strmap_new();
79 sigs
->signatures
= strmap_new();
85 if (tokenize_string(area
,s
, eos
, tokens
,
86 networkstatus_detached_signature_token_table
, 0)) {
87 log_warn(LD_DIR
, "Error tokenizing detached networkstatus signatures");
91 /* Grab all the digest-like tokens. */
92 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, _tok
) {
94 digest_algorithm_t alg
;
96 const char *hexdigest
;
97 size_t expected_length
, digest_length
;
101 if (tok
->tp
== K_CONSENSUS_DIGEST
) {
105 hexdigest
= tok
->args
[0];
106 } else if (tok
->tp
== K_ADDITIONAL_DIGEST
) {
107 int a
= crypto_digest_algorithm_parse_name(tok
->args
[1]);
109 log_warn(LD_DIR
, "Unrecognized algorithm name %s", tok
->args
[0]);
112 alg
= (digest_algorithm_t
) a
;
113 flavor
= tok
->args
[0];
114 algname
= tok
->args
[1];
115 hexdigest
= tok
->args
[2];
120 digest_length
= crypto_digest_algorithm_get_length(alg
);
121 expected_length
= digest_length
* 2; /* hex encoding */
123 if (strlen(hexdigest
) != expected_length
) {
124 log_warn(LD_DIR
, "Wrong length on consensus-digest in detached "
125 "networkstatus signatures");
128 digests
= detached_get_digests(sigs
, flavor
);
130 if (!fast_mem_is_zero(digests
->d
[alg
], digest_length
)) {
131 log_warn(LD_DIR
, "Multiple digests for %s with %s on detached "
132 "signatures document", flavor
, algname
);
135 if (base16_decode(digests
->d
[alg
], digest_length
,
136 hexdigest
, strlen(hexdigest
)) != (int) digest_length
) {
137 log_warn(LD_DIR
, "Bad encoding on consensus-digest in detached "
138 "networkstatus signatures");
141 } SMARTLIST_FOREACH_END(_tok
);
143 tok
= find_by_keyword(tokens
, K_VALID_AFTER
);
144 if (parse_iso_time(tok
->args
[0], &sigs
->valid_after
)) {
145 log_warn(LD_DIR
, "Bad valid-after in detached networkstatus signatures");
149 tok
= find_by_keyword(tokens
, K_FRESH_UNTIL
);
150 if (parse_iso_time(tok
->args
[0], &sigs
->fresh_until
)) {
151 log_warn(LD_DIR
, "Bad fresh-until in detached networkstatus signatures");
155 tok
= find_by_keyword(tokens
, K_VALID_UNTIL
);
156 if (parse_iso_time(tok
->args
[0], &sigs
->valid_until
)) {
157 log_warn(LD_DIR
, "Bad valid-until in detached networkstatus signatures");
161 SMARTLIST_FOREACH_BEGIN(tokens
, directory_token_t
*, _tok
) {
162 const char *id_hexdigest
;
163 const char *sk_hexdigest
;
166 digest_algorithm_t alg
;
168 char id_digest
[DIGEST_LEN
];
169 char sk_digest
[DIGEST_LEN
];
170 smartlist_t
*siglist
;
171 document_signature_t
*sig
;
175 if (tok
->tp
== K_DIRECTORY_SIGNATURE
) {
176 tor_assert(tok
->n_args
>= 2);
179 id_hexdigest
= tok
->args
[0];
180 sk_hexdigest
= tok
->args
[1];
181 } else if (tok
->tp
== K_ADDITIONAL_SIGNATURE
) {
182 tor_assert(tok
->n_args
>= 4);
183 flavor
= tok
->args
[0];
184 algname
= tok
->args
[1];
185 id_hexdigest
= tok
->args
[2];
186 sk_hexdigest
= tok
->args
[3];
192 int a
= crypto_digest_algorithm_parse_name(algname
);
194 log_warn(LD_DIR
, "Unrecognized algorithm name %s", algname
);
197 alg
= (digest_algorithm_t
) a
;
200 if (!tok
->object_type
||
201 strcmp(tok
->object_type
, "SIGNATURE") ||
202 tok
->object_size
< 128 || tok
->object_size
> 512) {
203 log_warn(LD_DIR
, "Bad object type or length on directory-signature");
207 if (strlen(id_hexdigest
) != HEX_DIGEST_LEN
||
208 base16_decode(id_digest
, sizeof(id_digest
),
209 id_hexdigest
, HEX_DIGEST_LEN
) != sizeof(id_digest
)) {
210 log_warn(LD_DIR
, "Error decoding declared identity %s in "
211 "network-status vote.", escaped(id_hexdigest
));
214 if (strlen(sk_hexdigest
) != HEX_DIGEST_LEN
||
215 base16_decode(sk_digest
, sizeof(sk_digest
),
216 sk_hexdigest
, HEX_DIGEST_LEN
) != sizeof(sk_digest
)) {
217 log_warn(LD_DIR
, "Error decoding declared signing key digest %s in "
218 "network-status vote.", escaped(sk_hexdigest
));
222 siglist
= detached_get_signatures(sigs
, flavor
);
224 SMARTLIST_FOREACH(siglist
, document_signature_t
*, dsig
, {
225 if (dsig
->alg
== alg
&&
226 tor_memeq(id_digest
, dsig
->identity_digest
, DIGEST_LEN
) &&
227 tor_memeq(sk_digest
, dsig
->signing_key_digest
, DIGEST_LEN
)) {
232 log_warn(LD_DIR
, "Two signatures with identical keys and algorithm "
237 sig
= tor_malloc_zero(sizeof(document_signature_t
));
239 memcpy(sig
->identity_digest
, id_digest
, DIGEST_LEN
);
240 memcpy(sig
->signing_key_digest
, sk_digest
, DIGEST_LEN
);
241 if (tok
->object_size
>= INT_MAX
|| tok
->object_size
>= SIZE_T_CEILING
) {
245 sig
->signature
= tor_memdup(tok
->object_body
, tok
->object_size
);
246 sig
->signature_len
= (int) tok
->object_size
;
248 smartlist_add(siglist
, sig
);
249 } SMARTLIST_FOREACH_END(_tok
);
253 ns_detached_signatures_free(sigs
);
256 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
257 smartlist_free(tokens
);
259 DUMP_AREA(area
, "detached signatures");
260 memarea_drop_all(area
);
265 /** Release all storage held in <b>s</b>. */
267 ns_detached_signatures_free_(ns_detached_signatures_t
*s
)
272 STRMAP_FOREACH(s
->signatures
, flavor
, smartlist_t
*, sigs
) {
273 SMARTLIST_FOREACH(sigs
, document_signature_t
*, sig
,
274 document_signature_free(sig
));
275 smartlist_free(sigs
);
276 } STRMAP_FOREACH_END
;
277 strmap_free(s
->signatures
, NULL
);
278 strmap_free(s
->digests
, tor_free_
);