|
@@ -48,7 +48,9 @@ static int keypin_journal_append_entry(const uint8_t *rsa_id_digest,
|
|
|
const uint8_t *ed25519_id_key);
|
|
|
static int keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
|
|
const uint8_t *ed25519_id_key,
|
|
|
- int do_not_add);
|
|
|
+ const int do_not_add,
|
|
|
+ const int replace);
|
|
|
+static int keypin_add_or_replace_entry_in_map(keypin_ent_t *ent);
|
|
|
|
|
|
static HT_HEAD(rsamap, keypin_ent_st) the_rsa_map = HT_INITIALIZER();
|
|
|
static HT_HEAD(edmap, keypin_ent_st) the_ed_map = HT_INITIALIZER();
|
|
@@ -100,12 +102,17 @@ HT_GENERATE2(edmap, keypin_ent_st, edmap_node, keypin_ent_hash_ed,
|
|
|
* return KEYPIN_FOUND. If we find an entry that matches one key but
|
|
|
* not the other, return KEYPIN_MISMATCH. If we have no entry for either
|
|
|
* key, add such an entry to the table and return KEYPIN_ADDED.
|
|
|
+ *
|
|
|
+ * If <b>replace_existing_entry</b> is true, then any time we would have said
|
|
|
+ * KEYPIN_FOUND, we instead add this entry anyway and return KEYPIN_ADDED.
|
|
|
*/
|
|
|
int
|
|
|
keypin_check_and_add(const uint8_t *rsa_id_digest,
|
|
|
- const uint8_t *ed25519_id_key)
|
|
|
+ const uint8_t *ed25519_id_key,
|
|
|
+ const int replace_existing_entry)
|
|
|
{
|
|
|
- return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0);
|
|
|
+ return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 0,
|
|
|
+ replace_existing_entry);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -116,7 +123,7 @@ int
|
|
|
keypin_check(const uint8_t *rsa_id_digest,
|
|
|
const uint8_t *ed25519_id_key)
|
|
|
{
|
|
|
- return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 1);
|
|
|
+ return keypin_check_and_add_impl(rsa_id_digest, ed25519_id_key, 1, 0);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -125,7 +132,8 @@ keypin_check(const uint8_t *rsa_id_digest,
|
|
|
static int
|
|
|
keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
|
|
const uint8_t *ed25519_id_key,
|
|
|
- int do_not_add)
|
|
|
+ const int do_not_add,
|
|
|
+ const int replace)
|
|
|
{
|
|
|
keypin_ent_t search, *ent;
|
|
|
memset(&search, 0, sizeof(search));
|
|
@@ -139,18 +147,21 @@ keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
|
|
if (tor_memeq(ent->ed25519_key, ed25519_id_key,sizeof(ent->ed25519_key))) {
|
|
|
return KEYPIN_FOUND; /* Match on both keys. Great. */
|
|
|
} else {
|
|
|
- return KEYPIN_MISMATCH; /* Found RSA with different Ed key */
|
|
|
+ if (!replace)
|
|
|
+ return KEYPIN_MISMATCH; /* Found RSA with different Ed key */
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* See if we know a different RSA key for this ed key */
|
|
|
- ent = HT_FIND(edmap, &the_ed_map, &search);
|
|
|
- if (ent) {
|
|
|
- /* If we got here, then the ed key matches and the RSA doesn't */
|
|
|
- tor_assert(fast_memeq(ent->ed25519_key, ed25519_id_key,
|
|
|
- sizeof(ent->ed25519_key)));
|
|
|
- tor_assert(fast_memneq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id)));
|
|
|
- return KEYPIN_MISMATCH;
|
|
|
+ if (! replace) {
|
|
|
+ ent = HT_FIND(edmap, &the_ed_map, &search);
|
|
|
+ if (ent) {
|
|
|
+ /* If we got here, then the ed key matches and the RSA doesn't */
|
|
|
+ tor_assert(fast_memeq(ent->ed25519_key, ed25519_id_key,
|
|
|
+ sizeof(ent->ed25519_key)));
|
|
|
+ tor_assert(fast_memneq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id)));
|
|
|
+ return KEYPIN_MISMATCH;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Okay, this one is new to us. */
|
|
@@ -158,7 +169,12 @@ keypin_check_and_add_impl(const uint8_t *rsa_id_digest,
|
|
|
return KEYPIN_NOT_FOUND;
|
|
|
|
|
|
ent = tor_memdup(&search, sizeof(search));
|
|
|
- keypin_add_entry_to_map(ent);
|
|
|
+ int r = keypin_add_or_replace_entry_in_map(ent);
|
|
|
+ if (! replace) {
|
|
|
+ tor_assert(r == 1);
|
|
|
+ } else {
|
|
|
+ tor_assert(r != 0);
|
|
|
+ }
|
|
|
keypin_journal_append_entry(rsa_id_digest, ed25519_id_key);
|
|
|
return KEYPIN_ADDED;
|
|
|
}
|
|
@@ -173,6 +189,57 @@ keypin_add_entry_to_map, (keypin_ent_t *ent))
|
|
|
HT_INSERT(edmap, &the_ed_map, ent);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Helper: add 'ent' to the maps, replacing any entries that contradict it.
|
|
|
+ * Take ownership of 'ent', freeing it if needed.
|
|
|
+ *
|
|
|
+ * Return 0 if the entry was a duplicate, -1 if there was a conflict,
|
|
|
+ * and 1 if there was no conflict.
|
|
|
+ */
|
|
|
+static int
|
|
|
+keypin_add_or_replace_entry_in_map(keypin_ent_t *ent)
|
|
|
+{
|
|
|
+ int r = 1;
|
|
|
+ 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);
|
|
|
+ return 0;
|
|
|
+ } 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);
|
|
|
+ r = -1;
|
|
|
+ /* Fall through */
|
|
|
+ }
|
|
|
+
|
|
|
+ keypin_add_entry_to_map(ent);
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Check whether we already have an entry in the key pinning table for a
|
|
|
* router with RSA ID digest <b>rsa_id_digest</b>. If we have no such entry,
|
|
@@ -321,22 +388,13 @@ 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;
|
|
|
- }
|
|
|
- tor_free(ent);
|
|
|
- continue;
|
|
|
- } else if (HT_FIND(edmap, &the_ed_map, ent)) {
|
|
|
- tor_free(ent);
|
|
|
+ const int r = keypin_add_or_replace_entry_in_map(ent);
|
|
|
+ if (r == 0) {
|
|
|
+ ++n_duplicates;
|
|
|
+ } else if (r == -1) {
|
|
|
++n_conflicts;
|
|
|
- continue;
|
|
|
}
|
|
|
|
|
|
- keypin_add_entry_to_map(ent);
|
|
|
++n_entries;
|
|
|
}
|
|
|
|