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 */
8 * @file authcert_parse.c
9 * @brief Authority certificate parsing.
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"
20 #include "feature/nodelist/authority_cert_st.h"
21 #include "feature/dirparse/authcert_members.h"
23 /** List of tokens recognized in V3 authority certificates. */
25 static token_rule_t dir_key_certificate_table
[] = {
27 T1("fingerprint", K_FINGERPRINT
, CONCAT_ARGS
, NO_OBJ
),
32 /** Parse a key certificate from <b>s</b>; point <b>end-of-string</b> to
33 * the first character after the certificate. */
35 authority_cert_parse_from_string(const char *s
, size_t maxlen
,
36 const char **end_of_string
)
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)
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
];
50 memarea_t
*area
= NULL
;
51 const char *end_of_s
= s
+ maxlen
;
52 const char *s_dup
= s
;
54 s
= eat_whitespace_eos(s
, end_of_s
);
55 eos
= tor_memstr(s
, end_of_s
- s
, "\ndir-key-certification");
57 log_warn(LD_DIR
, "No signature found on key certificate");
60 eos
= tor_memstr(eos
, end_of_s
- eos
, "\n-----END SIGNATURE-----\n");
62 log_warn(LD_DIR
, "No end-of-signature found on key certificate");
65 eos
= memchr(eos
+2, '\n', end_of_s
- (eos
+2));
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
);
76 tokens
= smartlist_new();
78 if (tokenize_string(area
,s
, eos
, tokens
, dir_key_certificate_table
, 0) < 0) {
79 log_warn(LD_DIR
, "Error tokenizing key certificate");
82 if (router_get_hash_impl(s
, eos
- s
, digest
, "dir-key-certificate-version",
83 "\ndir-key-certification", '\n', DIGEST_SHA1
) < 0)
85 tok
= smartlist_get(tokens
, 0);
86 if (tok
->tp
!= K_DIR_KEY_CERTIFICATE_VERSION
|| strcmp(tok
->args
[0], "3")) {
88 "Key certificate does not begin with a recognized version (3).");
92 cert
= tor_malloc_zero(sizeof(authority_cert_t
));
93 memcpy(cert
->cache_info
.signed_descriptor_digest
, digest
, DIGEST_LEN
);
95 tok
= find_by_keyword(tokens
, K_DIR_SIGNING_KEY
);
97 cert
->signing_key
= tok
->key
;
99 if (crypto_pk_get_digest(cert
->signing_key
, cert
->signing_key_digest
))
102 tok
= find_by_keyword(tokens
, K_DIR_IDENTITY_KEY
);
103 tor_assert(tok
->key
);
104 cert
->identity_key
= tok
->key
;
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]));
116 if (crypto_pk_get_digest(cert
->identity_key
,
117 cert
->cache_info
.identity_digest
))
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 "
126 tok
= find_opt_by_keyword(tokens
, K_DIR_ADDRESS
);
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");
139 tor_addr_from_in(&cert
->ipv4_addr
, &in
);
143 tok
= find_by_keyword(tokens
, K_DIR_KEY_PUBLISHED
);
144 if (parse_iso_time(tok
->args
[0], &cert
->cache_info
.published_on
) < 0) {
147 tok
= find_by_keyword(tokens
, K_DIR_KEY_EXPIRES
);
148 if (parse_iso_time(tok
->args
[0], &cert
->expires
) < 0) {
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.");
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
);
164 /* XXXX We could just compare signed_descriptor_digest, but that wouldn't
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.");
175 if (check_signature_token(digest
, DIGEST_LEN
, tok
, cert
->identity_key
, 0,
176 "key certificate")) {
180 tok
= find_by_keyword(tokens
, K_DIR_KEY_CROSSCERT
);
181 if (check_signature_token(cert
->cache_info
.identity_digest
,
185 CST_NO_CHECK_OBJTYPE
,
186 "key cross-certification")) {
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
;
198 *end_of_string
= eat_whitespace(eos
);
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
);
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
);
213 DUMP_AREA(area
, "authority cert");
214 memarea_drop_all(area
);