Tor 0.4.9.0-alpha-dev
authcert_parse.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 authcert_parse.c
9 * @brief Authority certificate parsing.
10 **/
11
12#include "core/or/or.h"
18#include "lib/memarea/memarea.h"
19
22
23/** List of tokens recognized in V3 authority certificates. */
24// clang-format off
26 AUTHCERT_MEMBERS,
27 T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
29};
30// clang-format on
31
32/** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
33 * the first character after the certificate. */
35authority_cert_parse_from_string(const char *s, size_t maxlen,
36 const char **end_of_string)
37{
38 /** Reject any certificate at least this big; it is probably an overflow, an
39 * attack, a bug, or some other nonsense. */
40#define MAX_CERT_SIZE (128*1024)
41
42 authority_cert_t *cert = NULL, *old_cert;
43 smartlist_t *tokens = NULL;
44 char digest[DIGEST_LEN];
46 char fp_declared[DIGEST_LEN];
47 const char *eos;
48 size_t len;
49 int found;
50 memarea_t *area = NULL;
51 const char *end_of_s = s + maxlen;
52 const char *s_dup = s;
53
54 s = eat_whitespace_eos(s, end_of_s);
55 eos = tor_memstr(s, end_of_s - s, "\ndir-key-certification");
56 if (! eos) {
57 log_warn(LD_DIR, "No signature found on key certificate");
58 return NULL;
59 }
60 eos = tor_memstr(eos, end_of_s - eos, "\n-----END SIGNATURE-----\n");
61 if (! eos) {
62 log_warn(LD_DIR, "No end-of-signature found on key certificate");
63 return NULL;
64 }
65 eos = memchr(eos+2, '\n', end_of_s - (eos+2));
66 tor_assert(eos);
67 ++eos;
68 len = eos - s;
69
70 if (len > MAX_CERT_SIZE) {
71 log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
72 "rejecting", (unsigned long)len);
73 return NULL;
74 }
75
76 tokens = smartlist_new();
77 area = memarea_new();
78 if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
79 log_warn(LD_DIR, "Error tokenizing key certificate");
80 goto err;
81 }
82 if (router_get_hash_impl(s, eos - s, digest, "dir-key-certificate-version",
83 "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
84 goto err;
85 tok = smartlist_get(tokens, 0);
86 if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
87 log_warn(LD_DIR,
88 "Key certificate does not begin with a recognized version (3).");
89 goto err;
90 }
91
92 cert = tor_malloc_zero(sizeof(authority_cert_t));
93 memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
94
95 tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
96 tor_assert(tok->key);
97 cert->signing_key = tok->key;
98 tok->key = NULL;
100 goto err;
101
102 tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
103 tor_assert(tok->key);
104 cert->identity_key = tok->key;
105 tok->key = NULL;
106
107 tok = find_by_keyword(tokens, K_FINGERPRINT);
108 tor_assert(tok->n_args);
109 if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
110 strlen(tok->args[0])) != DIGEST_LEN) {
111 log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
112 escaped(tok->args[0]));
113 goto err;
114 }
115
118 goto err;
119
120 if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
121 log_warn(LD_DIR, "Digest of certificate key didn't match declared "
122 "fingerprint");
123 goto err;
124 }
125
126 tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
127 if (tok) {
128 struct in_addr in;
129 char *address = NULL;
130 tor_assert(tok->n_args);
131 /* XXX++ use some tor_addr parse function below instead. -RD */
132 if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
133 &cert->ipv4_dirport) < 0 ||
134 tor_inet_aton(address, &in) == 0) {
135 log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
136 tor_free(address);
137 goto err;
138 }
139 tor_addr_from_in(&cert->ipv4_addr, &in);
140 tor_free(address);
141 }
142
143 tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
144 if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
145 goto err;
146 }
147 tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
148 if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
149 goto err;
150 }
151
152 tok = smartlist_get(tokens, smartlist_len(tokens)-1);
153 if (tok->tp != K_DIR_KEY_CERTIFICATION) {
154 log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
155 goto err;
156 }
157
158 /* If we already have this cert, don't bother checking the signature. */
161 cert->signing_key_digest);
162 found = 0;
163 if (old_cert) {
164 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
165 * buy us much. */
166 if (old_cert->cache_info.signed_descriptor_len == len &&
167 old_cert->cache_info.signed_descriptor_body &&
168 tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
169 log_debug(LD_DIR, "We already checked the signature on this "
170 "certificate; no need to do so again.");
171 found = 1;
172 }
173 }
174 if (!found) {
175 if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
176 "key certificate")) {
177 goto err;
178 }
179
180 tok = find_by_keyword(tokens, K_DIR_KEY_CROSSCERT);
183 tok,
184 cert->signing_key,
185 CST_NO_CHECK_OBJTYPE,
186 "key cross-certification")) {
187 goto err;
188 }
189 }
190
192 cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
193 memcpy(cert->cache_info.signed_descriptor_body, s, len);
194 cert->cache_info.signed_descriptor_body[len] = 0;
196
197 if (end_of_string) {
198 *end_of_string = eat_whitespace(eos);
199 }
201 smartlist_free(tokens);
202 if (area) {
203 DUMP_AREA(area, "authority cert");
204 memarea_drop_all(area);
205 }
206 return cert;
207 err:
208 dump_desc(s_dup, "authority cert");
209 authority_cert_free(cert);
211 smartlist_free(tokens);
212 if (area) {
213 DUMP_AREA(area, "authority cert");
214 memarea_drop_all(area);
215 }
216 return NULL;
217}
int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out)
Definition: address.c:1916
#define tor_addr_from_in(dest, in)
Definition: address.h:331
authority_cert_t * authority_cert_get_by_digests(const char *id_digest, const char *sk_digest)
Definition: authcert.c:648
Header file for authcert.c.
List of tokens common to V3 authority certificates and V3 consensuses.
static token_rule_t dir_key_certificate_table[]
authority_cert_t * authority_cert_parse_from_string(const char *s, size_t maxlen, const char **end_of_string)
Header file for authcert_parse.c.
Authority certificate structure.
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
Definition: crypto_rsa.c:356
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
const char * escaped(const char *s)
Definition: escape.c:126
int tor_inet_aton(const char *str, struct in_addr *addr)
Definition: inaddr.c:40
#define LD_DIR
Definition: log.h:88
#define LOG_WARN
Definition: log.h:53
#define tor_free(p)
Definition: malloc.h:56
memarea_t * memarea_new(void)
Definition: memarea.c:153
Header for memarea.c.
#define memarea_drop_all(area)
Definition: memarea.h:22
Master header file for Tor-specific functionality.
@ SAVED_NOWHERE
Definition: or.h:626
void token_clear(directory_token_t *tok)
Definition: parsecommon.c:41
int tokenize_string(memarea_t *area, const char *start, const char *end, smartlist_t *out, const token_rule_t *table, int flags)
Definition: parsecommon.c:53
directory_token_t * find_opt_by_keyword(const smartlist_t *s, directory_keyword keyword)
Definition: parsecommon.c:440
Header file for parsecommon.c.
@ NO_OBJ
Definition: parsecommon.h:221
#define CONCAT_ARGS
Definition: parsecommon.h:268
#define T1(s, t, a, o)
Definition: parsecommon.h:251
#define END_OF_TABLE
Definition: parsecommon.h:245
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(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
Header file for sigcommon.c.
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
crypto_pk_t * identity_key
crypto_pk_t * signing_key
char signing_key_digest[DIGEST_LEN]
signed_descriptor_t cache_info
directory_keyword tp
Definition: parsecommon.h:204
struct crypto_pk_t * key
Definition: parsecommon.h:212
char signed_descriptor_digest[DIGEST_LEN]
char identity_digest[DIGEST_LEN]
saved_location_t saved_location
int parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:423
void dump_desc(const char *desc, const char *type)
Definition: unparseable.c:496
Header file for unparseable.c.
#define tor_assert(expr)
Definition: util_bug.h:103
const char * eat_whitespace_eos(const char *s, const char *eos)
Definition: util_string.c:306
const char * eat_whitespace(const char *s)
Definition: util_string.c:279