|
@@ -173,6 +173,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,44 +372,13 @@ keypin_load_journal_impl(const char *data, size_t size)
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
+ const int r = keypin_add_or_replace_entry_in_map(ent);
|
|
|
+ if (r == 0) {
|
|
|
++n_duplicates;
|
|
|
- continue;
|
|
|
- } 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);
|
|
|
+ } else if (r == -1) {
|
|
|
++n_conflicts;
|
|
|
- /* Fall through */
|
|
|
}
|
|
|
|
|
|
- keypin_add_entry_to_map(ent);
|
|
|
++n_entries;
|
|
|
}
|
|
|
|