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-2018, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
7 #include "core/or/or.h"
8 #include "feature/dirparse/authcert_parse.h"
9 #include "feature/dirparse/parsecommon.h"
10 #include "feature/dirparse/sigcommon.h"
11 #include "feature/dirparse/unparseable.h"
12 #include "feature/nodelist/authcert.h"
13 #include "lib/memarea/memarea.h"
15 #include "feature/nodelist/authority_cert_st.h"
17 /** List of tokens recognized in V3 authority certificates. */
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
),
24 /** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
25 * the first character after the certificate. */
27 authority_cert_parse_from_string(const char *s
, const char **end_of_string
)
29 /** Reject any certificate at least this big; it is probably an overflow, an
30 * attack, a bug, or some other nonsense. */
31 #define MAX_CERT_SIZE (128*1024)
33 authority_cert_t
*cert
= NULL
, *old_cert
;
34 smartlist_t
*tokens
= NULL
;
35 char digest
[DIGEST_LEN
];
36 directory_token_t
*tok
;
37 char fp_declared
[DIGEST_LEN
];
41 memarea_t
*area
= NULL
;
42 const char *s_dup
= s
;
44 s
= eat_whitespace(s
);
45 eos
= strstr(s
, "\ndir-key-certification");
47 log_warn(LD_DIR
, "No signature found on key certificate");
50 eos
= strstr(eos
, "\n-----END SIGNATURE-----\n");
52 log_warn(LD_DIR
, "No end-of-signature found on key certificate");
55 eos
= strchr(eos
+2, '\n');
60 if (len
> MAX_CERT_SIZE
) {
61 log_warn(LD_DIR
, "Certificate is far too big (at %lu bytes long); "
62 "rejecting", (unsigned long)len
);
66 tokens
= smartlist_new();
68 if (tokenize_string(area
,s
, eos
, tokens
, dir_key_certificate_table
, 0) < 0) {
69 log_warn(LD_DIR
, "Error tokenizing key certificate");
72 if (router_get_hash_impl(s
, strlen(s
), digest
, "dir-key-certificate-version",
73 "\ndir-key-certification", '\n', DIGEST_SHA1
) < 0)
75 tok
= smartlist_get(tokens
, 0);
76 if (tok
->tp
!= K_DIR_KEY_CERTIFICATE_VERSION
|| strcmp(tok
->args
[0], "3")) {
78 "Key certificate does not begin with a recognized version (3).");
82 cert
= tor_malloc_zero(sizeof(authority_cert_t
));
83 memcpy(cert
->cache_info
.signed_descriptor_digest
, digest
, DIGEST_LEN
);
85 tok
= find_by_keyword(tokens
, K_DIR_SIGNING_KEY
);
87 cert
->signing_key
= tok
->key
;
89 if (crypto_pk_get_digest(cert
->signing_key
, cert
->signing_key_digest
))
92 tok
= find_by_keyword(tokens
, K_DIR_IDENTITY_KEY
);
94 cert
->identity_key
= tok
->key
;
97 tok
= find_by_keyword(tokens
, K_FINGERPRINT
);
98 tor_assert(tok
->n_args
);
99 if (base16_decode(fp_declared
, DIGEST_LEN
, tok
->args
[0],
100 strlen(tok
->args
[0])) != DIGEST_LEN
) {
101 log_warn(LD_DIR
, "Couldn't decode key certificate fingerprint %s",
102 escaped(tok
->args
[0]));
106 if (crypto_pk_get_digest(cert
->identity_key
,
107 cert
->cache_info
.identity_digest
))
110 if (tor_memneq(cert
->cache_info
.identity_digest
, fp_declared
, DIGEST_LEN
)) {
111 log_warn(LD_DIR
, "Digest of certificate key didn't match declared "
116 tok
= find_opt_by_keyword(tokens
, K_DIR_ADDRESS
);
119 char *address
= NULL
;
120 tor_assert(tok
->n_args
);
121 /* XXX++ use some tor_addr parse function below instead. -RD */
122 if (tor_addr_port_split(LOG_WARN
, tok
->args
[0], &address
,
123 &cert
->dir_port
) < 0 ||
124 tor_inet_aton(address
, &in
) == 0) {
125 log_warn(LD_DIR
, "Couldn't parse dir-address in certificate");
129 cert
->addr
= ntohl(in
.s_addr
);
133 tok
= find_by_keyword(tokens
, K_DIR_KEY_PUBLISHED
);
134 if (parse_iso_time(tok
->args
[0], &cert
->cache_info
.published_on
) < 0) {
137 tok
= find_by_keyword(tokens
, K_DIR_KEY_EXPIRES
);
138 if (parse_iso_time(tok
->args
[0], &cert
->expires
) < 0) {
142 tok
= smartlist_get(tokens
, smartlist_len(tokens
)-1);
143 if (tok
->tp
!= K_DIR_KEY_CERTIFICATION
) {
144 log_warn(LD_DIR
, "Certificate didn't end with dir-key-certification.");
148 /* If we already have this cert, don't bother checking the signature. */
149 old_cert
= authority_cert_get_by_digests(
150 cert
->cache_info
.identity_digest
,
151 cert
->signing_key_digest
);
154 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
156 if (old_cert
->cache_info
.signed_descriptor_len
== len
&&
157 old_cert
->cache_info
.signed_descriptor_body
&&
158 tor_memeq(s
, old_cert
->cache_info
.signed_descriptor_body
, len
)) {
159 log_debug(LD_DIR
, "We already checked the signature on this "
160 "certificate; no need to do so again.");
165 if (check_signature_token(digest
, DIGEST_LEN
, tok
, cert
->identity_key
, 0,
166 "key certificate")) {
170 tok
= find_by_keyword(tokens
, K_DIR_KEY_CROSSCERT
);
171 if (check_signature_token(cert
->cache_info
.identity_digest
,
175 CST_NO_CHECK_OBJTYPE
,
176 "key cross-certification")) {
181 cert
->cache_info
.signed_descriptor_len
= len
;
182 cert
->cache_info
.signed_descriptor_body
= tor_malloc(len
+1);
183 memcpy(cert
->cache_info
.signed_descriptor_body
, s
, len
);
184 cert
->cache_info
.signed_descriptor_body
[len
] = 0;
185 cert
->cache_info
.saved_location
= SAVED_NOWHERE
;
188 *end_of_string
= eat_whitespace(eos
);
190 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
191 smartlist_free(tokens
);
193 DUMP_AREA(area
, "authority cert");
194 memarea_drop_all(area
);
198 dump_desc(s_dup
, "authority cert");
199 authority_cert_free(cert
);
200 SMARTLIST_FOREACH(tokens
, directory_token_t
*, t
, token_clear(t
));
201 smartlist_free(tokens
);
203 DUMP_AREA(area
, "authority cert");
204 memarea_drop_all(area
);