mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-25 04:43:31 +01:00
Include a dir-signing-key token in directories to tell the parsing entity which key is being used to sign. This is the first step in obsoleting the dirservers file.
svn:r2428
This commit is contained in:
parent
7b98fb58eb
commit
c7e8c2098a
@ -552,7 +552,7 @@ dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
|
|||||||
crypto_pk_env_t *private_key)
|
crypto_pk_env_t *private_key)
|
||||||
{
|
{
|
||||||
char *cp, *eos;
|
char *cp, *eos;
|
||||||
char *identity_pkey; /* Identity key, PEM-encoded. */
|
char *identity_pkey; /* Identity key, DER64-encoded. */
|
||||||
char digest[20];
|
char digest[20];
|
||||||
char signature[128];
|
char signature[128];
|
||||||
char published[33];
|
char published[33];
|
||||||
@ -764,20 +764,32 @@ static int generate_runningrouters(crypto_pk_env_t *private_key)
|
|||||||
char published[33];
|
char published[33];
|
||||||
size_t len;
|
size_t len;
|
||||||
time_t published_on;
|
time_t published_on;
|
||||||
|
char *identity_pkey; /* Identity key, DER64-encoded. */
|
||||||
|
|
||||||
len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
|
len = 1024+(MAX_HEX_NICKNAME_LEN+2)*smartlist_len(descriptor_list);
|
||||||
s = tor_malloc_zero(len);
|
s = tor_malloc_zero(len);
|
||||||
if (list_running_servers(&cp))
|
if (list_running_servers(&cp))
|
||||||
return -1;
|
return -1;
|
||||||
|
/* ASN.1-encode the public key. This is a temporary measure; once
|
||||||
|
* everyone is running 0.0.9pre3 or later, we can shift to using a
|
||||||
|
* PEM-encoded key instead.
|
||||||
|
*/
|
||||||
|
if(crypto_pk_DER64_encode_public_key(private_key, &identity_pkey)<0) {
|
||||||
|
log_fn(LOG_WARN,"write identity_pkey to string failed!");
|
||||||
|
tor_free(cp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
published_on = time(NULL);
|
published_on = time(NULL);
|
||||||
format_iso_time(published, published_on);
|
format_iso_time(published, published_on);
|
||||||
sprintf(s, "network-status\n"
|
sprintf(s, "network-status\n"
|
||||||
"published %s\n"
|
"published %s\n"
|
||||||
"running-routers %s\n"
|
"running-routers %s\n"
|
||||||
|
"opt dir-signing-key %s\n"
|
||||||
"directory-signature %s\n"
|
"directory-signature %s\n"
|
||||||
"-----BEGIN SIGNATURE-----\n",
|
"-----BEGIN SIGNATURE-----\n",
|
||||||
published, cp, options.Nickname);
|
published, cp, identity_pkey, options.Nickname);
|
||||||
tor_free(cp);
|
tor_free(cp);
|
||||||
|
tor_free(identity_pkey);
|
||||||
if (router_get_runningrouters_hash(s,digest)) {
|
if (router_get_runningrouters_hash(s,digest)) {
|
||||||
log_fn(LOG_WARN,"couldn't compute digest");
|
log_fn(LOG_WARN,"couldn't compute digest");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -512,6 +512,7 @@ routerinfo_t *router_get_by_digest(const char *digest) {
|
|||||||
routerinfo_t *router;
|
routerinfo_t *router;
|
||||||
|
|
||||||
tor_assert(digest);
|
tor_assert(digest);
|
||||||
|
if (!routerlist) return NULL;
|
||||||
|
|
||||||
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
for(i=0;i<smartlist_len(routerlist->routers);i++) {
|
||||||
router = smartlist_get(routerlist->routers, i);
|
router = smartlist_get(routerlist->routers, i);
|
||||||
|
@ -40,6 +40,7 @@ typedef enum {
|
|||||||
K_CONTACT,
|
K_CONTACT,
|
||||||
K_NETWORK_STATUS,
|
K_NETWORK_STATUS,
|
||||||
K_UPTIME,
|
K_UPTIME,
|
||||||
|
K_DIR_SIGNING_KEY,
|
||||||
_UNRECOGNIZED,
|
_UNRECOGNIZED,
|
||||||
_ERR,
|
_ERR,
|
||||||
_EOF,
|
_EOF,
|
||||||
@ -113,6 +114,7 @@ static struct {
|
|||||||
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY },
|
{ "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ, ANY },
|
||||||
{ "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR_ONLY },
|
{ "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ, DIR_ONLY },
|
||||||
{ "uptime", K_UPTIME, ARGS, NO_OBJ, RTR_ONLY },
|
{ "uptime", K_UPTIME, ARGS, NO_OBJ, RTR_ONLY },
|
||||||
|
{ "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK, DIR_ONLY },
|
||||||
{ NULL, -1 }
|
{ NULL, -1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,8 +132,9 @@ static int tokenize_string(const char *start, const char *end,
|
|||||||
static directory_token_t *get_next_token(const char **s, where_syntax where);
|
static directory_token_t *get_next_token(const char **s, where_syntax where);
|
||||||
static int check_directory_signature(const char *digest,
|
static int check_directory_signature(const char *digest,
|
||||||
directory_token_t *tok,
|
directory_token_t *tok,
|
||||||
crypto_pk_env_t *pkey);
|
crypto_pk_env_t *pkey,
|
||||||
|
crypto_pk_env_t *declared_key);
|
||||||
|
static crypto_pk_env_t *find_dir_signing_key(const char *str);
|
||||||
|
|
||||||
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
|
/** Set <b>digest</b> to the SHA-1 digest of the hash of the directory in
|
||||||
* <b>s</b>. Return 0 on success, nonzero on failure.
|
* <b>s</b>. Return 0 on success, nonzero on failure.
|
||||||
@ -298,6 +301,7 @@ router_parse_routerlist_from_directory(const char *str,
|
|||||||
const char *end, *cp;
|
const char *end, *cp;
|
||||||
smartlist_t *tokens = NULL;
|
smartlist_t *tokens = NULL;
|
||||||
char dirnickname[MAX_NICKNAME_LEN+1];
|
char dirnickname[MAX_NICKNAME_LEN+1];
|
||||||
|
crypto_pk_env_t *declared_key = NULL;
|
||||||
|
|
||||||
if (router_get_dir_hash(str, digest)) {
|
if (router_get_dir_hash(str, digest)) {
|
||||||
log_fn(LOG_WARN, "Unable to compute digest of directory");
|
log_fn(LOG_WARN, "Unable to compute digest of directory");
|
||||||
@ -324,9 +328,9 @@ router_parse_routerlist_from_directory(const char *str,
|
|||||||
if(tok->tp != K_DIRECTORY_SIGNATURE) {
|
if(tok->tp != K_DIRECTORY_SIGNATURE) {
|
||||||
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
|
log_fn(LOG_WARN,"Expected a single directory signature"); goto err;
|
||||||
}
|
}
|
||||||
if (check_directory_signature(digest, tok, pkey)<0) {
|
declared_key = find_dir_signing_key(str);
|
||||||
|
if (check_directory_signature(digest, tok, pkey, declared_key)<0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
|
|
||||||
/* now we know tok->n_args == 1, so it's safe to access tok->args[0] */
|
/* now we know tok->n_args == 1, so it's safe to access tok->args[0] */
|
||||||
strlcpy(dirnickname, tok->args[0], sizeof(dirnickname));
|
strlcpy(dirnickname, tok->args[0], sizeof(dirnickname));
|
||||||
@ -439,6 +443,7 @@ router_parse_routerlist_from_directory(const char *str,
|
|||||||
routerlist_free(new_dir);
|
routerlist_free(new_dir);
|
||||||
tor_free(versions);
|
tor_free(versions);
|
||||||
done:
|
done:
|
||||||
|
if (declared_key) crypto_free_pk_env(declared_key);
|
||||||
if (tokens) {
|
if (tokens) {
|
||||||
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
||||||
smartlist_free(tokens);
|
smartlist_free(tokens);
|
||||||
@ -458,7 +463,7 @@ router_parse_runningrouters(const char *str)
|
|||||||
directory_token_t *tok;
|
directory_token_t *tok;
|
||||||
time_t published_on;
|
time_t published_on;
|
||||||
int i;
|
int i;
|
||||||
|
crypto_pk_env_t *declared_key = NULL;
|
||||||
smartlist_t *tokens = NULL;
|
smartlist_t *tokens = NULL;
|
||||||
|
|
||||||
if (router_get_runningrouters_hash(str, digest)) {
|
if (router_get_runningrouters_hash(str, digest)) {
|
||||||
@ -505,15 +510,16 @@ router_parse_runningrouters(const char *str)
|
|||||||
log_fn(LOG_WARN, "Missing signature on directory");
|
log_fn(LOG_WARN, "Missing signature on directory");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (check_directory_signature(digest, tok, NULL)<0) {
|
declared_key = find_dir_signing_key(str);
|
||||||
|
if (check_directory_signature(digest, tok, NULL, declared_key) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
|
|
||||||
goto done;
|
goto done;
|
||||||
err:
|
err:
|
||||||
running_routers_free(new_list);
|
running_routers_free(new_list);
|
||||||
new_list = NULL;
|
new_list = NULL;
|
||||||
done:
|
done:
|
||||||
|
if (declared_key) crypto_free_pk_env(declared_key);
|
||||||
if (tokens) {
|
if (tokens) {
|
||||||
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
SMARTLIST_FOREACH(tokens, directory_token_t *, tok, token_free(tok));
|
||||||
smartlist_free(tokens);
|
smartlist_free(tokens);
|
||||||
@ -521,9 +527,91 @@ router_parse_runningrouters(const char *str)
|
|||||||
return new_list;
|
return new_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Given a directory or running-routers string in <b>str</b>, try to
|
||||||
|
* find the its dir-signing-key token (if any). If this token is
|
||||||
|
* present, extract and return the key. Return NULL on failure. */
|
||||||
|
static crypto_pk_env_t *find_dir_signing_key(const char *str)
|
||||||
|
{
|
||||||
|
const char *cp;
|
||||||
|
directory_token_t *tok;
|
||||||
|
crypto_pk_env_t *key = NULL;
|
||||||
|
|
||||||
|
/* Is there a dir-signing-key in the directory? */
|
||||||
|
cp = strstr(str, "\nopt dir-signing-key");
|
||||||
|
if (!cp)
|
||||||
|
cp = strstr(str, "\ndir-signing-key");
|
||||||
|
if (!cp)
|
||||||
|
return NULL;
|
||||||
|
++cp; /* Now cp points to the start of the token. */
|
||||||
|
|
||||||
|
tok = get_next_token(&cp, DIR_ONLY);
|
||||||
|
if (!tok) {
|
||||||
|
log_fn(LOG_WARN, "Unparseable dir-signing-key token");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (tok->tp != K_DIR_SIGNING_KEY) {
|
||||||
|
log_fn(LOG_WARN, "Dir-signing-key token did not parse as expected");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok->key) {
|
||||||
|
key = tok->key;
|
||||||
|
tok->key = NULL; /* steal reference. */
|
||||||
|
} else if (tok->n_args >= 1) {
|
||||||
|
key = crypto_pk_DER64_decode_public_key(tok->args[0]);
|
||||||
|
if (!key) {
|
||||||
|
log_fn(LOG_WARN, "Unparseable dir-signing-key argument");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_fn(LOG_WARN, "Dir-signing-key token contained no key");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
token_free(tok);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true iff <b>key</b> is allowed to sign directories.
|
||||||
|
*/
|
||||||
|
static int dir_signing_key_is_trusted(crypto_pk_env_t *key)
|
||||||
|
{
|
||||||
|
char digest[DIGEST_LEN];
|
||||||
|
routerinfo_t *r;
|
||||||
|
if (!key) return 0;
|
||||||
|
if (crypto_pk_get_digest(key, digest) < 0) {
|
||||||
|
log_fn(LOG_WARN, "Error computing dir-signing-key digest");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(r = router_get_by_digest(digest))) {
|
||||||
|
log_fn(LOG_WARN, "No router known with given dir-signing-key digest");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (! r->is_trusted_dir) {
|
||||||
|
log_fn(LOG_WARN, "Listed dir-signing-key is not trusted");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check whether the K_DIRECTORY_SIGNATURE token in <b>tok</b> has a
|
||||||
|
* good signature for <b>digest</b>.
|
||||||
|
*
|
||||||
|
* If <b>declared_key</b> is set, the directory has declared what key
|
||||||
|
* was used to sign it, so we will use that key only if it is an
|
||||||
|
* authoritative directory signing key.
|
||||||
|
*
|
||||||
|
* Otherwise, try to look up the router whose nickname is given in the
|
||||||
|
* directory-signature token. If this fails, or the named router is
|
||||||
|
* not authoritative, try to use pkey.
|
||||||
|
*
|
||||||
|
* (New callers should always use <b>declared_key</b> when possible;
|
||||||
|
* <b>pkey is only for debugging.)
|
||||||
|
*/
|
||||||
static int check_directory_signature(const char *digest,
|
static int check_directory_signature(const char *digest,
|
||||||
directory_token_t *tok,
|
directory_token_t *tok,
|
||||||
crypto_pk_env_t *pkey)
|
crypto_pk_env_t *pkey,
|
||||||
|
crypto_pk_env_t *declared_key)
|
||||||
{
|
{
|
||||||
char signed_digest[PK_BYTES];
|
char signed_digest[PK_BYTES];
|
||||||
routerinfo_t *r;
|
routerinfo_t *r;
|
||||||
@ -533,6 +621,10 @@ static int check_directory_signature(const char *digest,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (declared_key) {
|
||||||
|
if (dir_signing_key_is_trusted(declared_key))
|
||||||
|
pkey = declared_key;
|
||||||
|
} else {
|
||||||
r = router_get_by_nickname(tok->args[0]);
|
r = router_get_by_nickname(tok->args[0]);
|
||||||
log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
|
log_fn(LOG_DEBUG, "Got directory signed by %s", tok->args[0]);
|
||||||
if (r && r->is_trusted_dir) {
|
if (r && r->is_trusted_dir) {
|
||||||
@ -548,6 +640,8 @@ static int check_directory_signature(const char *digest,
|
|||||||
tok->args[0]);
|
tok->args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
if (strcmp(tok->object_type, "SIGNATURE") || tok->object_size != 128) {
|
||||||
log_fn(LOG_WARN, "Bad object type or length on directory signature");
|
log_fn(LOG_WARN, "Bad object type or length on directory signature");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -619,6 +619,12 @@ test_util() {
|
|||||||
test_eq(5, tor_strstrip(buf, "!? "));
|
test_eq(5, tor_strstrip(buf, "!? "));
|
||||||
test_streq(buf, "Testing123");
|
test_streq(buf, "Testing123");
|
||||||
|
|
||||||
|
/* Test tor_strpartition() */
|
||||||
|
test_assert(! tor_strpartition(buf, sizeof(buf), "abcdefg", "##", 3));
|
||||||
|
test_streq(buf, "abc##def##g");
|
||||||
|
test_assert(! tor_strpartition(buf, sizeof(buf), "abcdefghi", "##", 3));
|
||||||
|
test_streq(buf, "abc##def##ghi##");
|
||||||
|
|
||||||
/* XXXX test older functions. */
|
/* XXXX test older functions. */
|
||||||
smartlist_free(sl);
|
smartlist_free(sl);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user