Commit c5e87e33 authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

Allow conflicts to occur in keypinning journal

When we find a conflict in the keypinning journal, treat the new
entry as superseding all old entries that overlap either of its
keys.

Also add a (not-yet-used) configuration option to disable keypinning
enforcement.
parent 81724d5a
......@@ -162,6 +162,7 @@ static config_var_t option_vars_[] = {
V(AuthDirInvalidCCs, CSV, ""),
V(AuthDirFastGuarantee, MEMUNIT, "100 KB"),
V(AuthDirGuardBWGuarantee, MEMUNIT, "2 MB"),
V(AuthDirPinKeys, BOOL, "0"),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
OBSOLETE("AuthDirRejectUnlisted"),
......
......@@ -321,19 +321,41 @@ keypin_load_journal_impl(const char *data, size_t size)
continue;
}
const keypin_ent_t *ent2;
if ((ent2 = HT_FIND(rsamap, &the_rsa_map, ent))) {
if (fast_memeq(ent2->ed25519_key, ent->ed25519_key, DIGEST256_LEN)) {
++n_duplicates;
} else {
++n_conflicts;
}
keypin_ent_t *ent2 = HT_FIND(rsamap, &the_rsa_map, ent);
keypin_ent_t *ent3 = HT_FIND(edmap, &the_ed_map, ent);
if (ent2 &&
fast_memeq(ent2->ed25519_key, ent->ed25519_key, DIGEST256_LEN)) {
/* We already have this mapping stored. Ignore it. */
tor_free(ent);
++n_duplicates;
continue;
} else if (HT_FIND(edmap, &the_ed_map, ent)) {
tor_free(ent);
} else if (ent2 || ent3) {
/* We have a conflict. (If we had no entry, we would have ent2 == ent3
* == NULL. If we had a non-conflicting duplicate, we would have found
* it above.)
*
* We respond by having this entry (ent) supersede all entries that it
* contradicts (ent2 and/or ent3). In other words, if we receive
* <rsa,ed>, we remove all <rsa,ed'> and all <rsa',ed>, for rsa'!=rsa
* and ed'!= ed.
*/
const keypin_ent_t *t;
if (ent2) {
t = HT_REMOVE(rsamap, &the_rsa_map, ent2);
tor_assert(ent2 == t);
t = HT_REMOVE(edmap, &the_ed_map, ent2);
tor_assert(ent2 == t);
}
if (ent3 && ent2 != ent3) {
t = HT_REMOVE(rsamap, &the_rsa_map, ent3);
tor_assert(ent3 == t);
t = HT_REMOVE(edmap, &the_ed_map, ent3);
tor_assert(ent3 == t);
tor_free(ent3);
}
tor_free(ent2);
++n_conflicts;
continue;
/* Fall through */
}
keypin_add_entry_to_map(ent);
......
......@@ -3790,6 +3790,7 @@ typedef struct {
* number of servers per IP address shared
* with an authority. */
int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */
int AuthDirPinKeys; /**< Boolean: Do we enforce key-pinning? */
/** If non-zero, always vote the Fast flag for any relay advertising
* this amount of capacity or more. */
......
......@@ -108,21 +108,21 @@ test_keypin_parse_file(void *arg)
;
tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2)));
tt_int_op(11, ==, smartlist_len(mock_addent_got));
tt_int_op(13, ==, smartlist_len(mock_addent_got));
ent = smartlist_get(mock_addent_got, 9);
tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20);
tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32);
ent = smartlist_get(mock_addent_got, 10);
ent = smartlist_get(mock_addent_got, 12);
tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20);
tt_mem_op(ent->ed25519_key, ==, "it was true that all the master\n", 32);
tt_mem_op(ent->ed25519_key, ==, "it was tru\xa5 that all the master\n", 32);
/* File truncated before NL */
const char data3[] =
"Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw";
tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3)));
tt_int_op(12, ==, smartlist_len(mock_addent_got));
ent = smartlist_get(mock_addent_got, 11);
tt_int_op(14, ==, smartlist_len(mock_addent_got));
ent = smartlist_get(mock_addent_got, 13);
tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20);
tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment