authcert_parse.c (7165B)
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" 13 #include "feature/dirparse/authcert_parse.h" 14 #include "feature/dirparse/parsecommon.h" 15 #include "feature/dirparse/sigcommon.h" 16 #include "feature/dirparse/unparseable.h" 17 #include "feature/nodelist/authcert.h" 18 #include "lib/memarea/memarea.h" 19 20 #include "feature/nodelist/authority_cert_st.h" 21 #include "feature/dirparse/authcert_members.h" 22 23 /** List of tokens recognized in V3 authority certificates. */ 24 // clang-format off 25 static token_rule_t dir_key_certificate_table[] = { 26 AUTHCERT_MEMBERS, 27 T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ), 28 END_OF_TABLE 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. */ 34 authority_cert_t * 35 authority_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]; 45 directory_token_t *tok; 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; 99 if (crypto_pk_get_digest(cert->signing_key, cert->signing_key_digest)) 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 116 if (crypto_pk_get_digest(cert->identity_key, 117 cert->cache_info.identity_digest)) 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. */ 159 old_cert = authority_cert_get_by_digests( 160 cert->cache_info.identity_digest, 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); 181 if (check_signature_token(cert->cache_info.identity_digest, 182 DIGEST_LEN, 183 tok, 184 cert->signing_key, 185 CST_NO_CHECK_OBJTYPE, 186 "key cross-certification")) { 187 goto err; 188 } 189 } 190 191 cert->cache_info.signed_descriptor_len = len; 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; 195 cert->cache_info.saved_location = SAVED_NOWHERE; 196 197 if (end_of_string) { 198 *end_of_string = eat_whitespace(eos); 199 } 200 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); 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); 210 SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); 211 smartlist_free(tokens); 212 if (area) { 213 DUMP_AREA(area, "authority cert"); 214 memarea_drop_all(area); 215 } 216 return NULL; 217 }