tor  0.4.2.0-alpha-dev
authcert_parse.c
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-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
7 #include "core/or/or.h"
13 #include "lib/memarea/memarea.h"
14 
15 #include "feature/nodelist/authority_cert_st.h"
16 
18 static token_rule_t dir_key_certificate_table[] = {
19 #include "feature/dirparse/authcert_members.i"
20  T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
22 };
23 
27 authority_cert_parse_from_string(const char *s, size_t maxlen,
28  const char **end_of_string)
29 {
32 #define MAX_CERT_SIZE (128*1024)
33 
34  authority_cert_t *cert = NULL, *old_cert;
35  smartlist_t *tokens = NULL;
36  char digest[DIGEST_LEN];
37  directory_token_t *tok;
38  char fp_declared[DIGEST_LEN];
39  const char *eos;
40  size_t len;
41  int found;
42  memarea_t *area = NULL;
43  const char *end_of_s = s + maxlen;
44  const char *s_dup = s;
45 
46  s = eat_whitespace_eos(s, end_of_s);
47  eos = tor_memstr(s, end_of_s - s, "\ndir-key-certification");
48  if (! eos) {
49  log_warn(LD_DIR, "No signature found on key certificate");
50  return NULL;
51  }
52  eos = tor_memstr(eos, end_of_s - eos, "\n-----END SIGNATURE-----\n");
53  if (! eos) {
54  log_warn(LD_DIR, "No end-of-signature found on key certificate");
55  return NULL;
56  }
57  eos = memchr(eos+2, '\n', end_of_s - (eos+2));
58  tor_assert(eos);
59  ++eos;
60  len = eos - s;
61 
62  if (len > MAX_CERT_SIZE) {
63  log_warn(LD_DIR, "Certificate is far too big (at %lu bytes long); "
64  "rejecting", (unsigned long)len);
65  return NULL;
66  }
67 
68  tokens = smartlist_new();
69  area = memarea_new();
70  if (tokenize_string(area,s, eos, tokens, dir_key_certificate_table, 0) < 0) {
71  log_warn(LD_DIR, "Error tokenizing key certificate");
72  goto err;
73  }
74  if (router_get_hash_impl(s, eos - s, digest, "dir-key-certificate-version",
75  "\ndir-key-certification", '\n', DIGEST_SHA1) < 0)
76  goto err;
77  tok = smartlist_get(tokens, 0);
78  if (tok->tp != K_DIR_KEY_CERTIFICATE_VERSION || strcmp(tok->args[0], "3")) {
79  log_warn(LD_DIR,
80  "Key certificate does not begin with a recognized version (3).");
81  goto err;
82  }
83 
84  cert = tor_malloc_zero(sizeof(authority_cert_t));
85  memcpy(cert->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
86 
87  tok = find_by_keyword(tokens, K_DIR_SIGNING_KEY);
88  tor_assert(tok->key);
89  cert->signing_key = tok->key;
90  tok->key = NULL;
92  goto err;
93 
94  tok = find_by_keyword(tokens, K_DIR_IDENTITY_KEY);
95  tor_assert(tok->key);
96  cert->identity_key = tok->key;
97  tok->key = NULL;
98 
99  tok = find_by_keyword(tokens, K_FINGERPRINT);
100  tor_assert(tok->n_args);
101  if (base16_decode(fp_declared, DIGEST_LEN, tok->args[0],
102  strlen(tok->args[0])) != DIGEST_LEN) {
103  log_warn(LD_DIR, "Couldn't decode key certificate fingerprint %s",
104  escaped(tok->args[0]));
105  goto err;
106  }
107 
110  goto err;
111 
112  if (tor_memneq(cert->cache_info.identity_digest, fp_declared, DIGEST_LEN)) {
113  log_warn(LD_DIR, "Digest of certificate key didn't match declared "
114  "fingerprint");
115  goto err;
116  }
117 
118  tok = find_opt_by_keyword(tokens, K_DIR_ADDRESS);
119  if (tok) {
120  struct in_addr in;
121  char *address = NULL;
122  tor_assert(tok->n_args);
123  /* XXX++ use some tor_addr parse function below instead. -RD */
124  if (tor_addr_port_split(LOG_WARN, tok->args[0], &address,
125  &cert->dir_port) < 0 ||
126  tor_inet_aton(address, &in) == 0) {
127  log_warn(LD_DIR, "Couldn't parse dir-address in certificate");
128  tor_free(address);
129  goto err;
130  }
131  cert->addr = ntohl(in.s_addr);
132  tor_free(address);
133  }
134 
135  tok = find_by_keyword(tokens, K_DIR_KEY_PUBLISHED);
136  if (parse_iso_time(tok->args[0], &cert->cache_info.published_on) < 0) {
137  goto err;
138  }
139  tok = find_by_keyword(tokens, K_DIR_KEY_EXPIRES);
140  if (parse_iso_time(tok->args[0], &cert->expires) < 0) {
141  goto err;
142  }
143 
144  tok = smartlist_get(tokens, smartlist_len(tokens)-1);
145  if (tok->tp != K_DIR_KEY_CERTIFICATION) {
146  log_warn(LD_DIR, "Certificate didn't end with dir-key-certification.");
147  goto err;
148  }
149 
150  /* If we already have this cert, don't bother checking the signature. */
153  cert->signing_key_digest);
154  found = 0;
155  if (old_cert) {
156  /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
157  * buy us much. */
158  if (old_cert->cache_info.signed_descriptor_len == len &&
159  old_cert->cache_info.signed_descriptor_body &&
160  tor_memeq(s, old_cert->cache_info.signed_descriptor_body, len)) {
161  log_debug(LD_DIR, "We already checked the signature on this "
162  "certificate; no need to do so again.");
163  found = 1;
164  }
165  }
166  if (!found) {
167  if (check_signature_token(digest, DIGEST_LEN, tok, cert->identity_key, 0,
168  "key certificate")) {
169  goto err;
170  }
171 
172  tok = find_by_keyword(tokens, K_DIR_KEY_CROSSCERT);
174  DIGEST_LEN,
175  tok,
176  cert->signing_key,
177  CST_NO_CHECK_OBJTYPE,
178  "key cross-certification")) {
179  goto err;
180  }
181  }
182 
183  cert->cache_info.signed_descriptor_len = len;
184  cert->cache_info.signed_descriptor_body = tor_malloc(len+1);
185  memcpy(cert->cache_info.signed_descriptor_body, s, len);
186  cert->cache_info.signed_descriptor_body[len] = 0;
188 
189  if (end_of_string) {
190  *end_of_string = eat_whitespace(eos);
191  }
193  smartlist_free(tokens);
194  if (area) {
195  DUMP_AREA(area, "authority cert");
196  memarea_drop_all(area);
197  }
198  return cert;
199  err:
200  dump_desc(s_dup, "authority cert");
201  authority_cert_free(cert);
203  smartlist_free(tokens);
204  if (area) {
205  DUMP_AREA(area, "authority cert");
206  memarea_drop_all(area);
207  }
208  return NULL;
209 }
struct crypto_pk_t * key
Definition: parsecommon.h:210
#define END_OF_TABLE
Definition: parsecommon.h:244
saved_location_t saved_location
Header file for authcert.c.
int tor_inet_aton(const char *str, struct in_addr *addr)
Definition: inaddr.c:38
char signed_descriptor_digest[DIGEST_LEN]
#define tor_free(p)
Definition: malloc.h:52
signed_descriptor_t cache_info
memarea_t * memarea_new(void)
Definition: memarea.c:153
crypto_pk_t * identity_key
Header file for unparseable.c.
tor_assert(buffer)
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
directory_keyword tp
Definition: parsecommon.h:202
#define DIGEST_LEN
Definition: digest_sizes.h:20
Master header file for Tor-specific functionality.
const char * eat_whitespace(const char *s)
Definition: util_string.c:268
Header for memarea.c.
char signing_key_digest[DIGEST_LEN]
crypto_pk_t * signing_key
#define LOG_WARN
Definition: log.h:51
Header file for authcert_parse.c.
authority_cert_t * authority_cert_parse_from_string(const char *s, size_t maxlen, const char **end_of_string)
#define CONCAT_ARGS
Definition: parsecommon.h:267
directory_token_t * find_opt_by_keyword(const smartlist_t *s, directory_keyword keyword)
Definition: parsecommon.c:450
#define LD_DIR
Definition: log.h:86
authority_cert_t * authority_cert_get_by_digests(const char *id_digest, const char *sk_digest)
Definition: authcert.c:650
Header file for parsecommon.c.
char identity_digest[DIGEST_LEN]
int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
Definition: crypto_rsa.c:356
#define SMARTLIST_FOREACH(sl, type, var, cmd)
const char * escaped(const char *s)
Definition: escape.c:126
#define T1(s, t, a, o)
Definition: parsecommon.h:250
void token_clear(directory_token_t *tok)
Definition: parsecommon.c:41
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:506
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 parse_iso_time(const char *cp, time_t *t)
Definition: time_fmt.c:392
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:143
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
Header file for sigcommon.c.
const char * eat_whitespace_eos(const char *s, const char *eos)
Definition: util_string.c:295
int tor_addr_port_split(int severity, const char *addrport, char **address_out, uint16_t *port_out)
Definition: address.c:1818