tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
May 2015
- 22 participants
- 990 discussions

28 May '15
commit a194385d5619f2b9c03ada34b8a7291ccc3c21ca
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu May 28 12:24:29 2015 -0400
Impose an upper limit on threads per threadpool.
Found by Coverity; Fixes CID 1268069
---
src/common/workqueue.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
index c1bd6d4..ed896d7 100644
--- a/src/common/workqueue.c
+++ b/src/common/workqueue.c
@@ -359,12 +359,17 @@ threadpool_queue_update(threadpool_t *pool,
return 0;
}
+/** Don't have more than this many threads per pool. */
+#define MAX_THREADS 1024
+
/** Launch threads until we have <b>n</b>. */
static int
threadpool_start_threads(threadpool_t *pool, int n)
{
if (n < 0)
return -1;
+ if (n > MAX_THREADS)
+ n = MAX_THREADS;
tor_mutex_acquire(&pool->lock);
1
0
commit 4a9f41e1eca32a8dbe53e1e4848e5f0d50c73731
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu May 28 11:40:20 2015 -0400
Bug 12498 needs a changes file.
---
changes/bug12498 | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/changes/bug12498 b/changes/bug12498
new file mode 100644
index 0000000..9f0147c
--- /dev/null
+++ b/changes/bug12498
@@ -0,0 +1,29 @@
+ o Major features (Ed25519 identity keys: #12498, Prop220):
+ - All relays now maintain a stronger identity key, using the
+ Ed25519 elliptic curve signature format. This master key is
+ designed so that it can be kept offline. Relays also generate
+ an online signing key, and a set of other Ed25519 keys and certificates.
+ These are all automatically regenerated and rotated as needed.
+ - Directory authorities track which Ed25519 identity keys have been
+ used with which RSA1024 identity keys, and do not allow them to vary
+ freely.
+ - Directory authorities now vote on Ed25519 identity keys along with
+ RSA1024 keys.
+ - Microdescriptors now include ed25519 identity keys.
+
+ o Major features (onion key cross-certification):
+ - Relay descriptors now include signatures of the identity keys using
+ the TAP and ntor onion keys. This allows relays to prove ownership of
+ their own onion keys. Because of this change, microdescriptors no longer
+ need to include RSA identity keys. Implements proposal 228;
+ closes ticket 12499.
+
+ o Code simplification and refactoring:
+ - The link authentication code has been refactored for better testability
+ and reliability. It now uses code generated with the "trunnel"
+ binary encoding generator, to reduce the risk of bugs due to
+ programmer error. Done as part of ticket 12498.
+
+ o Testing:
+ - The link authentication protocol code now has extensive tests.
+ - The relay descriptor signature testing code now has extensive tests.
1
0

[translation/torbutton-abouttorproperties_completed] Update translations for torbutton-abouttorproperties_completed
by translation@torproject.org 28 May '15
by translation@torproject.org 28 May '15
28 May '15
commit 1d1bd31073922b327c5ea95a6560d0565a44f17d
Author: Translation commit bot <translation(a)torproject.org>
Date: Thu May 28 15:16:17 2015 +0000
Update translations for torbutton-abouttorproperties_completed
---
en_GB/abouttor.properties | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/en_GB/abouttor.properties b/en_GB/abouttor.properties
new file mode 100644
index 0000000..d607324
--- /dev/null
+++ b/en_GB/abouttor.properties
@@ -0,0 +1,21 @@
+# Copyright (c) 2014, The Tor Project, Inc.
+# See LICENSE for licensing information.
+# vim: set sw=2 sts=2 ts=8 et:
+
+aboutTor.searchSP.privacy=Search <a href="%1$S">securely</a> with <a href="%2$S">Startpage</a>.
+# The following string is a link which replaces %1$S above.
+aboutTor.searchSP.privacy.link=https://startpage.com/eng/protect-privacy.html
+# The following string is a link which replaces %2$S above.
+aboutTor.searchSP.search.link=https://startpage.com/
+
+aboutTor.searchDDG.privacy=Search <a href="%1$S">securely</a> with <a href="%2$S">DuckDuckGo</a>.
+# The following string is a link which replaces %1$S above.
+aboutTor.searchDDG.privacy.link=https://duckduckgo.com/privacy.html
+# The following string is a link which replaces %2$S above.
+aboutTor.searchDDG.search.link=https://duckduckgo.com/
+
+aboutTor.searchDC.privacy=Search <a href="%1$S">securely</a> with <a href="%2$S">Disconnect.me</a>.
+# The following string is a link which replaces %1$S above.
+aboutTor.searchDC.privacy.link=https://disconnect.me/privacy
+# The following string is a link which replaces %2$S above.
+aboutTor.searchDC.search.link=https://search.disconnect.me/
1
0

[tor/master] Refactor link handshake cell type implementations to use trunnel
by nickm@torproject.org 28 May '15
by nickm@torproject.org 28 May '15
28 May '15
commit b29c1530c7864ddfe382b18f4fc6e88eb46c1595
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Fri Oct 17 17:06:31 2014 -0400
Refactor link handshake cell type implementations to use trunnel
Unit tests still pass.
---
src/or/channeltls.c | 138 +++++++++++++++++++++--------------------------
src/or/connection_or.c | 139 ++++++++++++++++++++++++++++++------------------
2 files changed, 148 insertions(+), 129 deletions(-)
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index af63444..0376e74 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -24,6 +24,7 @@
#include "connection.h"
#include "connection_or.h"
#include "control.h"
+#include "link_handshake.h"
#include "relay.h"
#include "router.h"
#include "routerlist.h"
@@ -1740,13 +1741,14 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
STATIC void
channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
{
- tor_x509_cert_t *link_cert = NULL;
- tor_x509_cert_t *id_cert = NULL;
- tor_x509_cert_t *auth_cert = NULL;
- uint8_t *ptr;
+#define MAX_CERT_TYPE_WANTED OR_CERT_TYPE_AUTH_1024
+ tor_x509_cert_t *certs[MAX_CERT_TYPE_WANTED + 1];
int n_certs, i;
+ certs_cell_t *cc = NULL;
+
int send_netinfo = 0;
+ memset(certs, 0, sizeof(certs));
tor_assert(cell);
tor_assert(chan);
tor_assert(chan->conn);
@@ -1776,63 +1778,41 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
if (cell->circ_id)
ERR("It had a nonzero circuit ID");
- n_certs = cell->payload[0];
- ptr = cell->payload + 1;
+ if (certs_cell_parse(&cc, cell->payload, cell->payload_len) < 0)
+ ERR("It couldn't be parsed.");
+
+ n_certs = cc->n_certs;
+
for (i = 0; i < n_certs; ++i) {
- uint8_t cert_type;
- uint16_t cert_len;
- if (cell->payload_len < 3)
- goto truncated;
- if (ptr > cell->payload + cell->payload_len - 3) {
- goto truncated;
- }
- cert_type = *ptr;
- cert_len = ntohs(get_uint16(ptr+1));
- if (cell->payload_len < 3 + cert_len)
- goto truncated;
- if (ptr > cell->payload + cell->payload_len - cert_len - 3) {
- goto truncated;
- }
- if (cert_type == OR_CERT_TYPE_TLS_LINK ||
- cert_type == OR_CERT_TYPE_ID_1024 ||
- cert_type == OR_CERT_TYPE_AUTH_1024) {
- tor_x509_cert_t *cert = tor_x509_cert_decode(ptr + 3, cert_len);
- if (!cert) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received undecodable certificate in CERTS cell from %s:%d",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ certs_cell_cert_t *c = certs_cell_get_certs(cc, i);
+
+ uint16_t cert_type = c->cert_type;
+ uint16_t cert_len = c->cert_len;
+ uint8_t *cert_body = certs_cell_cert_getarray_body(c);
+
+ if (cert_type > MAX_CERT_TYPE_WANTED)
+ continue;
+
+ tor_x509_cert_t *cert = tor_x509_cert_decode(cert_body, cert_len);
+ if (!cert) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received undecodable certificate in CERTS cell from %s:%d",
+ safe_str(chan->conn->base_.address),
+ chan->conn->base_.port);
+ } else {
+ if (certs[cert_type]) {
+ tor_x509_cert_free(cert);
+ ERR("Duplicate x509 certificate");
} else {
- if (cert_type == OR_CERT_TYPE_TLS_LINK) {
- if (link_cert) {
- tor_x509_cert_free(cert);
- ERR("Too many TLS_LINK certificates");
- }
- link_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_ID_1024) {
- if (id_cert) {
- tor_x509_cert_free(cert);
- ERR("Too many ID_1024 certificates");
- }
- id_cert = cert;
- } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
- if (auth_cert) {
- tor_x509_cert_free(cert);
- ERR("Too many AUTH_1024 certificates");
- }
- auth_cert = cert;
- } else {
- tor_x509_cert_free(cert);
- }
+ certs[cert_type] = cert;
}
}
- ptr += 3 + cert_len;
- continue;
-
- truncated:
- ERR("It ends in the middle of a certificate");
}
+ tor_x509_cert_t *id_cert = certs[OR_CERT_TYPE_ID_1024];
+ tor_x509_cert_t *auth_cert = certs[OR_CERT_TYPE_AUTH_1024];
+ tor_x509_cert_t *link_cert = certs[OR_CERT_TYPE_TLS_LINK];
+
if (chan->conn->handshake_state->started_here) {
int severity;
if (! (id_cert && link_cert))
@@ -1881,7 +1861,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
safe_str(chan->conn->base_.address), chan->conn->base_.port);
chan->conn->handshake_state->id_cert = id_cert;
- id_cert = NULL;
+ certs[OR_CERT_TYPE_ID_1024] = NULL;
if (!public_server_mode(get_options())) {
/* If we initiated the connection and we are not a public server, we
@@ -1908,7 +1888,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
chan->conn->handshake_state->id_cert = id_cert;
chan->conn->handshake_state->auth_cert = auth_cert;
- id_cert = auth_cert = NULL;
+ certs[OR_CERT_TYPE_ID_1024] = certs[OR_CERT_TYPE_AUTH_1024] = NULL;
}
chan->conn->handshake_state->received_certs_cell = 1;
@@ -1922,9 +1902,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
}
err:
- tor_x509_cert_free(id_cert);
- tor_x509_cert_free(link_cert);
- tor_x509_cert_free(auth_cert);
+ for (unsigned i = 0; i < ARRAY_LENGTH(certs); ++i) {
+ tor_x509_cert_free(certs[i]);
+ }
+ certs_cell_free(cc);
#undef ERR
}
@@ -1943,7 +1924,7 @@ STATIC void
channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
{
int n_types, i, use_type = -1;
- uint8_t *cp;
+ auth_challenge_cell_t *ac = NULL;
tor_assert(cell);
tor_assert(chan);
@@ -1956,7 +1937,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
safe_str(chan->conn->base_.address), \
chan->conn->base_.port, (s)); \
connection_or_close_for_error(chan->conn, 0); \
- return; \
+ goto done; \
} while (0)
if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
@@ -1969,19 +1950,17 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
ERR("We already received one");
if (!(chan->conn->handshake_state->received_certs_cell))
ERR("We haven't gotten a CERTS cell yet");
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
- ERR("It was too short");
if (cell->circ_id)
ERR("It had a nonzero circuit ID");
- n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
- if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
- ERR("It looks truncated");
+ if (auth_challenge_cell_parse(&ac, cell->payload, cell->payload_len) < 0)
+ ERR("It was not well-formed.");
+
+ n_types = ac->n_methods;
/* Now see if there is an authentication type we can use */
- cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
- for (i = 0; i < n_types; ++i, cp += 2) {
- uint16_t authtype = ntohs(get_uint16(cp));
+ for (i = 0; i < n_types; ++i) {
+ uint16_t authtype = auth_challenge_cell_get_methods(ac, i);
if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
use_type = authtype;
}
@@ -1992,7 +1971,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
/* If we're not a public server then we don't want to authenticate on a
connection we originated, and we already sent a NETINFO cell when we
got the CERTS cell. We have nothing more to do. */
- return;
+ goto done;
}
if (use_type >= 0) {
@@ -2006,7 +1985,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
log_warn(LD_OR,
"Couldn't send authenticate cell");
connection_or_close_for_error(chan->conn, 0);
- return;
+ goto done;
}
} else {
log_info(LD_OR,
@@ -2019,9 +1998,12 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
if (connection_or_send_netinfo(chan->conn) < 0) {
log_warn(LD_OR, "Couldn't send netinfo cell");
connection_or_close_for_error(chan->conn, 0);
- return;
+ goto done;
}
+done:
+ auth_challenge_cell_free(ac);
+
#undef ERR
}
@@ -2038,7 +2020,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
STATIC void
channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
{
- uint8_t expected[V3_AUTH_FIXED_PART_LEN];
+ uint8_t expected[V3_AUTH_FIXED_PART_LEN+256];
const uint8_t *auth;
int authlen;
@@ -2094,11 +2076,13 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
if (authlen < V3_AUTH_BODY_LEN + 1)
ERR("Authenticator was too short");
- if (connection_or_compute_authenticate_cell_body(
- chan->conn, expected, sizeof(expected), NULL, 1) < 0)
+ ssize_t bodylen =
+ connection_or_compute_authenticate_cell_body(
+ chan->conn, expected, sizeof(expected), NULL, 1);
+ if (bodylen < 0 || bodylen != V3_AUTH_FIXED_PART_LEN)
ERR("Couldn't compute expected AUTHENTICATE cell body");
- if (tor_memneq(expected, auth, sizeof(expected)))
+ if (tor_memneq(expected, auth, bodylen))
ERR("Some field in the AUTHENTICATE cell body was not as expected");
{
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 8602bcb..ba30987 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -30,6 +30,7 @@
#include "entrynodes.h"
#include "geoip.h"
#include "main.h"
+#include "link_handshake.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "reasons.h"
@@ -2279,28 +2280,37 @@ connection_or_send_certs_cell(or_connection_t *conn)
int
connection_or_send_auth_challenge_cell(or_connection_t *conn)
{
- var_cell_t *cell;
- uint8_t *cp;
- uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
+ var_cell_t *cell = NULL;
+ int r = -1;
tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
- if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0)
- return -1;
- cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4);
+ auth_challenge_cell_t *ac = auth_challenge_cell_new();
+
+ if (crypto_rand((char*)ac->challenge, sizeof(ac->challenge)) < 0)
+ goto done;
+
+ auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
+ auth_challenge_cell_set_n_methods(ac,
+ auth_challenge_cell_getlen_methods(ac));
+
+ cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
+ ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
+ ac);
+ if (len != cell->payload_len)
+ goto done;
cell->command = CELL_AUTH_CHALLENGE;
- memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN);
- cp = cell->payload + OR_AUTH_CHALLENGE_LEN;
- set_uint16(cp, htons(1)); /* We recognize one authentication type. */
- set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
connection_or_write_var_cell_to_buf(cell, conn);
+ r = 0;
+
+ done:
var_cell_free(cell);
- memwipe(challenge, 0, sizeof(challenge));
+ auth_challenge_cell_free(ac);
- return 0;
+ return r;
}
/** Compute the main body of an AUTHENTICATE cell that a client can use
@@ -2327,19 +2337,18 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
crypto_pk_t *signing_key,
int server)
{
- uint8_t *ptr;
+ auth1_t *auth = NULL;
+ auth_ctx_t *ctx = auth_ctx_new();
+ int result;
/* assert state is reasonable XXXX */
- if (outlen < V3_AUTH_FIXED_PART_LEN ||
- (!server && outlen < V3_AUTH_BODY_LEN))
- return -1;
+ ctx->is_ed = 0;
- ptr = out;
+ auth = auth1_new();
/* Type: 8 bytes. */
- memcpy(ptr, "AUTH0001", 8);
- ptr += 8;
+ memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
{
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
@@ -2359,12 +2368,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
server_id = server ? my_id : their_id;
/* Client ID digest: 32 octets. */
- memcpy(ptr, client_id, 32);
- ptr += 32;
+ memcpy(auth->cid, client_id, 32);
/* Server ID digest: 32 octets. */
- memcpy(ptr, server_id, 32);
- ptr += 32;
+ memcpy(auth->sid, server_id, 32);
}
{
@@ -2378,12 +2385,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
}
/* Server log digest : 32 octets */
- crypto_digest_get_digest(server_d, (char*)ptr, 32);
- ptr += 32;
+ crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
/* Client log digest : 32 octets */
- crypto_digest_get_digest(client_d, (char*)ptr, 32);
- ptr += 32;
+ crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
}
{
@@ -2396,49 +2401,79 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
freecert = tor_tls_get_peer_cert(conn->tls);
cert = freecert;
}
- if (!cert)
- return -1;
- memcpy(ptr, tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
+ if (!cert) {
+ log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
+ goto err;
+ }
+
+ memcpy(auth->scert,
+ tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
if (freecert)
tor_x509_cert_free(freecert);
- ptr += 32;
}
/* HMAC of clientrandom and serverrandom using master key : 32 octets */
- tor_tls_get_tlssecrets(conn->tls, ptr);
- ptr += 32;
-
- tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN);
-
- if (server)
- return V3_AUTH_FIXED_PART_LEN; // ptr-out
+ tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
/* 8 octets were reserved for the current time, but we're trying to get out
* of the habit of sending time around willynilly. Fortunately, nothing
* checks it. That's followed by 16 bytes of nonce. */
- crypto_rand((char*)ptr, 24);
- ptr += 24;
+ crypto_rand((char*)auth->rand, 24);
+
+ ssize_t len;
+ if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
+ log_warn(LD_OR, "Unable to encode signed part of AUTH1 data.");
+ goto err;
+ }
- tor_assert(ptr - out == V3_AUTH_BODY_LEN);
+ if (server) {
+ auth1_t *tmp = NULL;
+ ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
+ if (!tmp) {
+ log_warn(LD_OR, "Unable to parse signed part of AUTH1 data.");
+ goto err;
+ }
+ result = (int) (tmp->end_of_fixed_part - out);
+ auth1_free(tmp);
+ if (len2 != len) {
+ log_warn(LD_OR, "Mismatched length when re-parsing AUTH1 data.");
+ goto err;
+ }
+ goto done;
+ }
- if (!signing_key)
- return V3_AUTH_BODY_LEN; // ptr - out
+ if (signing_key) {
+ auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
- {
- int siglen;
char d[32];
- crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256);
- siglen = crypto_pk_private_sign(signing_key,
- (char*)ptr, outlen - (ptr-out),
+ crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
+ int siglen = crypto_pk_private_sign(signing_key,
+ (char*)auth1_getarray_sig(auth),
+ auth1_getlen_sig(auth),
d, 32);
- if (siglen < 0)
+ if (siglen < 0) {
+ log_warn(LD_OR, "Unable to sign AUTH1 data.");
return -1;
+ }
- ptr += siglen;
- tor_assert(ptr <= out+outlen);
- return (int)(ptr - out);
+ auth1_setlen_sig(auth, siglen);
+
+ len = auth1_encode(out, outlen, auth, ctx);
+ if (len < 0) {
+ log_warn(LD_OR, "Unable to encode signed AUTH1 data.");
+ goto err;
+ }
}
+ result = (int) len;
+ goto done;
+
+ err:
+ result = -1;
+ done:
+ auth1_free(auth);
+ auth_ctx_free(ctx);
+ return result;
}
/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
1
0

28 May '15
commit 4d1a0ece5c7c45e82206bd0abc3afec1358f8410
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Fri Oct 17 16:30:42 2014 -0400
Fix memory leaks in test_link_handshake.c
---
src/test/test_link_handshake.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index e164022..bfdd6f3 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -179,8 +179,12 @@ test_link_handshake_certs_ok(void *arg)
tor_free(cell2);
certs_cell_free(cc1);
certs_cell_free(cc2);
+ circuitmux_free(chan1->base_.cmux);
tor_free(chan1);
+ circuitmux_free(chan2->base_.cmux);
tor_free(chan2);
+ crypto_pk_free(key1);
+ crypto_pk_free(key2);
}
typedef struct certs_data_s {
@@ -188,6 +192,7 @@ typedef struct certs_data_s {
channel_tls_t *chan;
certs_cell_t *ccell;
var_cell_t *cell;
+ crypto_pk_t *key1, *key2;
} certs_data_t;
@@ -204,7 +209,10 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj)
tor_free(d->cell);
certs_cell_free(d->ccell);
connection_free_(TO_CONN(d->c));
+ circuitmux_free(d->chan->base_.cmux);
tor_free(d->chan);
+ crypto_pk_free(d->key1);
+ crypto_pk_free(d->key2);
tor_free(d);
}
return 1;
@@ -228,12 +236,11 @@ recv_certs_setup(const struct testcase_t *test)
tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
d->c->link_proto = 4;
- crypto_pk_t *key1 = NULL, *key2 = NULL;
- key1 = pk_generate(2);
- key2 = pk_generate(3);
+ d->key1 = pk_generate(2);
+ d->key2 = pk_generate(3);
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
- key1, key2, 86400), ==, 0);
+ d->key1, d->key2, 86400), ==, 0);
d->ccell = certs_cell_new();
ccc1 = certs_cell_cert_new();
certs_cell_add_certs(d->ccell, ccc1);
@@ -460,6 +467,7 @@ recv_authchallenge_cleanup(const struct testcase_t *test, void *obj)
if (d) {
tor_free(d->cell);
connection_free_(TO_CONN(d->c));
+ circuitmux_free(d->chan->base_.cmux);
tor_free(d->chan);
tor_free(d);
}
@@ -614,6 +622,7 @@ typedef struct authenticate_data_s {
or_connection_t *c1, *c2;
channel_tls_t *chan2;
var_cell_t *cell;
+ crypto_pk_t *key1, *key2;
} authenticate_data_t;
static int
@@ -630,7 +639,11 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg)
tor_free(d->cell);
connection_free_(TO_CONN(d->c1));
connection_free_(TO_CONN(d->c2));
+ circuitmux_free(d->chan2->base_.cmux);
tor_free(d->chan2);
+ crypto_pk_free(d->key1);
+ crypto_pk_free(d->key2);
+ tor_free(d);
}
mock_peer_cert = NULL;
@@ -652,11 +665,10 @@ authenticate_data_setup(const struct testcase_t *test)
d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
- crypto_pk_t *key1 = NULL, *key2 = NULL;
- key1 = pk_generate(2);
- key2 = pk_generate(3);
+ d->key1 = pk_generate(2);
+ d->key2 = pk_generate(3);
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
- key1, key2, 86400), ==, 0);
+ d->key1, d->key2, 86400), ==, 0);
d->c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->c1->link_proto = 3;
@@ -721,6 +733,7 @@ test_link_handshake_auth_cell(void *arg)
{
authenticate_data_t *d = arg;
auth1_t *auth1 = NULL;
+ crypto_pk_t *auth_pubkey = NULL;
/* Is the cell well-formed on the outer layer? */
tt_int_op(d->cell->command, ==, CELL_AUTHENTICATE);
@@ -744,8 +757,10 @@ test_link_handshake_auth_cell(void *arg)
/* Is the signature okay? */
uint8_t sig[128];
uint8_t digest[32];
+
+ auth_pubkey = tor_tls_cert_get_key(d->c2->handshake_state->auth_cert);
int n = crypto_pk_public_checksig(
- tor_tls_cert_get_key(d->c2->handshake_state->auth_cert),
+ auth_pubkey,
(char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1),
auth1_getlen_sig(auth1));
tt_int_op(n, ==, 32);
@@ -762,6 +777,7 @@ test_link_handshake_auth_cell(void *arg)
done:
auth1_free(auth1);
+ crypto_pk_free(auth_pubkey);
}
#define AUTHENTICATE_FAIL(name, code) \
@@ -800,8 +816,10 @@ test_link_handshake_auth_already_authenticated(void *arg)
AUTHENTICATE_FAIL(nocerts,
d->c2->handshake_state->received_certs_cell = 0)
AUTHENTICATE_FAIL(noidcert,
+ tor_x509_cert_free(d->c2->handshake_state->id_cert);
d->c2->handshake_state->id_cert = NULL)
AUTHENTICATE_FAIL(noauthcert,
+ tor_x509_cert_free(d->c2->handshake_state->auth_cert);
d->c2->handshake_state->auth_cert = NULL)
AUTHENTICATE_FAIL(tooshort,
d->cell->payload_len = 3)
1
0

[tor/master] Checkpoint some work on voting on ed25519 identities
by nickm@torproject.org 28 May '15
by nickm@torproject.org 28 May '15
28 May '15
commit 525383c46d1430abf680133e486fc532050d7123
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Oct 29 13:36:21 2014 -0400
Checkpoint some work on voting on ed25519 identities
* Include ed25519 identities in votes
* Include "no ed25519 identity" in votes
* Include some commented-out code about identity voting. (This
will disappear.)
* Include some functions for identity voting (These will disappear.)
* Enforce uniqueness in ed25519 keys within a vote
---
src/or/dirserv.c | 15 +++++++++++++++
src/or/dirvote.c | 32 ++++++++++++++++++++++++++++++++
src/or/dirvote.h | 3 +++
src/or/or.h | 3 +++
src/or/routerparse.c | 27 +++++++++++++++++++++++++++
5 files changed, 80 insertions(+)
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index f26a6bb..5b103bc 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1993,6 +1993,16 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
smartlist_add_asprintf(chunks, "p %s\n", summary);
tor_free(summary);
}
+
+ if (format == NS_V3_VOTE && vrs) {
+ if (tor_mem_is_zero((char*)vrs->ed25519_id, ED25519_PUBKEY_LEN)) {
+ smartlist_add(chunks, tor_strdup("id ed25519 none\n"));
+ } else {
+ char ed_b64[BASE64_DIGEST256_LEN+1];
+ digest256_to_base64(ed_b64, (const char*)vrs->ed25519_id);
+ smartlist_add_asprintf(chunks, "id ed25519 %s\n", ed_b64);
+ }
+ }
}
done:
@@ -2815,6 +2825,11 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
listbadexits,
vote_on_hsdirs);
+ if (ri->signing_key_cert) {
+ memcpy(vrs->ed25519_id, ri->signing_key_cert->signing_key.pubkey,
+ ED25519_PUBKEY_LEN);
+ }
+
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
clear_status_flags_on_sybil(rs);
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 94b4e51..6c53b3c 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -782,6 +782,28 @@ networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg,
return berr;
}
+#if 0
+/** DOCDOC */
+static vote_identity_map_t *
+networkstatus_compute_identity_mapping(const smartlist_t *votes)
+{
+ vote_identity_map_t *map = vote_identity_map_new();
+
+ SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, vote) {
+ SMARTLIST_FOREACH_BEGIN(vote->routerstatus_list,
+ vote_routerstatus_t *, vrs) {
+ vote_identity_map_add(map, vrs->status.identity_digest,
+ vrs->has_ed25519_listing ? vrs->ed25519_id : NULL,
+ vote_sl_idx);
+ } SMARTLIST_FOREACH_END(vrs);
+ } SMARTLIST_FOREACH_END(vote);
+
+ vote_identity_map_resolve(map);
+
+ return map;
+}
+#endif
+
/**
* This function computes the bandwidth weights for consensus method 10.
*
@@ -1139,6 +1161,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
char *params = NULL;
char *packages = NULL;
int added_weights = 0;
+#if 0
+ vote_identity_map_t *id_map = NULL;
+#endif
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
tor_assert(total_authorities >= smartlist_len(votes));
@@ -1494,6 +1519,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
);
+#if 0
+ id_map = networkstatus_compute_identity_mapping(votes);
+#endif
+
/* Now go through all the votes */
flag_counts = tor_calloc(smartlist_len(flags), sizeof(int));
while (1) {
@@ -1981,6 +2010,9 @@ networkstatus_compute_consensus(smartlist_t *votes,
done:
+#if 0
+ vote_identity_map_free(id_map);
+#endif
tor_free(client_versions);
tor_free(server_versions);
tor_free(packages);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index edd5751..0fb2b25 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -89,6 +89,9 @@
/** Lowest consensus method where authorities may include an "id" line for
* ed25519 identities in microdescriptors. */
#define MIN_METHOD_FOR_ED25519_ID_IN_MD 21
+/** Lowest consensus method where authorities vote on ed25519 ids and ensure
+ * ed25519 id consistency. */
+#define MIN_METHOD_FOR_ED25519_ID_VOTING MIN_METHOD_FOR_ED25519_ID_IN_MD
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
diff --git a/src/or/or.h b/src/or/or.h
index 714b1c6..a41a14e 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2356,9 +2356,12 @@ typedef struct vote_routerstatus_t {
char *version; /**< The version that the authority says this router is
* running. */
unsigned int has_measured_bw:1; /**< The vote had a measured bw */
+ unsigned int has_ed25519_listing:1; /** DOCDOC */
uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */
/** The hash or hashes that the authority claims this microdesc has. */
vote_microdesc_hash_t *microdesc;
+ /** Ed25519 identity for this router, or zero if it has none. */
+ uint8_t ed25519_id[ED25519_PUBKEY_LEN];
} vote_routerstatus_t;
/** A signature of some document by an authority. */
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 03a5eaf..71a0baa 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -369,6 +369,7 @@ static token_rule_t rtrstatus_token_table[] = {
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
T01("w", K_W, ARGS, NO_OBJ ),
T0N("m", K_M, CONCAT_ARGS, NO_OBJ ),
+ T0N("id", K_ID, GE(2), NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
@@ -2348,6 +2349,17 @@ routerstatus_parse_entry_from_string(memarea_t *area,
line->microdesc_hash_line = tor_strdup(t->args[0]);
vote_rs->microdesc = line;
}
+ if (t->tp == K_ID) {
+ tor_assert(t->n_args >= 2);
+ if (!strcmp(t->args[0], "ed25519")) {
+ vote_rs->has_ed25519_listing = 1;
+ if (strcmp(t->args[1], "none") &&
+ digest256_from_base64((char*)vote_rs->ed25519_id, t->args[1])<0) {
+ log_warn(LD_DIR, "Bogus ed25519 key in networkstatus vote");
+ goto err;
+ }
+ }
+ }
} SMARTLIST_FOREACH_END(t);
} else if (flav == FLAV_MICRODESC) {
tok = find_opt_by_keyword(tokens, K_M);
@@ -3172,6 +3184,21 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
goto err;
}
}
+ if (ns_type != NS_TYPE_CONSENSUS) {
+ digest256map_t *ed_id_map = digest256map_new();
+ SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, vote_routerstatus_t *, vrs) {
+ if (! vrs->has_ed25519_listing ||
+ tor_mem_is_zero((const char *)vrs->ed25519_id, DIGEST256_LEN))
+ continue;
+ if (digest256map_get(ed_id_map, vrs->ed25519_id) != NULL) {
+ log_warn(LD_DIR, "Vote networkstatus ed25519 identities were not "
+ "unique");
+ goto err;
+ }
+ digest256map_set(ed_id_map, vrs->ed25519_id, (void*)1);
+ } SMARTLIST_FOREACH_END(vrs);
+ digest256map_free(ed_id_map, NULL);
+ }
/* Parse footer; check signature. */
footer_tokens = smartlist_new();
1
0

[tor/master] Revise makedesc.py: teach it how to emit ed signatures and crosscerts
by nickm@torproject.org 28 May '15
by nickm@torproject.org 28 May '15
28 May '15
commit b600b68b209984fa55f1dc0c311f77e2942a8a17
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Oct 22 14:19:18 2014 -0400
Revise makedesc.py: teach it how to emit ed signatures and crosscerts
Also, add a trivial ed25519-signed routerinfo to the tests.
---
scripts/codegen/makedesc.py | 349 +++++++++++++++++++++++++++-----------
src/test/failing_routerdescs.inc | 46 +++++
src/test/test_dir.c | 6 +-
3 files changed, 299 insertions(+), 102 deletions(-)
diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py
index 8339519..0ed1f7e 100644
--- a/scripts/codegen/makedesc.py
+++ b/scripts/codegen/makedesc.py
@@ -14,6 +14,17 @@ import binascii
import ctypes
import ctypes.util
import hashlib
+import optparse
+import os
+import struct
+import time
+import UserDict
+
+import slow_ed25519
+import slownacl_curve25519
+import ed25519_exts_ref
+
+# Pull in the openssl stuff we need.
crypt = ctypes.CDLL(ctypes.util.find_library('crypto'))
BIO_s_mem = crypt.BIO_s_mem
@@ -24,6 +35,15 @@ BIO_new = crypt.BIO_new
BIO_new.argtypes = [ctypes.c_void_p]
BIO_new.restype = ctypes.c_void_p
+crypt.BIO_free.argtypes = [ctypes.c_void_p]
+crypt.BIO_free.restype = ctypes.c_int
+
+crypt.BIO_ctrl.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_long, ctypes.c_void_p ]
+crypt.BIO_ctrl.restype = ctypes.c_long
+
+crypt.PEM_write_bio_RSAPublicKey.argtypes = [ ctypes.c_void_p, ctypes.c_void_p ]
+crypt.PEM_write_bio_RSAPublicKey.restype = ctypes.c_int
+
RSA_generate_key = crypt.RSA_generate_key
RSA_generate_key.argtypes = [ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p]
RSA_generate_key.restype = ctypes.c_void_p
@@ -39,6 +59,14 @@ i2d_RSAPublicKey.argtypes = [
]
i2d_RSAPublicKey.restype = ctypes.c_int
+
+def rsa_sign(msg, rsa):
+ buf = ctypes.create_string_buffer(1024)
+ n = RSA_private_encrypt(len(msg), msg, buf, rsa, 1)
+ if n <= 0:
+ raise Exception()
+ return buf.raw[:n]
+
def b64(x):
x = base64.b64encode(x)
res = []
@@ -51,29 +79,188 @@ def bio_extract(bio):
length = crypt.BIO_ctrl(bio, 3, 0, ctypes.byref(buf))
return ctypes.string_at(buf, length)
-def make_key(e=65537):
+def make_rsa_key(e=65537):
rsa = crypt.RSA_generate_key(1024, e, None, None)
bio = BIO_new(BIO_s_mem())
crypt.PEM_write_bio_RSAPublicKey(bio, rsa)
pem = bio_extract(bio).rstrip()
crypt.BIO_free(bio)
-
buf = ctypes.create_string_buffer(1024)
pBuf = ctypes.c_char_p(ctypes.addressof(buf))
n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
s = buf.raw[:n]
digest = hashlib.sha1(s).digest()
-
return (rsa,pem,digest)
+def makeEdSigningKeyCert(sk_master, pk_master, pk_signing, date,
+ includeSigning=False, certType=1):
+ assert len(pk_signing) == len(pk_master) == 32
+ expiration = struct.pack("!L", date//3600)
+ if includeSigning:
+ extensions = "\x01\x00\x20\x04\x00%s"%(pk_master)
+ else:
+ extensions = "\x00"
+ signed = "\x01%s%s\x01%s%s" % (
+ chr(certType), expiration, pk_signing, extensions)
+ signature = ed25519_exts_ref.signatureWithESK(signed, sk_master, pk_master)
+ assert len(signature) == 64
+ return signed+signature
+
+def objwrap(identifier, body):
+ return ("-----BEGIN {0}-----\n"
+ "{1}"
+ "-----END {0}-----").format(identifier, body)
+
+MAGIC1 = "<<<<<<MAGIC>>>>>>"
+MAGIC2 = "<<<<<!#!#!#XYZZY#!#!#!>>>>>"
+
+class OnDemandKeys(object):
+ def __init__(self, certDate=None):
+ if certDate is None:
+ certDate = time.time() + 86400
+ self.certDate = certDate
+ self.rsa_id = None
+ self.rsa_onion_key = None
+ self.ed_id_sk = None
+ self.ntor_sk = None
+ self.ntor_crosscert = None
+ self.rsa_crosscert_ed = None
+ self.rsa_crosscert_noed = None
+
+ @property
+ def RSA_IDENTITY(self):
+ if self.rsa_id is None:
+ self.rsa_id, self.rsa_ident_pem, self.rsa_id_digest = make_rsa_key()
+
+ return self.rsa_ident_pem
+
+ @property
+ def RSA_ID_DIGEST(self):
+ self.RSA_IDENTITY
+ return self.rsa_id_digest
+
+ @property
+ def RSA_FINGERPRINT_NOSPACE(self):
+ return binascii.b2a_hex(self.RSA_ID_DIGEST).upper()
+
+ @property
+ def RSA_ONION_KEY(self):
+ if self.rsa_onion_key is None:
+ self.rsa_onion_key, self.rsa_onion_pem, _ = make_rsa_key()
+
+ return self.rsa_onion_pem
+
+ @property
+ def RSA_FINGERPRINT(self):
+ hexdigest = self.RSA_FINGERPRINT_NOSPACEK
+ return " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
+
+ @property
+ def RSA_SIGNATURE(self):
+ return MAGIC1
+
+ @property
+ def ED_SIGNATURE(self):
+ return MAGIC2
+
+ @property
+ def NTOR_ONION_KEY(self):
+ if self.ntor_sk is None:
+ self.ntor_sk = slownacl_curve25519.Private()
+ self.ntor_pk = self.ntor_sk.get_public()
+ return base64.b64encode(self.ntor_pk.serialize())
+
+ @property
+ def ED_CERT(self):
+ if self.ed_id_sk is None:
+ self.ed_id_sk = ed25519_exts_ref.expandSK(os.urandom(32))
+ self.ed_signing_sk = ed25519_exts_ref.expandSK(os.urandom(32))
+ self.ed_id_pk = ed25519_exts_ref.publickeyFromESK(self.ed_id_sk)
+ self.ed_signing_pk = ed25519_exts_ref.publickeyFromESK(self.ed_signing_sk)
+ self.ed_cert = makeEdSigningKeyCert(self.ed_id_sk, self.ed_id_pk, self.ed_signing_pk, self.certDate, includeSigning=True, certType=4)
+
+ return objwrap('ED25519 CERT', b64(self.ed_cert))
+
+ @property
+ def NTOR_CROSSCERT(self):
+ if self.ntor_crosscert is None:
+ self.ED_CERT
+ self.NTOR_ONION_KEY
+
+ ed_privkey = self.ntor_sk.serialize() + os.urandom(32)
+ ed_pub0 = ed25519_exts_ref.publickeyFromESK(ed_privkey)
+ sign = (ord(ed_pub0[31]) & 255) >> 7
+
+ self.ntor_crosscert = makeEdSigningKeyCert(self.ntor_sk.serialize() + os.urandom(32), ed_pub0, self.ed_id_pk, self.certDate, certType=10)
+ self.ntor_crosscert_sign = sign
+
+ return objwrap('ED25519 CERT', b64(self.ntor_crosscert))
+
+ @property
+ def NTOR_CROSSCERT_SIGN(self):
+ self.NTOR_CROSSCERT
+ return self.ntor_crosscert_sign
+
+ @property
+ def RSA_CROSSCERT_NOED(self):
+ if self.rsa_crosscert_noed is None:
+ self.RSA_ONION_KEY
+ signed = self.RSA_ID_DIGEST
+ self.rsa_crosscert_noed = rsa_sign(signed, self.rsa_onion_key)
+ return objwrap("CROSSCERT",b64(self.rsa_crosscert_noed))
+
+ @property
+ def RSA_CROSSCERT_ED(self):
+ if self.rsa_crosscert_ed is None:
+ self.RSA_ONION_KEY
+ self.ED_CERT
+ signed = self.RSA_ID_DIGEST + self.ed_id_pk
+ self.rsa_crosscert_ed = rsa_sign(signed, self.rsa_onion_key)
+ return objwrap("CROSSCERT",b64(self.rsa_crosscert_ed))
+
+ def sign_desc(self, body):
+ idx = body.rfind("\nrouter-sig-ed25519 ")
+ if idx >= 0:
+ self.ED_CERT
+ signed_part = body[:idx+len("\nrouter-sig-ed25519 ")]
+ signed_part = "Tor router descriptor signature v1" + signed_part
+ digest = hashlib.sha256(signed_part).digest()
+ ed_sig = ed25519_exts_ref.signatureWithESK(digest,
+ self.ed_signing_sk, self.ed_signing_pk)
+
+ body = body.replace(MAGIC2, base64.b64encode(ed_sig).replace("=",""))
+
+ idx = body.rindex("\nrouter-signature")
+ end_of_sig = body.index("\n", idx+1)
+
+ signed_part = body[:end_of_sig+1]
+
+ digest = hashlib.sha1(signed_part).digest()
+ assert len(digest) == 20
+
+ rsasig = rsa_sign(digest, self.rsa_id)
+
+ body = body.replace(MAGIC1, objwrap("SIGNATURE", b64(rsasig)))
+
+ return body
+
+
def signdesc(body, args_out=None):
rsa, ident_pem, id_digest = make_key()
_, onion_pem, _ = make_key()
+ need_ed = '{ED25519-CERT}' in body or '{ED25519-SIGNATURE}' in body
+ if need_ed:
+ sk_master = os.urandom(32)
+ sk_signing = os.urandom(32)
+ pk_master = slow_ed25519.pubkey(sk_master)
+ pk_signing = slow_ed25519.pubkey(sk_signing)
+
hexdigest = binascii.b2a_hex(id_digest).upper()
fingerprint = " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
MAGIC = "<<<<<<MAGIC>>>>>>"
+ MORE_MAGIC = "<<<<<!#!#!#XYZZY#!#!#!>>>>>"
args = {
"RSA-IDENTITY" : ident_pem,
"ONION-KEY" : onion_pem,
@@ -81,6 +268,11 @@ def signdesc(body, args_out=None):
"FINGERPRINT-NOSPACE" : hexdigest,
"RSA-SIGNATURE" : MAGIC
}
+ if need_ed:
+ args['ED25519-CERT'] = makeEdSigningKeyCert(
+ sk_master, pk_master, pk_signing)
+ args['ED25519-SIGNATURE'] = MORE_MAGIC
+
if args_out:
args_out.update(args)
body = body.format(**args)
@@ -104,115 +296,72 @@ def signdesc(body, args_out=None):
return body.rstrip()
-def emit_ri(name, body, args_out=None):
- print "const char %s[] ="%name
- body = "\n".join(line.rstrip() for line in body.split("\n"))+"\n"
- b = signdesc(body, args_out)
- for line in b.split("\n"):
- print ' "%s\\n"'%line
+def print_c_string(ident, body):
+ print "static const char EX %s[] =" % ident
+ for line in body.split("\n"):
+ print ' "%s\\n"' %(line)
print " ;"
+def emit_ri(name, body):
+ info = OnDemandKeys()
+ body = body.format(d=info)
+ body = info.sign_desc(body)
+ print_c_string("EX_RI_%s"%name.upper(), body)
+
def emit_ei(name, body):
- args = { 'NAME' : name }
- emit_ri(name, body, args)
- args['key'] = "\n".join(
- ' "%s\\n"'%line for line in args['RSA-IDENTITY'].split("\n"))
- print """
-const char {NAME}_fp[] = "{FINGERPRINT-NOSPACE}";
-const char {NAME}_key[] =
-{key};""".format(**args)
+ info = OnDemandKeys()
+ body = body.format(d=info)
+ body = info.sign_desc(body)
+ print_c_string("EX_EI_%s"%name.upper(), body)
-if 0:
- emit_ri("minimal",
- """\
-router fred 127.0.0.1 9001 0 9002
-signing-key
-{RSA-IDENTITY}
-onion-key
-{ONION-KEY}
-published 2014-10-05 12:00:00
-bandwidth 1000 1000 1000
-reject *:*
-router-signature
-{RSA-SIGNATURE}
-""")
+ print 'const char {NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
+ d=info, NAME=name.upper())
+ prnit_c_string("%s_KEY"%name.upper(), d.RSA_IDENTITY)
+
+def analyze(s):
+ fields = {}
+ while s.startswith(":::"):
+ first,s=s.split("\n", 1)
+ m = re.match(r'^:::(\w+)=(.*)',first)
+ if not m:
+ raise ValueError(first)
+ k,v = m.groups()
+ fields[k] = v
+ return fields, s
+
+def process_file(s):
+ try:
+ name = fields['name']
+ tp = fields['type']
+ except KeyError:
+ raise ValueError("missing required field")
+
+ if tp == 'ei':
+ emit_ei(name, s)
+ elif tp == 'ri':
+ emit_ri(name, s)
+ else:
+ raise ValueError("unrecognized type")
if 0:
- emit_ri("maximal",
+ emit_ri("minimal_ed",
"""\
router fred 127.0.0.1 9001 0 9002
+identity-ed25519
+{d.ED_CERT}
signing-key
-{RSA-IDENTITY}
+{d.RSA_IDENTITY}
onion-key
-{ONION-KEY}
+{d.RSA_ONION_KEY}
+ntor-onion-key {d.NTOR_ONION_KEY}
+ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
+{d.NTOR_CROSSCERT}
+onion-key-crosscert
+{d.RSA_CROSSCERT_ED}
published 2014-10-05 12:00:00
bandwidth 1000 1000 1000
-reject 127.0.0.1:*
-accept *:80
reject *:*
-ipv6-policy accept 80,100,101
-ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw
-uptime 1000
-hibernating 0
-unrecognized-keywords are just dandy in this format
-platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
-contact O.W.Jones
-fingerprint {FINGERPRINT}
-read-history 900 1,2,3,4
-write-history 900 1,2,3,4
-extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
-hidden-service-dir
-allow-single-hop-exits
-family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
-caches-extra-info
-or-address [::1:2:3:4]:9999
-or-address 127.0.0.99:10000
-opt fred is a fine router
-router-signature
-{RSA-SIGNATURE}
-""")
-
-if 0:
- emit_ei("maximal",
-"""\
-extra-info bob {FINGERPRINT-NOSPACE}
-published 2014-10-05 20:07:00
-opt foobarbaz
-read-history 900 1,2,3
-write-history 900 1,2,3
-dirreq-v2-ips 1
-dirreq-v3-ips 100
-dirreq-v3-reqs blahblah
-dirreq-v2-share blahblah
-dirreq-v3-share blahblah
-dirreq-v2-resp djfkdj
-dirreq-v3-resp djfkdj
-dirreq-v2-direct-dl djfkdj
-dirreq-v3-direct-dl djfkdj
-dirreq-v2-tunneled-dl djfkdj
-dirreq-v3-tunneled-dl djfkdj
-dirreq-stats-end foobar
-entry-ips jfsdfds
-entry-stats-end ksdflkjfdkf
-cell-stats-end FOO
-cell-processed-cells FOO
-cell-queued-cells FOO
-cell-time-in-queue FOO
-cell-circuits-per-decile FOO
-exit-stats-end FOO
-exit-kibibytes-written FOO
-exit-kibibytes-read FOO
-exit-streams-opened FOO
-router-signature
-{RSA-SIGNATURE}
-""")
-
-if 0:
- emit_ei("minimal",
-"""\
-extra-info bob {FINGERPRINT-NOSPACE}
-published 2014-10-05 20:07:00
+router-sig-ed25519 {d.ED_SIGNATURE}
router-signature
-{RSA-SIGNATURE}
+{d.RSA_SIGNATURE}
""")
-
diff --git a/src/test/failing_routerdescs.inc b/src/test/failing_routerdescs.inc
index b49d59f..db3fd70 100644
--- a/src/test/failing_routerdescs.inc
+++ b/src/test/failing_routerdescs.inc
@@ -666,3 +666,49 @@ static const char EX_RI_ZERO_ORPORT[] =
"wgFKhHI/49NHyWHX5IMQpeicg0T7Qa6qwnUvspH62p8=\n"
"-----END SIGNATURE-----\n"
;
+
+static const char EX_RI_MINIMAL_ED[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf5iAa+2yD5ryD5kXaWbpmzaTyuTjRfjMTFleDuFGkHe26wrAQAgBABFTAHm\n"
+ "hdZriC+6BRCCMYu48cYc9tUN1adfEROqSHZN3HHP4k/fYgncoxrS3OYDX1x8Ysm/\n"
+ "sqxAXBY4NhCMswWvuDYgtQpro9YaFohiorJkHjyLQXjUeZikCfDrlxyR8AM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOsjlHgM/lPQgjJyfrq0y+cR+iipcAeS2HAU8CK9SATETOTZYrxoL5vH\n"
+ "1BNteT+JxAxpjva+j7r7XZV41xPDx7alVr8G3zQsjqkAt5NnleTfUREUbg0+OSMV\n"
+ "10gU+DgcZJTMehfGYJnuJsF4eQHio/ZTdJLaZML7qwq0iWg3sZfBAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK9NjRY7GtAZnlxrAZlImChXmGzml0uk2KlCugvju+eIsjSA/zW3LuqW\n"
+ "wqp7Kh488Ak5nUFSlCaV9GjAexT134pynst8P0m/ofrejwlzl5DHd6sFbR33Fkzl\n"
+ "H48zic0QDY+8tKXI732dA4GveEwZDlxxy8sPcvUDaVyTsuZLHR4zAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 71DgscFrk4i58O5GuTerI9g3JL0kz+6QaCstAllz9xw=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf5iAUVMAeaF1muIL7oFEIIxi7jxxhz21Q3Vp18RE6pIdk3cAH5ijeKqa+LM\n"
+ "T5Nb0I42Io4Z7BVjXG7sYVSxrospCOI4dqkl2ln3BKNuEFFT42xJwt+XGz3aMyK2\n"
+ "Cpp8w8I8nwU=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "lAZwD6YVic61NvJ0Iy62cSPuzJl5hJOFYNh9iSG/vn4/lVfnnCik+Gqi2v9pwItC\n"
+ "acwmutCSrMprmmFAW1dgzoU7GzUtdbxaGaOJdg8WwtO4JjFSzScTDB8R6sp0SCAI\n"
+ "PdbzAzJyiMqYcynyyCTiL77iwhUOBPzs2fXlivMtW2E=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 Oyo/eES+/wsgse1f+YSiJDGatBDaiB4fASf7vJ7GxFeD4OfLbB7OYa4hYNEo5NBssNt/PA55AQVSL8hvzBE3Cg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "wdk26ZtS1H81IxcUThyirANLoszrnYYhOMP57YRAUDEzUr88X6yNDZ5S0tLl+FoT\n"
+ "9XlEVrpN7Z3k4N9WloWb0o/zVVidPMRVwt8YQakSgR8axzMQg6QhQ6zXTiYhiXa4\n"
+ "mawlwYFXsaVDSIIqYA2CudIyF3UBRZuTbw0CFZElMWc=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index d7b5e1b..20863bf 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -352,7 +352,7 @@ test_dir_formats(void *arg)
#include "failing_routerdescs.inc"
static void
-test_dir_routerparse_bad(void *arg)
+test_dir_routerinfo_parsing(void *arg)
{
(void) arg;
@@ -377,6 +377,8 @@ test_dir_routerparse_bad(void *arg)
CHECK_OK(EX_RI_MINIMAL);
CHECK_OK(EX_RI_MAXIMAL);
+ CHECK_OK(EX_RI_MINIMAL_ED);
+
/* good annotations prepended */
routerinfo_free(ri);
ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
@@ -3168,7 +3170,7 @@ test_dir_packages(void *arg)
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
DIR_LEGACY(formats),
- DIR(routerparse_bad, 0),
+ DIR(routerinfo_parsing, 0),
DIR(extrainfo_parsing, 0),
DIR(parse_router_list, TT_FORK),
DIR(load_routers, TT_FORK),
1
0
commit 79db24b3d5cb845b18d737bbc63510154f6a87c7
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu May 28 10:42:22 2015 -0400
Sign extrainfo documents with ed25519
Extrainfo documents are now ed-signed just as are router
descriptors, according to proposal 220. This patch also includes
some more tests for successful/failing parsing, and fixes a crash
bug in ed25519 descriptor parsing.
---
scripts/codegen/makedesc.py | 34 +-
src/or/or.h | 6 +
src/or/router.c | 90 +++-
src/or/router.h | 3 +-
src/or/routerlist.c | 1 +
src/or/routerparse.c | 95 ++++-
src/test/example_extrainfo.inc | 233 +++++++++++
src/test/failing_routerdescs.inc | 855 ++++++++++++++++++++++++++++++++++++++
src/test/test_dir.c | 43 ++
9 files changed, 1318 insertions(+), 42 deletions(-)
diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py
index 0ed1f7e..d4ba21e 100644
--- a/scripts/codegen/makedesc.py
+++ b/scripts/codegen/makedesc.py
@@ -16,6 +16,7 @@ import ctypes.util
import hashlib
import optparse
import os
+import re
import struct
import time
import UserDict
@@ -297,7 +298,7 @@ def signdesc(body, args_out=None):
return body.rstrip()
def print_c_string(ident, body):
- print "static const char EX %s[] =" % ident
+ print "static const char %s[] =" % ident
for line in body.split("\n"):
print ' "%s\\n"' %(line)
print " ;"
@@ -314,9 +315,9 @@ def emit_ei(name, body):
body = info.sign_desc(body)
print_c_string("EX_EI_%s"%name.upper(), body)
- print 'const char {NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
+ print 'const char EX_EI_{NAME}_FP[] = "{d.RSA_FINGERPRINT_NOSPACE}";'.format(
d=info, NAME=name.upper())
- prnit_c_string("%s_KEY"%name.upper(), d.RSA_IDENTITY)
+ print_c_string("EX_EI_%s_KEY"%name.upper(), info.RSA_IDENTITY)
def analyze(s):
fields = {}
@@ -330,6 +331,7 @@ def analyze(s):
return fields, s
def process_file(s):
+ fields, s = analyze(s)
try:
name = fields['name']
tp = fields['type']
@@ -343,25 +345,7 @@ def process_file(s):
else:
raise ValueError("unrecognized type")
-if 0:
- emit_ri("minimal_ed",
- """\
-router fred 127.0.0.1 9001 0 9002
-identity-ed25519
-{d.ED_CERT}
-signing-key
-{d.RSA_IDENTITY}
-onion-key
-{d.RSA_ONION_KEY}
-ntor-onion-key {d.NTOR_ONION_KEY}
-ntor-onion-key-crosscert {d.NTOR_CROSSCERT_SIGN}
-{d.NTOR_CROSSCERT}
-onion-key-crosscert
-{d.RSA_CROSSCERT_ED}
-published 2014-10-05 12:00:00
-bandwidth 1000 1000 1000
-reject *:*
-router-sig-ed25519 {d.ED_SIGNATURE}
-router-signature
-{d.RSA_SIGNATURE}
-""")
+if __name__ == '__main__':
+ import sys
+ for fn in sys.argv[1:]:
+ process_file(open(fn).read())
diff --git a/src/or/or.h b/src/or/or.h
index ba36ad8..714b1c6 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2004,6 +2004,8 @@ typedef int16_t country_t;
/** Information about another onion router in the network. */
typedef struct {
signed_descriptor_t cache_info;
+ /** A SHA256-digest of the extrainfo (if any) */
+ char extra_info_digest256[DIGEST256_LEN];
char *nickname; /**< Human-readable OR name. */
uint32_t addr; /**< IPv4 address of OR, in host order. */
@@ -2085,8 +2087,12 @@ typedef struct {
/** Information needed to keep and cache a signed extra-info document. */
typedef struct extrainfo_t {
signed_descriptor_t cache_info;
+ /** SHA256 digest of this document */
+ uint8_t digest256[DIGEST256_LEN];
/** The router's nickname. */
char nickname[MAX_NICKNAME_LEN+1];
+ /** Certificate for ed25519 signing key */
+ struct tor_cert_st *signing_key_cert;
/** True iff we found the right key for this extra-info, verified the
* signature, and found it to be bad. */
unsigned int bad_sig : 1;
diff --git a/src/or/router.c b/src/or/router.c
index 242ec05..c94667a 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1974,10 +1974,12 @@ router_rebuild_descriptor(int force)
ei->cache_info.is_extrainfo = 1;
strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
ei->cache_info.published_on = ri->cache_info.published_on;
+ ei->signing_key_cert = tor_cert_dup(get_master_signing_key_cert());
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
DIGEST_LEN);
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
- ei, get_server_identity_key()) < 0) {
+ ei, get_server_identity_key(),
+ get_master_signing_keypair()) < 0) {
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
extrainfo_free(ei);
ei = NULL;
@@ -1987,6 +1989,10 @@ router_rebuild_descriptor(int force)
router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
ei->cache_info.signed_descriptor_len,
ei->cache_info.signed_descriptor_digest);
+ crypto_digest256((char*) ei->digest256,
+ ei->cache_info.signed_descriptor_body,
+ ei->cache_info.signed_descriptor_len,
+ DIGEST_SHA256);
}
/* Now finish the router descriptor. */
@@ -1994,6 +2000,9 @@ router_rebuild_descriptor(int force)
memcpy(ri->cache_info.extra_info_digest,
ei->cache_info.signed_descriptor_digest,
DIGEST_LEN);
+ memcpy(ri->extra_info_digest256,
+ ei->digest256,
+ DIGEST256_LEN);
} else {
/* ri was allocated with tor_malloc_zero, so there is no need to
* zero ri->cache_info.extra_info_digest here. */
@@ -2319,8 +2328,7 @@ router_dump_router_to_string(routerinfo_t *router,
char digest[DIGEST256_LEN];
char published[ISO_TIME_LEN+1];
char fingerprint[FINGERPRINT_LEN+1];
- int has_extra_info_digest;
- char extra_info_digest[HEX_DIGEST_LEN+1];
+ char *extra_info_line = NULL;
size_t onion_pkeylen, identity_pkeylen;
char *family_line = NULL;
char *extra_or_address = NULL;
@@ -2457,12 +2465,19 @@ router_dump_router_to_string(routerinfo_t *router,
family_line = tor_strdup("");
}
- has_extra_info_digest =
- ! tor_digest_is_zero(router->cache_info.extra_info_digest);
-
- if (has_extra_info_digest) {
+ if (!tor_digest_is_zero(router->cache_info.extra_info_digest)) {
+ char extra_info_digest[HEX_DIGEST_LEN+1];
base16_encode(extra_info_digest, sizeof(extra_info_digest),
router->cache_info.extra_info_digest, DIGEST_LEN);
+ if (!tor_digest256_is_zero(router->extra_info_digest256)) {
+ char d256_64[BASE64_DIGEST256_LEN+1];
+ digest256_to_base64(d256_64, router->extra_info_digest256);
+ tor_asprintf(&extra_info_line, "extra-info-digest %s %s\n",
+ extra_info_digest, d256_64);
+ } else {
+ tor_asprintf(&extra_info_line, "extra-info-digest %s\n",
+ extra_info_digest);
+ }
}
if (router->ipv6_orport &&
@@ -2491,7 +2506,7 @@ router_dump_router_to_string(routerinfo_t *router,
"fingerprint %s\n"
"uptime %ld\n"
"bandwidth %d %d %d\n"
- "%s%s%s%s"
+ "%s%s"
"onion-key\n%s"
"signing-key\n%s"
"%s%s"
@@ -2509,9 +2524,7 @@ router_dump_router_to_string(routerinfo_t *router,
(int) router->bandwidthrate,
(int) router->bandwidthburst,
(int) router->bandwidthcapacity,
- has_extra_info_digest ? "extra-info-digest " : "",
- has_extra_info_digest ? extra_info_digest : "",
- has_extra_info_digest ? "\n" : "",
+ extra_info_line ? extra_info_line : "",
(options->DownloadExtraInfo || options->V3AuthoritativeDir) ?
"caches-extra-info\n" : "",
onion_pkey, identity_pkey,
@@ -2631,6 +2644,7 @@ router_dump_router_to_string(routerinfo_t *router,
tor_free(ed_cert_line);
tor_free(rsa_tap_cc_line);
tor_free(ntor_cc_line);
+ tor_free(extra_info_line);
return output;
}
@@ -2774,7 +2788,8 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
* success, negative on failure. */
int
extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
- crypto_pk_t *ident_key)
+ crypto_pk_t *ident_key,
+ const ed25519_keypair_t *signing_keypair)
{
const or_options_t *options = get_options();
char identity[HEX_DIGEST_LEN+1];
@@ -2784,18 +2799,44 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
int result;
static int write_stats_to_extrainfo = 1;
char sig[DIROBJ_MAX_SIG_LEN+1];
- char *s, *pre, *contents, *cp, *s_dup = NULL;
+ char *s = NULL, *pre, *contents, *cp, *s_dup = NULL;
time_t now = time(NULL);
smartlist_t *chunks = smartlist_new();
extrainfo_t *ei_tmp = NULL;
+ const int emit_ed_sigs = signing_keypair && extrainfo->signing_key_cert;
+ char *ed_cert_line = NULL;
base16_encode(identity, sizeof(identity),
extrainfo->cache_info.identity_digest, DIGEST_LEN);
format_iso_time(published, extrainfo->cache_info.published_on);
bandwidth_usage = rep_hist_get_bandwidth_lines();
+ if (emit_ed_sigs) {
+ if (!extrainfo->signing_key_cert->signing_key_included ||
+ !ed25519_pubkey_eq(&extrainfo->signing_key_cert->signed_key,
+ &signing_keypair->pubkey)) {
+ log_warn(LD_BUG, "Tried to sign a extrainfo descriptor with a "
+ "mismatched ed25519 key chain %d",
+ extrainfo->signing_key_cert->signing_key_included);
+ goto err;
+ }
+ char ed_cert_base64[256];
+ if (base64_encode(ed_cert_base64, sizeof(ed_cert_base64),
+ (const char*)extrainfo->signing_key_cert->encoded,
+ extrainfo->signing_key_cert->encoded_len) < 0) {
+ log_err(LD_BUG,"Couldn't base64-encode signing key certificate!");
+ goto err;
+ }
+ tor_asprintf(&ed_cert_line, "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "%s"
+ "-----END ED25519 CERT-----\n", ed_cert_base64);
+ } else {
+ ed_cert_line = tor_strdup("");
+ }
- tor_asprintf(&pre, "extra-info %s %s\npublished %s\n%s",
+ tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s",
extrainfo->nickname, identity,
+ ed_cert_line,
published, bandwidth_usage);
tor_free(bandwidth_usage);
smartlist_add(chunks, pre);
@@ -2855,6 +2896,23 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
}
}
+ if (emit_ed_sigs) {
+ char digest[DIGEST256_LEN];
+ smartlist_add(chunks, tor_strdup("router-sig-ed25519 "));
+ crypto_digest_smartlist_prefix(digest, DIGEST256_LEN,
+ ED_DESC_SIGNATURE_PREFIX,
+ chunks, "", DIGEST_SHA256);
+ ed25519_signature_t sig;
+ char buf[ED25519_SIG_BASE64_LEN+1];
+ if (ed25519_sign(&sig, (const uint8_t*)digest, DIGEST256_LEN,
+ signing_keypair) < 0)
+ goto err;
+ if (ed25519_signature_to_base64(buf, &sig) < 0)
+ goto err;
+
+ smartlist_add_asprintf(chunks, "%s\n", buf);
+ }
+
smartlist_add(chunks, tor_strdup("router-signature\n"));
s = smartlist_join_strings(chunks, "", 0, NULL);
@@ -2903,7 +2961,8 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
"adding statistics to this or any future "
"extra-info descriptors.");
write_stats_to_extrainfo = 0;
- result = extrainfo_dump_to_string(s_out, extrainfo, ident_key);
+ result = extrainfo_dump_to_string(s_out, extrainfo, ident_key,
+ signing_keypair);
goto done;
} else {
log_warn(LD_BUG, "We just generated an extrainfo descriptor we "
@@ -2925,6 +2984,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
smartlist_free(chunks);
tor_free(s_dup);
+ tor_free(ed_cert_line);
extrainfo_free(ei_tmp);
return result;
diff --git a/src/or/router.h b/src/or/router.h
index cb813c6..695cfd3 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -109,7 +109,8 @@ int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr);
int router_has_orport(const routerinfo_t *router,
const tor_addr_port_t *orport);
int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
- crypto_pk_t *ident_key);
+ crypto_pk_t *ident_key,
+ const ed25519_keypair_t *signing_keypair);
int is_legal_nickname(const char *s);
int is_legal_nickname_or_hexdigest(const char *s);
int is_legal_hexdigest(const char *s);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index dbb93e4..b2784ae 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -2684,6 +2684,7 @@ extrainfo_free(extrainfo_t *extrainfo)
{
if (!extrainfo)
return;
+ tor_cert_free(extrainfo->signing_key_cert);
tor_free(extrainfo->cache_info.signed_descriptor_body);
tor_free(extrainfo->pending_sig);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index e1bc295..03a5eaf 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -324,6 +324,8 @@ static token_rule_t routerdesc_token_table[] = {
static token_rule_t extrainfo_token_table[] = {
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
+ T01("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
+ T01("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
@@ -1398,7 +1400,7 @@ router_parse_entry_from_string(const char *s, const char *end,
ntor_cc_cert = tor_cert_parse((const uint8_t*)cc_ntor_tok->object_body,
cc_ntor_tok->object_size);
- if (!cc_ntor_tok) {
+ if (!ntor_cc_cert) {
log_warn(LD_DIR, "Couldn't parse ntor-onion-key-crosscert cert");
goto err;
}
@@ -1564,6 +1566,14 @@ router_parse_entry_from_string(const char *s, const char *end,
} else {
log_warn(LD_DIR, "Invalid extra info digest %s", escaped(tok->args[0]));
}
+
+ if (tok->n_args >= 2) {
+ if (digest256_from_base64(router->extra_info_digest256, tok->args[1])
+ < 0) {
+ log_warn(LD_DIR, "Invalid extra info digest256 %s",
+ escaped(tok->args[1]));
+ }
+ }
}
if (find_opt_by_keyword(tokens, K_HIDDEN_SERVICE_DIR)) {
@@ -1666,6 +1676,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
goto err;
}
+ /* XXXX Accept this in position 1 too, and ed identity in position 0. */
tok = smartlist_get(tokens,0);
if (tok->tp != K_EXTRA_INFO) {
log_warn(LD_DIR,"Entry does not start with \"extra-info\"");
@@ -1678,6 +1689,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
extrainfo->cache_info.signed_descriptor_body = tor_memdup_nulterm(s,end-s);
extrainfo->cache_info.signed_descriptor_len = end-s;
memcpy(extrainfo->cache_info.signed_descriptor_digest, digest, DIGEST_LEN);
+ crypto_digest256((char*)extrainfo->digest256, s, end-s, DIGEST_SHA256);
tor_assert(tok->n_args >= 2);
if (!is_legal_nickname(tok->args[0])) {
@@ -1700,6 +1712,87 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
goto err;
}
+ {
+ directory_token_t *ed_sig_tok, *ed_cert_tok;
+ ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519);
+ ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519);
+ int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok;
+ if (n_ed_toks != 0 && n_ed_toks != 2) {
+ log_warn(LD_DIR, "Router descriptor with only partial ed25519/"
+ "cross-certification support");
+ goto err;
+ }
+ if (ed_sig_tok) {
+ tor_assert(ed_cert_tok);
+ const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok);
+ if (ed_cert_token_pos != 1) {
+ /* Accept this in position 0 XXXX */
+ log_warn(LD_DIR, "Ed25519 certificate in wrong position");
+ goto err;
+ }
+ if (ed_sig_tok != smartlist_get(tokens, smartlist_len(tokens)-2)) {
+ log_warn(LD_DIR, "Ed25519 signature in wrong position");
+ goto err;
+ }
+ if (strcmp(ed_cert_tok->object_type, "ED25519 CERT")) {
+ log_warn(LD_DIR, "Wrong object type on identity-ed25519 in decriptor");
+ goto err;
+ }
+
+ uint8_t d256[DIGEST256_LEN];
+ const char *signed_start, *signed_end;
+ tor_cert_t *cert = tor_cert_parse(
+ (const uint8_t*)ed_cert_tok->object_body,
+ ed_cert_tok->object_size);
+ if (! cert) {
+ log_warn(LD_DIR, "Couldn't parse ed25519 cert");
+ goto err;
+ }
+ extrainfo->signing_key_cert = cert; /* makes sure it gets freed. */
+ if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
+ ! cert->signing_key_included) {
+ log_warn(LD_DIR, "Invalid form for ed25519 cert");
+ goto err;
+ }
+
+ if (router_get_hash_impl_helper(s, end-s, "extra-info ",
+ "\nrouter-sig-ed25519",
+ ' ', &signed_start, &signed_end) < 0) {
+ log_warn(LD_DIR, "Can't find ed25519-signed portion of extrainfo");
+ goto err;
+ }
+ crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
+ crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX,
+ strlen(ED_DESC_SIGNATURE_PREFIX));
+ crypto_digest_add_bytes(d, signed_start, signed_end-signed_start);
+ crypto_digest_get_digest(d, (char*)d256, sizeof(d256));
+ crypto_digest_free(d);
+
+ ed25519_checkable_t check[2];
+ int check_ok[2];
+ if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
+ log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
+ goto err;
+ }
+
+ if (ed25519_signature_from_base64(&check[1].signature,
+ ed_sig_tok->args[0])<0) {
+ log_warn(LD_DIR, "Couldn't decode ed25519 signature");
+ goto err;
+ }
+ check[1].pubkey = &cert->signed_key;
+ check[1].msg = d256;
+ check[1].len = DIGEST256_LEN;
+
+ if (ed25519_checksig_batch(check_ok, check, 2) < 0) {
+ log_warn(LD_DIR, "Incorrect ed25519 signature(s)");
+ goto err;
+ }
+ /* We don't check the certificate expiration time: checking that it
+ * matches the cert in the router descriptor is adequate. */
+ }
+ }
+
/* We've checked everything that's covered by the hash. */
can_dl_again = 1;
diff --git a/src/test/example_extrainfo.inc b/src/test/example_extrainfo.inc
index 606279a..e096afd 100644
--- a/src/test/example_extrainfo.inc
+++ b/src/test/example_extrainfo.inc
@@ -190,3 +190,236 @@ static const char EX_EI_BAD_PUBLISHED_KEY[] =
"BvG6303md3INygg+KP49RvWEJR/cU4RZ9QfHpORxH2OocMyRedw2rLex2E7jNNSi\n"
"52yd1sHFYI8ZQ4aff+ZHUjJUGKRyqpbc8okVbq/Rl7vug0dd12eHAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_GOOD_ED_EI[] =
+ "extra-info emma A692FE045C32B5E3A54B52882EF678A9DAC46A73\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AYgHn/OKR8GHBlscN5VkO73wA9jSci8QgTM30615ZT44AQAgBAC08woT\n"
+ "MBZpKzRcaoEJhEG7+RmuYtnB2+nODk9IRIs8ZoyYPTZ6dLzI+MLMmtzUuo/Wmvw0\n"
+ "PflTyCb2RlWitOEhAErWH3Z9UmYGnzM/COId0Fe3ScSriyvRoFnJY1+GVAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "GvmCmIGgbC1DeawRyRuChy62VmBOG0EviryG/a2qSZiFy0iPPwqSp5ZyZDQEIEId\n"
+ "kkk1zPzK1+S3fmgOAXyXGH0r4YFkoLGnhMk07BoEwi6HEXzjJsabmcNkOHfaOWgs\n"
+ "/5nvnLfcmxL4c6FstZ7t9VQpE06y3GU0zwBeIy1qjp0=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_GOOD_ED_EI_FP[] = "A692FE045C32B5E3A54B52882EF678A9DAC46A73";
+static const char EX_EI_GOOD_ED_EI_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM3jdYwjwGxDWYj/vyFkQT7RgeCNIn89Ei6D2+L/fdtFnqrMXOreFFHL\n"
+ "C7CK2v2uN3v+uXxfb5lADz3NcalxJrCfGTGtaBk7PwMZraTSh2luFKOvSRBQCmB1\n"
+ "yD5N0QqnIhBJoGr6NITpbWyiTKWvYLjl9PZd9af8e8jQCAa5P1j1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISSING_SIG[] =
+ "extra-info rachel 2A7521497B91A8437021515308A47491164EDBA1\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AT2/T71LFYHiI1ppwNiuaewIu2Hq+GWWQ85O8gpWcUxeAQAgBAC2dgYu\n"
+ "moxhtuip7GVlthT9iomZKba1IllVa7uE1u2uO9BUYZQWXciFt7OnNzMH5mlffwxB\n"
+ "1dWCl+G5nbOsV5jYLbfhrF5afZotf+EQTfob4cCH79AV223LPcySbTHTtQ4=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "oypRD2IZQ5EttOE8dvofrW80nnBfijSkvYzBrM6H4KVeayRYvWfmi96dYO6ybMqm\n"
+ "Yp7Gs3ngqeeNdfHtkRPuQVUXUGYZgBTvYItuagnFlFgRqaHy0knwUIVOL35eqWYx\n"
+ "xSbQKA7fglxEDMFs/RK7FRP4dWc731ZMt5wzzfJHZ8E=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISSING_SIG_FP[] = "2A7521497B91A8437021515308A47491164EDBA1";
+static const char EX_EI_ED_MISSING_SIG_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOOB8ccxbtk2dB5FuKFhGndDcO6STNjB6KiG0b9X2QwKrOZMfmXSigto\n"
+ "mtC1JfPTxECayRjLSiP/9UD8iTVvlcnc8mMWBGM12Pa/KoCZRn7McHI3JJ7n9lfn\n"
+ "qw9+iZ9b/rBimzOb3W6k3uxzg9r8secdq4jJwTnwSjTObgxZtC8/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISSING_CERT[] =
+ "extra-info lynne E88E43E86015345A323D93D825C33E4AD1028F65\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 H4gKIKm5K9Pfkriy7SlMUD6BdYVp6B5mXKzR/rTyYlpH0tEZ4Fx2hlHNfNNdWXJieXzKZQZo8e7SOVzvrAC3CQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "dIrbQjK5T9t5KM8CpsMF85hh2i060oPIxzYQMgE1q4j99dtb/n7SE8nhj1Sjij4D\n"
+ "7JvTjGdLHi3bFSxXaSmla0wxD9PUYFN7VsBQmwSaDrqrzJFb1SGwZuzW1IEZ7BBi\n"
+ "H0czsxEteg5hcNRwISj5WVthuWmau9v13MijtZGSK40=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISSING_CERT_FP[] = "E88E43E86015345A323D93D825C33E4AD1028F65";
+static const char EX_EI_ED_MISSING_CERT_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALjA/geb0TR9rp/UPvLhABQpB0XUDYuZAnLkrv+i7AAV7FemTDveEGnc\n"
+ "XdXNSusO1mHOquvr0YYKPhwauInxD56S8QOzLYiWWajGq8XHARQ33b4/9K2TUrAx\n"
+ "W9HTHV1U1zrPlCJtrkbjxsYoHpUg5ljzM7FGYGY5xuvyHu18SQvzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_CERT1[] =
+ "extra-info marcie F78D8A655607D32281D02144817A4F1D26AE520F\n"
+ "identity-ed25519\n"
+ "-----BEGIN PLAGICAL SPELL-----\n"
+ "aaaa\n"
+ "-----END PLAGICAL SPELL\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 KQJ+2AH7EkkjrD0RtDtUAIr+Vc7wndwILYnoUxFLSJiTP+5fMi54eFF/f1OgkG8gYyTh8phMij9WOxK/dsOpBg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "XWD+P25AH6moi79j20Si3hqKGcJDws+FORL1MTu+GeJLV1mp5CR9N83UH4ffulcL\n"
+ "CpSSBDL/j74HqapzW7QvBx3FilaNT55GvcobZDFK4TKkCEyEmcuWKpEceBS7JTTV\n"
+ "SvwZeOObTjWPafELbsc/gI9Rh5Idwu7mZt3ZVntCGaQ=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_CERT1_FP[] = "F78D8A655607D32281D02144817A4F1D26AE520F";
+static const char EX_EI_ED_BAD_CERT1_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMlR46JhxsCmWYtmIB/JjTV2TUYIhJLmHy+X7FfkK3ZVQvvl9/3GSXFL\n"
+ "3USfyf3j34XLh8An7pJBi9LAHkIXgnRbglCud7dXoexabmC+c2mSbw5RnuxDGEwz\n"
+ "krXUph/r2b+2UY1CgEt28nFigaHrIQbCmF4szFX/2GPYCLi5SrRNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_CERT2[] =
+ "extra-info jaeger 7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55Acpw27GZBdwGCgawCj2F/DPadt8F/9DnEWywEew1Yi3qAOtLpCB8KXL7\n"
+ "4w5deFW2RBg8qTondNSUvAmwYLbLjNXMmgA3+nkoJOP3fcmQMHz1jm5xzgs2lCVP\n"
+ "t5txApaBIA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 DRQ4MLOGosBbW8M+17klNu8uWVkPxErmmEYoSo6OuH2Tzrcs6sUY+8Xi2qLoV1SbOugJ214Htl0I+6ceag+vBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DfdA+DbuN9nVJNujuSY5wNCDLk7Hfzkrde/sK0hVmZRvivtpF/Fy/dVQHHGNFY5i\n"
+ "L1cESAgq9HLdbHU+hcc08XXxTIaGwvoklcJClcG3ENVBWkTXbJNT+ifr7chEagIi\n"
+ "cVrtU6RVmzldSbyir8V/Z4S/Cm67gYAgjM5gfoFUqDs=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+const char EX_EI_ED_BAD_CERT2_FP[] = "7C2B42E783C4E0EB0CC3BDB37385D16737BACFBD";
+static const char EX_EI_ED_BAD_CERT2_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALAM1F/0XJEsbxIQqb3+ObX/yGVnq9of8Q9sLsmxffD6hwVpCqnV3lTg\n"
+ "iC6+xZ/bSlTGLPi0k8QLCaTmYxgKwmlMPpbQZ4kpZUrsb9flKdChMN7w8hd48pY9\n"
+ "lu8QiAEgErsl5rCCJIHHjrxxM/Cnd0TnedRnj/Z2YqpNx/ggsmsRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_SIG1[] =
+ "extra-info vary 5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AbPp++GrRb6WphSu+PkMaYsqY/beiLBmtiV3YP5i2JkKAQAgBABKXjg1\n"
+ "aiz2JfQpNOG308i2EojnUAZEk0C0x9g2BAAXGL63sv3eO/qrlytsG1x2hkcamxFn\n"
+ "LmfZBb/prqe1Vy4wABuhqWHAUtM29vXR6lpiCJeddt9Pa8XVy/tgWLX6TAw=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 a7K8nwfg+HrdlSGQwr9rnLBq0qozkyZZs6d6aiLEiXGdhV1r9KJncmlQ5SNoY/zMQlyQm8EV5rCyBiVliKQ1Bw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "xhZX8Qmgft51NJ7eMd4vrESzf/VdxDrBz7hgn8K+5bLtZUksG0s6s7IyGRYWQtp4\n"
+ "/7oc9sYe3lcQiUN2K7DkeBDlL8Pcsl8aIlKuujWomCE3j0TIu+8XK6oJeo7eYic+\n"
+ "IA7EwVbdZsKsW5/eJVzbX2eO0a5zyJ5RIYotFNYNCSE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_SIG1_FP[] = "5AC3A538FEEFC6F9FCC5FA0CE64704396C30D62A";
+static const char EX_EI_ED_BAD_SIG1_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMvb6SuoIkPfBkJgQuo5aQDepAs1kEETZ9VXotMlhB0JJikrqBrAAz+7\n"
+ "rjIJ4JsBaeQuN0Z5ksXk2ebxtef7oMIUs37NfekLQHbNR0VsXkFXPEGmOAqpZjW0\n"
+ "P524eHqybWYZTckvZtUvKI3xYGD6kEEkz4qmV6dcExU1OiAYO9jrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_BAD_SIG2[] =
+ "extra-info coward 7F1D4DD477E340C6D6B389FAC26EDC746113082F\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf56AZkSDiFZ1QaiLJhcKdFDE5Kei/sPaPEIEoPMGP4BvOVXAQAgBAAlRLzx\n"
+ "U029tgIL9BRe47MVgcPJGy48db6ntzhjil7iOnWKT70z2LorUD5CZoLJs72TjB6r\n"
+ "8+HYNyFLEM6dvytWZf9NA5gLdhogbFcUk/R3gbNepmCF7XoZjbhPIp8zOwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-sig-ed25519 yfV+GySMIP1fw1oVa1C1de4XOWBqT4pUtEmSHq1h+WrLBNCh3/HZWvNC/denf2YVntuQrMLCJEv5ZaFKU+AIDQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "g+BWq69i9CP19va2cYMAXCQ6jK3IG0VmNYspjjUFgmFpJKGG6bHeOkuy1GXp47fG\n"
+ "LzZ3OPfJLptxU5AOQDUUYf25hu9uSl6gyknCzsszFs5n6ticuNejvcpzw6UfO1LP\n"
+ "5u+mGJlgpcMtmSraImDZrRipmZ3oRWvEULltlvzGQcQ=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_BAD_SIG2_FP[] = "7F1D4DD477E340C6D6B389FAC26EDC746113082F";
+static const char EX_EI_ED_BAD_SIG2_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALzOyfCEUZnvCyhlyMctPkdXg/XRE3Cr6QgyzdKf5kQbUiu2n0FgSHOX\n"
+ "iP5gfq8sO9eVeTPZtjE7/+KiR8aQJECy+eoye+lpsfm3tXpLxnpOIgL4DlURxlo/\n"
+ "rfCyv30SYBN9j62qgU9m6U2ydI0tH7/9Ep8yIY/QL8me8VAjLbf/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
+static const char EX_EI_ED_MISPLACED_CERT[] =
+ "extra-info msselene 3B788BD0CE348BC5CED48313307C78175EB6D0F3\n"
+ "published 2014-10-05 20:07:00\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AWBcqjzLESDuLNGsqQ/tHn32XueXwj2fDlgEy/kQNVf/AQAgBAAFOegg\n"
+ "XY1LR82xE9ohAYJxYpwJJw0YfXsBhGHqfakEoBtSgFJ3cQAUXZQX4lX6G8IxAlQB\n"
+ "7Rj7dPQuQRUmqD1yyKb/ScBgCa8esxlhNlATz47kRNR38A3TcoJ4c1Zv6AE=\n"
+ "-----END ED25519 CERT-----\n"
+ "router-sig-ed25519 Q52JKH9/iMsr1jIPlWHHxakSBvyqjT1gzL944vad4OhzCZuNuAYGWyWSGzTb1DVmBqqbAUq73TiZKAz77YLNCQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "YplvAIwExGf5/L8AoroVQXtGm+26EffrxKBArMKn0zS1NOOie1p0oF/+qJg+rNWU\n"
+ "6cv3Anf188EXGlkUOddavgVH8CQbvve2nHSfIAPxjgEX9QNXbM5CiaMwgpCewXnF\n"
+ "UoNBVo5tydeLHVns15MBg/JNIxUQMd6svMoPp2WqmaE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISPLACED_CERT_FP[] = "3B788BD0CE348BC5CED48313307C78175EB6D0F3";
+static const char EX_EI_ED_MISPLACED_CERT_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALTwNqhTprg1oC6bEbDqwIYBoER6prqUXQFbwbFDn+ekXhZj8vltgGwp\n"
+ "aDGl9ceZWDKfi+reR6rZXjAJGctmv0VHkfe7maUX4FC/d2T8N8DvS+3IvJzFMpbT\n"
+ "O0fFrDTrCSnPikqFfQWnlP8yoF5vO7wo0jRRY432fLRXg9WqVzdrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+static const char EX_EI_ED_MISPLACED_SIG[] =
+ "extra-info grazie 384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AcGuIBoa6TBqD8Gg5atcwp/+r9ThxIBkULmPv9OSGhv+AQAgBACXH13y\n"
+ "mUvdpcN6oRN1nX6mnH40LyfYR5um8xogJZk3oINse5cRNrfMgVWiBpDlJZAwlDDa\n"
+ "lx99hzuZBong+CiOcnEvLMsBaVJmNTm5mpdetYclZpl0g8QEXznXXeRBMgM=\n"
+ "-----END ED25519 CERT-----\n"
+ "router-sig-ed25519 TxuO86dQ3pUaIY2raQ3hoDBmh4TTPC0OVgY98T5cf6Y+sHyiELCkkKQ3lqqXCjqnbTLr1/4riH980JoWPpR+Dw\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "kV2CtArl1VF1nUSyHL00mO3nEdNxlQU5N7/hZNTd+45lej5Veb+6vb4ujelsFERJ\n"
+ "YoxwIs6SuKAR4orQytCL0e+GgZsrg8zGTveEtMX/+u//OcCwQBYEevR5duBZjVw/\n"
+ "yzpEHwdIdB2PPyDBLkf1VKnP7uDj059tXiQRWl7LXgE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+const char EX_EI_ED_MISPLACED_SIG_FP[] = "384E40A5DEED4AB1D8A74F1FCBDB18B7C24A8284";
+static const char EX_EI_ED_MISPLACED_SIG_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK0HgOCG/6433VCrwz/vhk3cKmyOfenCp0GZ4DIUwPWt4DeyP4nTbN6T\n"
+ "1HJ1H8+hXC9bMuI4m43IWrzgLycQ9UaskUn372ZjHP9InPqHMJU6GQ7vZUe9Tgza\n"
+ "qnBdRPoxnrZzUOzlvatGrePt0hDiOZaMtDAkeEojFp9Wp2ZN7+tZAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ ;
+
diff --git a/src/test/failing_routerdescs.inc b/src/test/failing_routerdescs.inc
index db3fd70..e2b72c5 100644
--- a/src/test/failing_routerdescs.inc
+++ b/src/test/failing_routerdescs.inc
@@ -712,3 +712,858 @@ static const char EX_RI_MINIMAL_ED[] =
"-----END SIGNATURE-----\n"
"\n"
;
+
+static const char EX_RI_ED_MISSING_CROSSCERT[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AfsyyHhGluzfESzL4LP8AhFEm83+GkFoHbe1KnssVngHAQAgBABNzJRw\n"
+ "BLXT3QMlic0QZ4eG612wkfSRS4yzONIbATKLHIgyzgGiGl4gaSX0JTeHeGfIlu7P\n"
+ "5SKocZVNxm1mp55PG+tgBqHObDRJRSgbOyUbUgfOtcbQGUeVgUlFKWZ9FAY=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMqT7K8cEzWIaPNXbNgvoZ5ejavoszI2OjW9XXetPD/S2f+N7TfQXHBW\n"
+ "bnjpgj87gmk59w0OXTMCv+XofZ0xOy2YR/jG5l1VJIvqgJhhFJ8oSEGVzy+97Ekn\n"
+ "Lb1FEYuVfVxSxnU2jhHW6KPtee/gvuyRI/TvZuwmYWxLRpikVn4pAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM4nITNe8UykgsIuo5czSSSl3Okr1K+UVWTzDGLznDg77MkLy7mydmk9\n"
+ "vf51OB+ogQhozYKIh9uHvecOzY4EhSIuKhui4hNyQklD9juGoW7RVTSpGdYT1ymp\n"
+ "dDYS30JBPwCZ7KjdMtXiU8ch2WgbzYBuI+JfjwOhfcsuNC9QPfbfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key lx8o212IYw5Ly2KbH2ua1+fr4YvDq5nKd7LHMdPzTGo=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "cv1yL8HhQzQfjzkSosziu2kMecNUQGle4d103h6tVMoZS1ua1xiDpVKeuWPl9Z0+\n"
+ "wpFwRkOmK0HpNeOXCNHJwfJaWBGQXunB3WQ6Oi1BLilwLtWQixGTYG0hZ6xYLTnX\n"
+ "PdSQIbsohSgCzo9HLTAgTnkyBgklIO1PHJBJsaNOwfI=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+
+static const char EX_RI_ED_MISSING_CROSSCERT2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AXXgm0CUWQr+rxvgdIslqaFdBiwosT+9PaC8zOxYGIsZAQAgBAA6yeH7\n"
+ "3AfGIGuDpVihVUUo0QwguWDPwk2dBJan7B0qgPWF5Y4YL5XDh2nMatskUrtUGCr1\n"
+ "abLYlJPozmYd6QBSv6eyBfITS/oNOMyZpjDiIjcLQD08tVQ2Jho+WmN64wc=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMdyTK/VPZloLUaLsvj1+NOFs33/E9HmA0VgvZ1nNUrR+PxSR71QF7Tw\n"
+ "DKz+/p2rJE+MPfQ/Na3dH0vH4CDZ+FH2m4A8SB9emF8aKxdc/7KCjQNDQCNlEQYn\n"
+ "O9WvZJhbNPHUmX0z4OotI+Sk3qBzVHu0BGDsPYC9gwszIumDUILxAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL8o6CJiLfW4vdRFvJ2nFt/H/ei0ov83rilOuwSmNORmL9lvnHY++HrD\n"
+ "dmEEvBv74xqWJxGbJ6OQ3VOwRpf2X/cb4gAvsQDqDmNwpJsrPYRQVXp/KY/8z7bJ\n"
+ "dM4CjcsuJHHmj3yc3iCzgqt/Xr6vR24X4bee12/bP7R8IETvWoiHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key qpNEGrLMVn28Odonk/nDtZq1ljy0fBshwgoAm4X1yzQ=\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "i4RKGIeaUrO6nzfdtb6j+ijYJh1Vgc9bsHMpW9cVCOjoJKFW9xljgl9xp6LytviN\n"
+ "ppKYCt9/JflbZUZjny34ESltPGrdquvHe8TtdQazjiZBWQok/kKnx2i+PioRF/xI\n"
+ "P8D0512kbJjXSuuq9tGl94RKPM/ySGjkTJPevN4TaJE=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 pMAOpepn5Q9MxcV9+Yiftu50oBzBsItQcBV9qdZCIt3lvSFqFY9+wJjaShvW3N9ICHkunrC0h/w5VEfx4SQdDA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Du5fJYDzvEeGqKTJwgaQsJJgz39K/J4qEM2TZ3Mh0XuDM1ZWDtjyzP03PaPQqbJ1\n"
+ "FsN5IStjOqN3O1IWuLzGaZGpGVuqcyYOxjs7REkGQn2LfqCjpzjaAdcsL0fI4ain\n"
+ "o/in8GQ6S/qhsx8enKlN0tffTmWmH9bmmVz0+yYmBSo=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_MISSING_CROSSCERT_SIGN[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AfoVFYuJnDNBWbjbTqfXACUtXWPipmqEYC++Ok/+4VoFAQAgBADH7JzI\n"
+ "fjSMV158AMiftgNY+KyHYIECuL9SnV3CSO+8+I7+r9n+A3DQQmGLULo/uZnkbteJ\n"
+ "+uy6uRG4kW0fnuBlKhseJQm9hjNGWzC8hmebp1M+bxwG41EGI7BZvnTrRgM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALEqlijoFIDX1y1i5zfei8DuDIsFtSw56PGgnMRGcybwD1PRQCheCUZM\n"
+ "erQgFCWjgLgvGJERBK/oILW1dFXp4MAR5RgnrPGTfWTinCj32obMLN1gIczpq6a9\n"
+ "P9uv6Cz0ApSxpA/AuvjyAZwQKbUXuMvIY4aTprAKSqqVohk6E+E1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMZbbBjGV7xPri4XNmejq4add93p+XsWlsfbM930bcC2JZiwg4g4cq6W\n"
+ "idl8VDmCXeaWg5y3kb82Ch/Q9vPG0QYQbXxUA3JxQKKbcEK3QsEvqQh8Nb7krILK\n"
+ "YnSGAnLG2Nc3PnKb7Wpb8M3rAysC5O99Gq1mSfm8ntj3zlIM7NSHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key CYcpfIF4T9PJcfROfVJTUYl0zNd4Ia5u0L9eng/EBSo=\n"
+ "ntor-onion-key-crosscert\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AcfsnMh+NIxXXnwAyJ+2A1j4rIdggQK4v1KdXcJI77z4AMRc2LxiKbyr\n"
+ "fqRVynHuB031C4TN/HAlNPBjVoRvQRgzpiyyoyCqMDxLZdM8KtzdLLeqZJOXtWod\n"
+ "UXbYG3L70go=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BRwRAK2lWxWGS49k8gXFHLEQ/h4k8gOQxM0WgCaN4LjAOilLHFjsjXkmKgttVpHl\n"
+ "f0V9ebSf+HgkpQnDSD8ittnr/0QaohUbD4lzslW4e/tQYEiM46soSoFft85J6U3G\n"
+ "D3D63+GmaOfIaa4nv7CD0Rw/Jz0zTuyEuARsdJIr1IY=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 7XfV5r7FXbXPEvrxlecWmAJxat/6VT+/4tE5cHrQnvLM4zslysstWH6/AfIfcmUuDlQ0watmfg1MvVnjavcfDA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "eigLL3S/oMGL2tJULt9bl3S0iY+YIxdKeGFCcKZci59zD786m+n+BpGM3yPpvrXr\n"
+ "bGvl4IBqCa1I+TqPP1rM9lIEcUWaBT7Zo5uMcL1o+zZl1ZWPWVVKP5hC5ehDueu8\n"
+ "/blzNhTEFAp23ftDK9PnFf+bXxqbgKkEoZsxnd3e9Ns=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+
+static const char EX_RI_ED_BAD_SIG1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AR8QC+SNBpPOTVY198IQBANNwZjy+SBqQNxfzjEmo204AQAgBABjz4FP\n"
+ "zW/G+fu7YirvANvvqJeb7S1YYJnf6IrPaPsPRzDqJcO3/sTzFC5OSb9iJmzQAWnn\n"
+ "ADPOl+nOJC58XJnJ7CUJdPtyoVdMvUiUT/Jtg4RuCN1iDaDYaTh2VavImAY=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKuLC0kzCBTV6+WPZcAOQPKjqbjvMIyaehIQS1o90dYM+Tosrhtk3bw8\n"
+ "QBLMaiWL3kfIWPZuWi2ai40dmqAXMrXH3yBgKRNZ6zZSbUUuJ1IknqmrQ2PKjC/p\n"
+ "sIW2awC6Tq+zrZ7vntDb02zY857vP59j8eolTDg1Vvn6l2ieL+WhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMnBQPOJBQLZ3NAa70n6lGZGvS3DYZFNOZ2QnHVeVvOSFIFsuvHtnUdX\n"
+ "svDafznYAuRFRVqJS2xtKKGu0cmy6ulEbBF+4uAEMwQY7dGRPMgVF1Z33U0CSd08\n"
+ "ChCJGPTE7tGGuoeSIGN3mfC4z2v9SP3McBdAiLHisPzaUjfRTcwRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key W8fUvBpKBoePmqb70rdJUcRT0NhELDWH7/BSXJtkXS0=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AWPPgU/Nb8b5+7tiKu8A2++ol5vtLVhgmd/ois9o+w9HAAPwWqmL0HXa\n"
+ "bYKrKPWQYnpQHQ3Ty0MmCgj3ABF940JURnV161RlN8CRAOJaeQ0Z8wBRLFC1NqLT\n"
+ "+GVdtewGeQA=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "x0vT5Wv7Guc0/Vu2BqomWwenh8oda9+8K/7ILi5GQL/WC29Tj51i0EE7PVSnSMJ7\n"
+ "33I/V+N5neauqWnbg7TxYaLsPfr6SpPTpBL1Xt0OiwT1//PvPYZ1gCcF3ig3KcfI\n"
+ "mreQd5C5Vri6ukWkMtz/zNDaDpDanzaNXTdaUXmFHF4=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Hci/Br1+NNymDZBmQy1QWMlCeLe8Z1vtZ2ZTj42jDhWg1OC/v72ptI072x4x5cmi\n"
+ "X3EONy8wQUvTNowkfG6/V/B768C7FYJYBId1GAFZZymXnON9zUYnE3z1J20eu6l6\n"
+ "QepmmdvRmteIHMQ7HLSrBuDuXZUDJD0yXm6g8bMT+Ek=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AW8fyx54c7vQQA/AmShAitFP7XI1CLdifEVPSrFKwYq6AQAgBAChqjVA\n"
+ "/wKKJZ30BIQoXe5+QMiPR6meNxF1lBttQ2t5AhauZbH5XzRhZkdGo114wuyPNEM9\n"
+ "PrBwp5akTtari9doVy6gs3McqdoIbRdWevpaGj5g5oOEOtA9b5UNWQSwUAs=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALp0Croi9zhpGxi9sUj54jr/flZdzxVVS+8VNldJG2c1soSx8kwlwotu\n"
+ "7mGGudJDAzDHGo5F5CCPEfQov2OmDehpefYUz/AaMLly6PrLRJlcUcpLogGf1+KU\n"
+ "1lLwE8kanXUkgvDhVQiFvNjy2Dxxuv3AHH4WdZZfbMbm8FJRGoHzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMoI9vQT4g2sV2dViGOWOzxckk367T9sMjVwcYfJCmnixGxjWeKScQFB\n"
+ "K9v1uK73cfZR8AxiUGK4/iOX/9en14mJOGF7fftAqypFLAt1TBvb07IgXljOBoHc\n"
+ "Paw4oZoJQzEoazt0Oa181LyNnNIoaZpHVZd1+a1Gs1gKoM4xDBv1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key KjyvXYkMcpke5ZsUYf2gZAUNeEoz8NAwYoQvvbcDGiw=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AaGqNUD/AoolnfQEhChd7n5AyI9HqZ43EXWUG21Da3kCAI6MRHm7GpCF\n"
+ "/3zDGR/6jKe625uFZX9HpLt6FgAdGSJeMQ9W4Np9VkrFXAB3gvh7xxRzSgZ1rXgR\n"
+ "lUomgi7N1gc=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "xJXvCCpP4ExBuT3OTsdn2HJB0HidupmQq5zBh8fx/ox6+047ZBOM7+hVxxWapcMg\n"
+ "PMXbcLD4L/FCBpA/rjnFUE/9kztdq7FH/rOdi0nB6FZWhwDcsZuyfvbnDTxz5iHJ\n"
+ "87gd5nXA5PE649SRCxW5LX0OtSiPFPazu4KyyBgnTIM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "tk4kBNYqB8utOmX30HrV8YfnwBXYODIiL3M/juRS6nPn0uvbW7pjoZ3ck/ahgW+6\n"
+ "FNQsgTJnEADCWS1r6v7PcvzQjtrOUUpNxGJxYw1r8yZkvmIxSQD6GMzuTxq7o1VA\n"
+ "/wZYDLonLhCWRdPjxnrl12+z92NdyISJCHMLRVqs2QY=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf54AYYiKZrFWZ/Cj5mZbfK11MZHYbwchllsUl4qPqY9gfi6AQAgBAB4irxT\n"
+ "86FYA0NbZssSTmfyG6Edcf0ge61OwB4QD35kHCrvuZk2HnmL+63Tj4QoFqIVnwVC\n"
+ "3wRGJGcmS7y+vS64GUXbuyTgqgpl/KuoHo5Aqe6IxJlVWYtU6W0M6FV9tAM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMUEvXTVTl5xkQ2MTEsB4sXQ3MQkz8sQrU63rlqglpi1yUv24fotjzvE\n"
+ "oJpeKJBwwg5WBW/fW0bUDJF2cOHRHkj/R4Is3m+2PR1Kn3UbYfxNkFkTE11l099V\n"
+ "H6xlsi0TJOJKlgrcbSuB7se2QctZVhwsdsJvFRptC9Qd+klAPb7tAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMooTeSUX7GPoyklSd1/6cF1u8e2LbjOLIpZrMon0Xt7c/aNwlrG9rVo\n"
+ "TSokHs3AQ2H2XIceySVRRWR4AdX9KApO4CX0gGTuVUmq6hFJWMnHdAs2mKL0kt1w\n"
+ "I+YWzjUqn4jIVa2nMbyHVQWzIysWwWiO4yduIjAYpBbWd9Biew4BAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key BN0I+pLmFkDQD5iRsdkcped4eZwGIuXnLiX2K0Zoi2I=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AXiKvFPzoVgDQ1tmyxJOZ/IboR1x/SB7rU7AHhAPfmQcAOrIvaG/xJqe\n"
+ "adM6mai+FlV8Dbt6QrXTcNHJU1m+CUDthA9TPTAYz9D8W0mTEQ6KEAKGfQrNLy2r\n"
+ "G1B+9wWSpA4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 abcdvEzGFYMcJ/Ea7sbessW1qRJmnNNo2Khkkl0rEEgtLX0b4L4MMhK/ktS52Y6jX3PRQWK5PZc6gjV7Jaldh+g0Aw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Vyj7g3eQ3K4+tm49fJkAtsAYnYHcEiMnlucYCEPeKojzYStNfZwQO2SG5gsoBIif\n"
+ "urgQZ/heaF4uiGFg64UFw08doXqQkd5SHO3B4astslITvmq0jyaqzSXhdB5uUzvp\n"
+ "QCR0fqGLVS1acUiqGbRr4PiZ9G7OJkm230N3rGdet+0=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_SIG4[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AaEnncX/t0cbLm1xrtlUpkXghaA8fVuV7g1VF3YNfCaIAQAgBAC7Ki3S\n"
+ "zzH9Aezz5X4fbwHeF+BQEDfVasfyTxTI4fhRi7t3RxHzBJd60uEMXy2FchD8VO5d\n"
+ "j4Dl7R4btrohPVSVBQZuemBQSW6g3ufNl0txpFWu0R7vBPTFH6oyXYfY9gQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALGKwzhOui2/jJPjU1ngW5IZRPcoDk7RAfGDO4xaef4VfAFHCV9CQO1c\n"
+ "/wQ09CcRdggTvUcv9hJTGJhSObUUooCkxw4/35f/A6/NoW1Gi0JqF9EsQWHpuAfr\n"
+ "n/ATlJQ9oGdTCNDq/BXSPWXhoI6UhUe0wiD4P4x4QwaYHcZh+lE5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOKrizVm2h5/jE/HqqLCBLWJZVVoGspasCtDDqHhSqsPzyjpqa52iMKi\n"
+ "q/deJ92le3J2NJRGKxPmPQqWxwhIjnMS5kUMoW182iLpO/G9qyPZ0dh6jXB0NBLF\n"
+ "ySfW6V2s3h4G4D2P+fqnsnzQnAX7YufkvgDau/qTWi2CqD0CjavDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key A9h8jY9dPbhHTDbIc/NYWXmRP65wwSMrkY1MN8dV3BM=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AbsqLdLPMf0B7PPlfh9vAd4X4FAQN9Vqx/JPFMjh+FGLAN8xr/w3KFVi\n"
+ "yXoP/az6hIbJh0HYCwH8D1rPoQLcdpe8XVwFSrHGarZesdslIwc9dZa/D1dx3OGO\n"
+ "UhJOrdv51QY=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "bLmdO7ME5vq+c9y/Hd8EyBviMBTeo85sHZF/z6Pehc3Wg3i1BJ8DHSd1cK24Pg48\n"
+ "4WUrGTfonewuzJBDd3MLkKe6epXmvUgvuQN5wQszq1+u9ap/mRf6b3nEG0MHxMlO\n"
+ "FLx5MBsScuo+Q+pwXZa8vPuKTtEjqbVZivdKExJuIX0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ " router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "LqNGEa10zwSPeomBXTfgvBnnWAdWyiR7KYZq9T++jK4ctR6hUaWngH8qSteUrkMx\n"
+ "gyWb6UMmlxdfOG0sdcU463HsqV7zObaKya8/WwQ9elj3FfsToswUCeOaLR/Rg7wC\n"
+ "zcUjI5VsneQoXT2WVZbZBLsLB3+7QfezVHRMB377GAY=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_ED_BAD_CROSSCERT1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AV1AfOvQWKlWsbzoBdJc5m72ShIJuA8eNV15basjhXYdAQAgBABy+KQK\n"
+ "3oLDGtqL5kwRmjAsls/+C6SAoAALll7U7wNSH7en5RVBal4RUzCf57ea/KG0c9V8\n"
+ "2DmZ3PdOt2aY/M2bWGmmH/tyyapOoV98dhDwFU7zcx/pMfRnJTDRSDwl8QE=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMP6xbqbj+x1mq5XImjeT0rUzqKZTgBd5zvK4Xcy9IifJuFC9+mMzrY4\n"
+ "WhYbdClxKUkDMkit9MVhek+P/w5TSHKl6AuqGaO09ID+hZpoUSdoBUYktynxfGsx\n"
+ "kIDu0XvgtAeSyJaVvoV1SKVChY0IBbzUqbHt4O2Q1BhzFCKEJTEzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANwWlBh7e/eSLlhto5YUdj1iGYOq+yAmlosDItVfYrSPJuUfM2ocMBAn\n"
+ "udbRbWiADoqsbKn/gwwHCC/f1HX2FkRXxxnOlJKLo+NEi8tGmOlcQXSQol1pCpvK\n"
+ "sA9TxtYr+Ft4LRpxNrexF+pIBxqzwetqQrZbKYr0CFJi8q1qlMynAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key cs1AP+xF5cXTLuKeOeItdoDAzfALTJkwk9lB4mtC4QI=\n"
+ "ntor-onion-key-crosscert 3\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AXL4pAregsMa2ovmTBGaMCyWz/4LpICgAAuWXtTvA1IfAKo6ANUq+hi+\n"
+ "xb3J4aYafnszlj87oi/DR+SDf29wzwNw8gmaqGzJ5GbfISfABuTUCzlilZyVnLxi\n"
+ "BHcCH6PWiAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "qC9Kph/kGtONR2DxZDoIFFgnDFC+/7H07EgCiYQdIFIROc+gGK9qBOgeFEptrkXF\n"
+ "XdE35xxox5xSASQvp7hjFwxUtJRGOtf2O98regqeeaz6O9VPXHkLf51uqX3bVgq8\n"
+ "KvFAsFFS66GxhtbrVjpyRgIwHAYvse1WVESfLuZZTn0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 3uW8Q1aetIQLOsqSco128ZUaHlhqdYiBvrxV7x75BGNS5RzIMTEwYDNtEX1LNPFJ5N0YOV0HEEOLhrJUV9QCBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "WuD7S/saTYBxKvItITbHRi8n+e6g/oVbosicfbRbafYPzPp4Prb+RK03UTafzXrV\n"
+ "QEQIzDNhfePcIMH8qX+qrogLMXFqiXx6TVQ0GqNvqirokk8ar3AgtRtewhChAuAj\n"
+ "8pmQTj2JpZn/iB3PCE2l/93O9LHZfp44hc8QOWKs6BE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT4[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
+ "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
+ "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALeS5YbeDuKQ5iiuUvh3REoyJ47/YU9lslWmTrVBf9b66pMnYJv/awPu\n"
+ "m2HredUAJ3VzwQ38VJA39w3fQXUhQDnQ0OPpKzeAmIiuG+6WdW/mBSK7uKcezC23\n"
+ "LA1d6Afyl79LjZz/n+ENXqNMlJk4QPcPHuRnAvwBl3t8YVRPJmxhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPprokY7utWuO/0252dBB5MCxmVD/dROaIBDyFtpdH+YVv04rkOlDzYD\n"
+ "W4mgHVBMxEm/cspTgQmJ4exRHJPpcSe1RYHt1ONZdLYr6D7OOWf0y1IUrVSzF6K4\n"
+ "lqlmNuH1H4+TKGbkvixYc5GU/2ZmAy6gFEuphYnBbsN2Ywc38mnfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key Cgo6xniGfEiuYoLSPUdE4Vb2D4zj2NQzC1lRjysRRXs=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "bi4M/AJLZF7/vSNmOj4uhrgKBQA/KfcZy5e58mhGL4owxd9vaWfl3aelvb9jf9zN\n"
+ "Q7FMv8f9aXzeVIoXIpRJxSKIJgBtG2wnMumIc80pqBvTyGInharszb6njfm0bg1u\n"
+ "PfJkbQYyf/dA5l5UwCrjFs06ImDmjFTAdsSWf6DfZ/k=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "io16v+e0pK3sbFzPGnkQrAjrRgIOJHrVZ1RXcxZ1+UNXagWM/MOLhQpkU/cw49Wd\n"
+ "4rQeZD3JQh16330eXbxc97AyDgp0b30He846SI0MfW/DnmGI8ZNeYfLbMv2bmbs9\n"
+ "QULzyIH8C+5mnMI1arcuiAua+Dpa34F79vgqPuvw5fU=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AVB+j+B2yPgGywvp7nvejyhMh9ejKmw7LCwufV83Zl9eAQAgBAConA3B\n"
+ "jJ3X2tES40jd94rRUFS2/s/Yv7E4LEQ9z0+jz8horNivzK3O/t7IGxJggi+b41/9\n"
+ "Uaqt+wqtVuKj0xJ9jwBlCXFt28G2P9s4ZyXYgGZqo7MlJlboybnOMvmoTQA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPWuEWckT4aYAVNrZzLA8xVwfXp0wzfXeTWBztLS8VzssN6w/+cwXdeY\n"
+ "N1YNc2DiD3u8f+7kmuZIqL1EFQUwTvRwEzQXm2dqGM7qkm5ZGNMb5FKu+QwO2ImI\n"
+ "FLNiO5zO/LqP3cf/2L8/DuvruLenUrhRtecGFaHmhDYl+2brHIiPAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMtHTfk0gDvp9+PtIG8Ks7rgCiJZ2aihSvr6WaKHYuIprgspFuga98cg\n"
+ "D//J80CrgH5Dw68YnkG+gU40IxP7YzhQ4glFlJGu3s2y7Qazcv5ww1XtHur+GDoA\n"
+ "cY0zCLhltNQFxIsoVUepY97XA6Y2ejYJjyqNXQcAmoPNoVhnTdkhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key ibZf57LptdOK3WpVFXkYMatEEqPhuVWxsnkwF6638V4=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AaicDcGMndfa0RLjSN33itFQVLb+z9i/sTgsRD3PT6PPAEbkxCdI/bH/\n"
+ "B06DAjRuoDiv1HKsGuW+UN1iGEiWu2ieFzf3m0Z7BL9p2u2zIbHYkP50b3T3sebD\n"
+ "1AksemmMdA0=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 XS4zVi46Xl3xKhuozPCDlW0QRFD4qUhJmkefonQNsRlMVsrPkALnP2tfnfdfTc69hbNa22pOjJNf6Gm505EnAw\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Q+R3OpO8VhfvFbXuE5qolhVbgosBHy2A5QS91TMzCbsxa8pBA6Li4QdPR37wvdLq\n"
+ "KayfmmNCMKU5qiZMyXqJZm4fdpxiSi50Z0tYlXM3b2OVfza3+pSOEBl89fN6G4Qc\n"
+ "pAmM14eEo1UzXrqZw76tMS2CwOYF5vR2xFGCYC0b5hM=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT5[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AaCfOaispi7dJhK0c8HXJHIwoBkMgRpmmHu+3Zce/soMAQAgBAB5bAIo\n"
+ "5i4TSY/bV2KQAyziRwvgJm+nEiECClflPbP9Um+zOzOgxtDmNnR5UFQj+VWNG4uf\n"
+ "5lnaryN+PfUXZMTcs8AARof3fFz9tVPINHDrsGvKt8gpzgZEHkVioAXOFwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL3Fr/ovZ9SMGYrAM24taKBm/NpemZaXdD/JeBXFYm5Zs3szLwJC4Etm\n"
+ "zjNL6tVy+I21O1g3cs16TkflcidsjPXNx//PHAn7bqWMekjrt3SQdkHW2gDPgT2c\n"
+ "zYJ/hBR96JYG796jP3pkfJz6Iz5uT/ci3A/cdaVbzM1uZbMUgYGzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMHB+1dWa8BBrKE94vTqfbkSEuysG5LyyZF/WrqHq/3W+ocDLz795k8O\n"
+ "2Zvgr9im/Ib4hD7IyrtRexcuBdwujdG7cBALdCcWiUTGAMkl96HNETSX+lUVIpJ9\n"
+ "pMsc9O7+yz+/0Cl2RpILZCdE/7I96qHpZl3tzlRKSu15WeIm5U77AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key GXi0a2VLcRHQMMYys85zu3IPqOn5ZTsOixYyQvTGnQs=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN BUTTERED CRUMPET-----\n"
+ "AQoABf54AU3MlHAEtdPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END BUTTERED CRUMPET-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "T9NHMBhuJo+TlfU3TztNgCc9fK1naNRwPOyoqr5R6lJvJ40jkHnIVOFuvuzvZ35O\n"
+ "QgPbyFcMjv6leV5xcW+/I9tWaBUFXiRGI27qjCFth4Gxq2B6B2dIcQliLXSvW9b+\n"
+ "CMTgDwVa4h2R2PMh18TRx1596ywE09YhCgBF3CwYsiM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 sRpiP9kyW/DGOphp4V2VCtcKNA8i7zGuv2tnljNIPTB7r7KsTvdUk/Ha9ArRQEivO4nC2HHENtknDl3GtWIPCA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DtORw3+gO/yUUIp70xDaWSOgQZrJAAoZTNCB7q5WCoZOngeaCiC1Gtc+Fmdn7tER\n"
+ "uPqQC5H/Kh3Mi82PCj0JxvNivnNTNY1AZVaIX5YoioXVOkWF0B2pqMvFuDSdm2oJ\n"
+ "29PqSVcklquu19EjJRTopIHvYn3sFhQL4LarMsYY11c=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ "\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT6[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55ARMMCtQ8pObC5bq02AUE9Lx2bqsZBBkeOsDZVaEq6JavAQAgBABtV0xF\n"
+ "CsWXL/uFIBnoEsnXBeU1MvYRFrj1vR7QHdWXnxywXvBYUAC8lu/uyc8qqLp+aQSJ\n"
+ "5JzpDYlg3hp1fl5k97iv5F9WrR6s554YpmgYy9agFaxZ4LmRgz7n0UJ8mwM=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAO5qd1TndKD2pEs1ZLWsHlvfO/E7cA0H7NKGLSioGpBf4P0rtkueX4ci\n"
+ "kJNa/4Fn/QsLECqEF2lUjkIc8YL+HMS6qteKvN8+nn16DfvnIhPDNZWTJjLl1bOI\n"
+ "sWSSiduhanoWQnhRtl3Rxg3opdNd9ApO0DLUNy4Qy18Ai6SgksfHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAJkMYNpK7eJJyGwD/xG/iNg6gzzbIwrOSvmtoP7Rot42qtBiQ9A9kdsy\n"
+ "sazwkWkM93U1+1OaAADPYxeHoyHnuia95Cnc5y2lFSH3I7gnGGSPKSTwXtdyvDWZ\n"
+ "P1LbmQ4Bnh5leTCNZ/eFC4/GjNVzqHxjbb8a11dQhA8dOk8PrUq9AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key HdSQOqvLr4YnJE1XzzVIddgKgnjaHKJqnq0GqF4wXDg=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AW1XTEUKxZcv+4UgGegSydcF5TUy9hEWuPW9HtAd1ZefACVwif1deQry\n"
+ "K5GeemRa32sGzujVDDe75WRiPKFT3l/EtjTq3oeVq2xwbVJklnG3ASejKTr3YcHt\n"
+ "ov0jOl0jywc=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN NAUGHTY MARMOSET-----\n"
+ "BpLBsl6Yo64QzczJn0TjdcXC1Jv9IhUG2m/Re3v0voCELOP+t5vkZXXLoVL23oKv\n"
+ "JheSkWiuAIEPsatb4afXZ8wZxPcQjwy3zTOBM7p9CG5fA+KYpqKTxAi+dhVYlcDo\n"
+ "M7S5nMV63FclkZIT70FFTHwWed1sAKwEO3/Ny24eppc=\n"
+ "-----END NAUGHTY MARMOSET-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 lNY8TRX/FZdH5eFbsBkFHuRi8bPDsE5P+v7zExyD/IXnKS/ffYlP8qw1XIPdEDOIzGQ14+kyPX0SotaAqHRtBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "BHamS+epF77iozo5cBt+tbs22m9GhwY55DRXpEWAtvn67jsMnmn7qCOLONigK1RT\n"
+ "adZNezIydcCxXltgHTdKaZw4lcqv3s0KL8kI8frbBmm7PjXtWnrdXBYY+YK54MN/\n"
+ "t4N3162o9hzzKSwye0gPjgzpQ1xtEIkzWhBcmE9Vw5s=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CROSSCERT7[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AfVmH2ReTyatl4VnS5YREtCM2dwikWuAPffq6M5bysZxAQAgBAAXoqE7\n"
+ "taqwLDXLZrZukpF1eBkCwYQK9uzctHTuMdqOHChguvkfX7V4H3O76Ayqvz+Z1ut1\n"
+ "KYRdgiArn3viRaBv3ZKT4Z75suMI3bjqGOSGLAKfOa0uLkOmKblHHhSUkwQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOLNugzUezzzw+N1SuQWzILJYkUJyQDoVXSZjT0dzBplHCjlrv0WZCUP\n"
+ "/pbonE7SlCChIovHcdiASaLj7MVaGgYDq3M1Vtgt5vhgGl10/+evBAD1QEt8AVfr\n"
+ "5+PH/sbZvOWucAhNUhOlqFKAn4vdRY39VEEXC5/Jz5fsk1E/DBu5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKxzg1hsYMS+0zAIrgYxSGO0GbKRrL/VhdlMEGu7ACaoqlGnmGQS3B4B\n"
+ "gLk8xDdx9N//8+YTx0hUIxP38w08lubPl1WXMq8s7wAiFd06Nklf65mHs0sXVtS1\n"
+ "EG3f97PQqmBpEJOwYBATNcA9e6F62P8SXNkpSjOzNaE0h9wHNKk7AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key msdr3O4W4bm/xdmZLzj35363ZSFex8yQxLWsV3wRCAQ=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "VQoABx54AU3MlHAEtgPdAyWJzRBnh4brXbCR9JFLjLM40hsBMoscAJ8cHMIc71+p\n"
+ "Qa+lg5JiYb551mLgtPWLy12xdhog7SXiJl3NvnMgbMZXHDqkU2YZCidnVz+xqMdh\n"
+ "mjQFK4AtRwg=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "RJJRiU0vjVtRi3bVZru3aTvV5l56X/WOOp/ii316yPAS3aAMpOm1+piFVR5MNqcB\n"
+ "ZGyrA2Kx0hawdL2buU47iZ12GOCi4f1Es4V4N0TQgJICsKX38DsRdct9c1qMcqpp\n"
+ "1aENSRuaw0szTIr9OgR7/8stqR5c3iF1H5fOhmTi6xM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 4DSdPePrToNx3WQ+4GfFelB8IyHu5Z9vTbbLZ02vfYEsCF9QeaeHbYagY/yjdt+9e71jmfM+W5MfRQd8FJ1+Dgxx\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "F3ZqvsyL6RRhPEnNFFIZY4WJM7LK082rseWzRkGNXjwoEwOWUK8enQ4Wjit+wozW\n"
+ "4HVIY1F+vP7gm6IiOEAFgEpB4C8FGuyoFw2q0ONA2tqTcvBJDDnqbx08FO7v2Dij\n"
+ "d3ucfc5gf7YNaoFCMMuyAzC56eyNk4U+6cSKy6wnJds=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_ED_MISPLACED1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKT6OIN6TsDB+xcp1uLeE0K3aiHGqa7hdxMBGpvcD0UFSyzpVv1A/fJa\n"
+ "tClDCwTpfTGbyK2L7AO75Ci0c7jf6Pq+V7L6R7o12g6WBTMrgsceC4YqXSKpXNhi\n"
+ "oudJyPfVzBfKcJUSynv89FUQOyul/WRRqWTfv0xUsJ3yjuOESfCNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AbBV9NVz0Hdl0Uiv87LiXaTAoeSXE+bheNG4Dju1GzQHAQAgBAD16h+T\n"
+ "ygzSgPN4Qat5ITthvm+lvMwMVGbVNWMxNy9i33NGhgp8kqMp2iPAY+LhX8It2b+X\n"
+ "8H9cBmYLO5G7AlMPj7GsuWdCdP/M/ldMvFfznlqeE3pCpRas6W48CFJ+9Ao=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANMO/MepK3uCkKTLRCwIWc/8URVza2gEmDx6mDTJIB/Mw8U8VRDuu4iJ\n"
+ "v+LL3D8/HGLvT9a8OXbl5525Zszt8XueF3uePBF0Qp0fjGBL8GFqmrmFe6plurPJ\n"
+ "TfrS/m3q+KhXAUowmghciVGDY0kMiDG9X/t/zKLMKWVDYRZk+fupAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key I8yDO62Flx5O/QsFvgb2ArIRqwJLWetHMeZdxngRl2A=\n"
+ "ntor-onion-key-crosscert 1\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AfXqH5PKDNKA83hBq3khO2G+b6W8zAxUZtU1YzE3L2LfAGC1uXxN2KwW\n"
+ "w4PqRidM1UPZ5jVOHceZYNQcTzzzArfBpr9OraOO2up4TGte8GVqjJNxrZc1gfjn\n"
+ "CwPW5WxpFg0=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "jLg3D3VO4i0sN8p2qtB6+5C3tai/K4M89mP7z2abQnUTbynOacPoNXIk4o64DjBJ\n"
+ "kaR42yfA7yQZ8Rj8abwgz0Zz6zbd+JjE+s/EklrEEtOl+jZAl3i+92FaHROJojXq\n"
+ "hw+ZEPOb9zgb1UQ7S1Fo+GoqA5bdGm/Wg1kSQielkNE=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 TRKvIl/wIIRD4Xcmd6HYmy7tD0KhVGgoStpWPtX0zmXGZ7+jugItrY0frDu9n82syiruuA45ZOs1Rfi4CbOSCg\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "NYpRfurB1YhFmDAdRc2Sd77S7By2V/0kgEHpJhtySb7efiQsyOA4ZBr1zEFPAXdp\n"
+ "TviKzyS9kN2fnz3hORoqFul33BDZbiLMNLtt5tzp62TYtmIg9IZdjjczbJUgbVLt\n"
+ "KCJL0vM7fdbXkZX61GIBbMYwzwIiHvVxG7F/AS5RbtE=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_MISPLACED2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55AfJo9FIePrxeDNnWT6SWkoz0/L27018XjUNWEHfaR06MAQAgBAAMgolK\n"
+ "nLg3ZnVv0skzHCfmX+ZR9Ttwj7FNXfhXCsyr860S79OW5LD0/m1GcS9JflWhP+FO\n"
+ "ng5cRb+aqNc8Ul+/4sQudZRx8w4U3d5rOuMGCqhQXnktH9AFzQHFq0jpAAU=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPeK/znKLRvSUmCIUiZOgfhiRFt7XGN//C2GFuey4xkKiIr9LWMuVe9m\n"
+ "Wx39Ea2UGEtNGCEVvZdJMDVRl7heFTfJTN4L1YeyWx6iNRWlpAmgQOKII7slHwlq\n"
+ "seEULOLOXc9AsU/v9ba9G54DFbHfe2k44ZOwEmaQZW5VF/I0YMMdAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKFRzlrqPPxEW0nboAJ1qzKFb/vFtvRW0xNVb8RtbOY/NY5FV1hS8yfH\n"
+ "igtugkrOBmWah7cmJhiON2j+TKeBxEoXwJMZeyV+HLbr7nY/mFhad4BQ3Frkl8d6\n"
+ "1kQMhOJswMdwnnVHPNGUob4YAX0SpFA6MpBVj92zmMBeaihqUS9VAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key br8svioLcJCAQxoo3KvlT288p8rb4lQIZNLlplkIKkw=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AQyCiUqcuDdmdW/SyTMcJ+Zf5lH1O3CPsU1d+FcKzKvzAG9XqwmRm0uJ\n"
+ "E49NoHcWr9IzdIwSGo+PJSkVpk95a5p2s065BetCWxEEBJQniajQf2hZ36zmV9rq\n"
+ "a6puqkEAKAM=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "d6QGIVAJL5JjHUyV+aicLIdBYyxHwviKpPcp7uldRF8vfDGFpu0qFgJ5KT+3t36w\n"
+ "QY1r75bvUMG/ZzGKDg95dcK0X2AK6GFlcrYyCoQEVOsuPc1QEUeK9P2s7viNQE4V\n"
+ "tRwG/CvJhPfcnxErzVGfXIeYRL1r/hPNFDZSeSxPPM0=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "router-sig-ed25519 ts9pFk8PnDWtXgQad09XC/ZCbruSx1U1pNOMWF9fyoNG0CodxdDH9Vglg+BOS7Nd9fmsINfPWKCVdVuSSM7zCA\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "YMl6mpQm7UCsPQhZKMm0aZ7fzGevWzRbQO+de20HTn7fVqMWQf2hBDJe9QTN/uDK\n"
+ "/VKYT8SnIBexbrSMy1N5q8kNFKxxUtwA9GRtz620Vvc4m+lz/tnT9qucIKCDL5iJ\n"
+ "eRpnls0JoAMIHKl99zdUioYubmOZuqUaRAdT8ulWy+Y=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
+ "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
+ "dZToQTFSzAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM4o2DrTwn3wrvUMm41S/hFL5ZtRHGRDh26o8htn14AKMC65vpygKFY7\n"
+ "fUQVClAiJthAs5fD/8sE5XDtQrLnFv5OegQx8kSPuwyS/+5pI1bdxRJvKMOUl2Tc\n"
+ "fAUhzeNBmPvW3lMi9Fksw5sCSAKQ5VH/+DlYvBGZIO49pTnOAty1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMzIsJeEWWjN3Lp6qrzaJGn8uhJPJyjy2Wt3sp7z7iD/yBWW6Q7Jku3e\n"
+ "C5QfKmSmNi2pNjS0SqPjqZZNsbcxpq/bEOcZdysZG1lqi/QgxUevk57RWjh3EFsG\n"
+ "TwK3ougKWB5Q6/3m32dNsnnnDqzVapgZo7Zd3V/aCo0BVtL5VXZbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key W28nwT/5FJ818M78y/5sNOkxhQ7ENBhjVhGG2j6KvFY=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYf+rX8a5rzdTBGPvLdQIP8XcElDDQnJIruGqfDTj+tjAP+3XOL2UTmn\n"
+ "Hu39PbLZV+m9DIj/DvG38M0hP4MmHUjP/iZG5PaCX6/aMe+nQSNuTl0IDGpIo1l8\n"
+ "dZToQTFSzAQ=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "FWnEjvFob0ObgqohMT7miwGsAuioCT7Urz6tyWaGWph/TP9hbFWj4MPK5mt998mn\n"
+ "xA8zHSF5n/edu7wVX+rtnPrYPBmg+qN8+Pq6XMg64CwtWu+sqigsi6vtz/TfAIDL\n"
+ "mypENmSY32sWPvy/CA8dAZ2ASh57EH9a+WcFModpXkM=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 88YqJdGJS4O6XiUCNrc9xbOHxujvcN/TkCoRuQQeKfZGHM+4IhI6AcXFlPIfDYq0SAavMhVmzsDDw0ROl7vyCQ\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "cU4WDO3w9ZfVRbNUgxOQMbwS2xWXvaL+cZmIV6AAjAZVWkLEpif4g6uYu+jJUZOS\n"
+ "NUT7lNOMwTu4tE4b1YJpnD9T8iW0DlOXxlvRBMQYmKwhQuYk898BDGTSk+0AY0HJ\n"
+ "vv8wRVewDajNhW7tFY907IdHvPXG0u83GANxkYrRyUg=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN WOBBLY RUTABAGA-----\n"
+ "helo\n"
+ "-----END WOBBLY RUTABAGA-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANZvqyqFeiekh8ApqIGK4ZtOqjaX87EzDestvAWwamVOXiPoUrzXgM3O\n"
+ "l8uuTnMA4TfnjLyyA2TnaMzJylOI1OMHuW/D9B/liWDstSxWNNIlKgLQ/Dh9xBS7\n"
+ "uQb2PYlI+iMkPKPyJQSTDdGHE7cdFPewUfhRtJU3F5ztm/3FLBFvAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANZl8U/Z8KCPS7EBDzt8i9kNETXS7vnp9gnw3BQNXfjiDtDg9eO7ChxY\n"
+ "NBwuOTXmRxfX3W9kvZ0op9Hno6hixIhHzDql+vZ+hN7yPanVVDglSUXcr31yBm5K\n"
+ "kA+ZnRvH3oVQ97E4rRzpi09dtI13Pzu7JS5jRMtH+JF1kQBoNC0dAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key lUrEL+TVXpjjHQ2BIKk34vblyDmoyMro1a6/9hJ4VRc=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55Abm5E7FBdd3F8N1xuz/vdv03zh2lABrmGjzPQ3AFJtntALNeQTgjv0JL\n"
+ "jON4+SPNi0B2Bva3yKaSsdxiHQ1rIwQqIUVkzXmmX4jmsvJK/9gERAdD7GafTKZQ\n"
+ "BaZbNXBvmQw=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "OxkqFsw1vHUQ9iPYcKC/MHUBtbLPK6JY2i81ccAai2eW118UXcTbeCRccrXyqSkl\n"
+ "RLcooZyli1D6wg9x7O8+2+HXIbUa6WcTOD1Qi7Z9wKZfk4sDUy7QHKENMRfAXwX3\n"
+ "U/gqd4BflMPp4+XrYfPzz+6yQPWp0t9wXbFv5hZ9F3k=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 fW6Bt4R3xVk5KMDyOcYg8n5ANP0OrQq2PQFK2cW0lTAdi+eX+oT/BeWnkrn0uSWOC/t4omCmH4Rdl8M9xtpfBA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "DHxiQXuLxZR0ylqwUGGePgN4KF4ItlOV/DuGmmszCO/Ut0p+5s4FP2v6Mm9M92Wj\n"
+ "75rS9xF/Ts0Kf49dvgc+c5VTvhX5I5SwGQkRk0RNJtNoP0t+qXBHaFV8BlAeaWF6\n"
+ "Lg3O+GUK325fQv9uDPCe37mFQV9jafAzsZUrO/ggb1U=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_ED_BAD_CERT3[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "BVVVnf55AW5TTGF9jCMl7aALZzqypD9Bj8WYnAPIrKCoIJdgMbY0AQAgBAB7eCn8\n"
+ "rukx7t/egZUdqU7+FYqsnO4wdmOkLZkp0+gpF3jjk6N1Q0037NNVNZBjONB0Nm2F\n"
+ "CpB3nWSJliSSKr5tOYsuBPFy5VVGYeKPakpOoxanQ1UcqevMBAQy0zf9hwA=\n"
+ "-----END ED25519 CERT-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPgeQNbKwpnTU+qW/2djh66hptS9rcy1B4vdyWkDTdREao2ECuCv691Y\n"
+ "oIw3MpTWvpC1qHIKorunusR0FKgwXw3xQTikXbDq/1ptsekzoIA1R/hltQV3UuGH\n"
+ "zdzHuQXAMX7Fdll2gyya03c3Yq5s+xSDvGdkEeaIoctKjwxp4SdNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOzWuH4cPW9rIrfi8MrruMUg4IUVHz4BxfY4/szMIUvzeEAdHn4FYkWy\n"
+ "Vt7MDtUELZsmZeFNmkn72kLxnrdZ5XhxZBriq1Fzq11cSWRBF+SyE1MdcouY4GyG\n"
+ "drw6T8xb8ty19q0eO6C/gw27iqXPAp1clvkroLg6Nv9lGZvsedVDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key /vYZ+9yLqG7yUnutoI57s96JBl36GTz0IDWE244rbzE=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AZ4zVBWP/fIYEgWmyj0WpO6CkXRJjtrWXtiT02k3IddiAMpYgMemGIpN\n"
+ "xj7TQRULsHHYvo4fLcKrSgndQbUUhfLTUuVhIzbnE2TBLMVOEkpxKU6mTuvTT/3h\n"
+ "MJugrwTWVg4=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "c/Vqu3wtsTsYMdnhTS9Tn1Pq6jDmH4uRD5WmbaCKKrkin2DjuYSMVpypndkdlZDE\n"
+ "He7uF7SUO3QG/UcRIXYOsg9MSLUmvn2kIwef8ykyqlRh95Csjo5DyattUhL2w4QF\n"
+ "tJkJBQAnXWaAVW1O8XimGCAvJ84cxbmZEcpN6WKjrXI=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 Ue7bkPpOoc8ca7cyQj/Vq3BP5X4vwLA5QmpLGw/WfRNVRPojJRxU3RVqWMi3JbsJFRTe6pH6ZHyXER33G5aAAA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "ifKUtbxmqHVs8A0oT5n7Te0c6D/XqWQTc0RxX9OKGspzh6wNX26h0Xa2vpK1Q9Zu\n"
+ "sj61I7vbHuZN6rxiWs9IzJgb//XaNJasX1pd9tbGSXW+yYzc9G9kaa7vp3HcnhIP\n"
+ "XVWzzS8WmOiVNGcF65j6f7yGloTgN7cHMptgJG7pWes=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
+static const char EX_RI_BAD_EI_DIGEST2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQQABf55ATrK8IVBWLO2yXKCqXLXJOTu89W2b+hREPO+tCrxjVqWAQAgBACG/vVx\n"
+ "NK8wKVZvf34d75ZObSR0ge1N2RrAIKNslNXBq/tcllIrNE4S0ZNcMpA+hxXoVFeo\n"
+ "jbxifYX7nTs5N3GrGPmkiuo82v2X6ZwoIXJGFnvWMxCjsYsUVDDxoT6h/w8=\n"
+ "-----END ED25519 CERT-----\n"
+ "extra-info-digest E5FAC29E766D63F96AD175069640E803F2723765 99oo\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK9wHSdRalxkuAybrSCA3dlEC1ZGc7oHOzXRGLg+z6batuiCdQtus1Rk\n"
+ "LP821eZJtEMAE56aewCIHDcTiCxVa6DMqmxRjm5pfW4G5H5QCPYT6Fu0RoYck3Ef\n"
+ "vkgits5/fNYGPPVC7k8AdGax5dKj5oFVGq+JWolYFRv6tyR9AThvAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKxjxTQ/T/MHpFbk7/zwA7l5b3IW3yVcyVe6eIGFoYun8FI0fbYRmR4M\n"
+ "G5Asu07gP9Bbgt3AFPuEqrjg4u+lIkgqTcCgKWJbAgm7fslwaDTXQ36A7I1M95PD\n"
+ "GJ10Dk5v4dVbrqwoF7MSrQPFtMO91RP11nGPSvDqXZJ4XpwqwdxpAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key LuVmHxpj4F5mPXGNi4MtxbIbLMav6frJRBsRgAvpdzo=\n"
+ "ntor-onion-key-crosscert 0\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQoABf55AYb+9XE0rzApVm9/fh3vlk5tJHSB7U3ZGsAgo2yU1cGrAKBcSzwi4lY/\n"
+ "salCELOLdeZzOjDNnBd6cKp2WJg7Yz5zFlbVbyNk0iwfGmucHk8vQZe5BS0Oq/Pz\n"
+ "B1u/BcJv8gk=\n"
+ "-----END ED25519 CERT-----\n"
+ "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n"
+ "QsAQVdDVHtasDbhrZG4ZxImdTTMY7fz3vouAiGyZx6/jCCB5v0gHwTn4xo6pgLEW\n"
+ "LQfMhQZIr76Ky67c0hAN2hihuDlfvhfVe9c2c5UOH1BOhq3llE3Hc3xGyEy3rw7r\n"
+ "5y38YGi759CvsP2/L8JfXMuBg89OcgJYFa27Q6e6MdQ=\n"
+ "-----END CROSSCERT-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-sig-ed25519 5zoQ0dufeeOJ/tE/BgcWgM8JpfW1ELSXLz4dI+K8YRH/gUtaPmYJgU2QfeUHD0oy1iwv4Qvl8Ferga7aBk1+DA\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "D6KRMwkb6JmVEnpZ825SD3LMB84UmVy0i94xk44OwhoWNKLXhaSTWJgf6AqnPG5o\n"
+ "QrCypSb44bYLn+VaDN5LVUl36jeZqCT4xd+4ZwIRdPOUj7vcVmyUDg3lXcAIk97Q\n"
+ "E5PrQY1mQuLSIjjKInAR2NRBumNJtRw31Y/DTB7tODU=\n"
+ "-----END SIGNATURE-----\n"
+ "\n"
+ ;
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 20863bf..5f68c34 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -437,8 +437,28 @@ test_dir_routerinfo_parsing(void *arg)
CHECK_FAIL(EX_RI_BAD_FAMILY, 0);
CHECK_FAIL(EX_RI_ZERO_ORPORT, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT2, 0);
+ CHECK_FAIL(EX_RI_ED_MISSING_CROSSCERT_SIGN, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG3, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_SIG4, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT3, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT4, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT5, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT6, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CROSSCERT7, 0);
+ CHECK_FAIL(EX_RI_ED_MISPLACED1, 0);
+ CHECK_FAIL(EX_RI_ED_MISPLACED2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT1, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT2, 0);
+ CHECK_FAIL(EX_RI_ED_BAD_CERT3, 0);
+
/* This is allowed; we just ignore it. */
CHECK_OK(EX_RI_BAD_EI_DIGEST);
+ CHECK_OK(EX_RI_BAD_EI_DIGEST2);
#undef CHECK_FAIL
#undef CHECK_OK
@@ -494,20 +514,34 @@ test_dir_extrainfo_parsing(void *arg)
tt_assert(ei->pending_sig);
CHECK_OK(EX_EI_MAXIMAL);
tt_assert(ei->pending_sig);
+ CHECK_OK(EX_EI_GOOD_ED_EI);
+ tt_assert(ei->pending_sig);
map = (struct digest_ri_map_t *)digestmap_new();
ADD(EX_EI_MINIMAL);
ADD(EX_EI_MAXIMAL);
+ ADD(EX_EI_GOOD_ED_EI);
ADD(EX_EI_BAD_FP);
ADD(EX_EI_BAD_NICKNAME);
ADD(EX_EI_BAD_TOKENS);
ADD(EX_EI_BAD_START);
ADD(EX_EI_BAD_PUBLISHED);
+ ADD(EX_EI_ED_MISSING_SIG);
+ ADD(EX_EI_ED_MISSING_CERT);
+ ADD(EX_EI_ED_BAD_CERT1);
+ ADD(EX_EI_ED_BAD_CERT2);
+ ADD(EX_EI_ED_BAD_SIG1);
+ ADD(EX_EI_ED_BAD_SIG2);
+ ADD(EX_EI_ED_MISPLACED_CERT);
+ ADD(EX_EI_ED_MISPLACED_SIG);
+
CHECK_OK(EX_EI_MINIMAL);
tt_assert(!ei->pending_sig);
CHECK_OK(EX_EI_MAXIMAL);
tt_assert(!ei->pending_sig);
+ CHECK_OK(EX_EI_GOOD_ED_EI);
+ tt_assert(!ei->pending_sig);
CHECK_FAIL(EX_EI_BAD_SIG1,1);
CHECK_FAIL(EX_EI_BAD_SIG2,1);
@@ -518,6 +552,15 @@ test_dir_extrainfo_parsing(void *arg)
CHECK_FAIL(EX_EI_BAD_START,0);
CHECK_FAIL(EX_EI_BAD_PUBLISHED,0);
+ CHECK_FAIL(EX_EI_ED_MISSING_SIG,0);
+ CHECK_FAIL(EX_EI_ED_MISSING_CERT,0);
+ CHECK_FAIL(EX_EI_ED_BAD_CERT1,0);
+ CHECK_FAIL(EX_EI_ED_BAD_CERT2,0);
+ CHECK_FAIL(EX_EI_ED_BAD_SIG1,0);
+ CHECK_FAIL(EX_EI_ED_BAD_SIG2,0);
+ CHECK_FAIL(EX_EI_ED_MISPLACED_CERT,0);
+ CHECK_FAIL(EX_EI_ED_MISPLACED_SIG,0);
+
#undef CHECK_OK
#undef CHECK_FAIL
1
0

28 May '15
commit 55bb7bbafd1272a1bc36a17d89bd2419d59b113a
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Oct 16 09:07:50 2014 -0400
Tests for AUTHENTICATE cell functionality.
---
src/common/tortls.c | 8 +-
src/common/tortls.h | 4 +-
src/or/channel.c | 8 +-
src/or/channel.h | 5 +-
src/or/channeltls.c | 4 +-
src/or/channeltls.h | 2 +
src/test/test_link_handshake.c | 261 +++++++++++++++++++++++++++++++++++++++-
7 files changed, 276 insertions(+), 16 deletions(-)
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 62e32c5..e498b2a 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -2394,8 +2394,8 @@ tor_tls_peer_has_cert(tor_tls_t *tls)
}
/** Return the peer certificate, or NULL if there isn't one. */
-tor_x509_cert_t *
-tor_tls_get_peer_cert(tor_tls_t *tls)
+MOCK_IMPL(tor_x509_cert_t *,
+tor_tls_get_peer_cert,(tor_tls_t *tls))
{
X509 *cert;
cert = SSL_get_peer_certificate(tls->ssl);
@@ -2820,8 +2820,8 @@ tor_tls_server_got_renegotiate(tor_tls_t *tls)
* the v3 handshake to prove that the client knows the TLS secrets for the
* connection <b>tls</b>. Return 0 on success, -1 on failure.
*/
-int
-tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
+MOCK_IMPL(int,
+tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
{
#define TLSSECRET_MAGIC "Tor V3 handshake TLS cross-certification"
char buf[128];
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 11ef09f..1dc4b31 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -72,7 +72,7 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
int tor_tls_is_server(tor_tls_t *tls);
void tor_tls_free(tor_tls_t *tls);
int tor_tls_peer_has_cert(tor_tls_t *tls);
-tor_x509_cert_t *tor_tls_get_peer_cert(tor_tls_t *tls);
+MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls));
int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity);
int tor_tls_check_lifetime(int severity,
tor_tls_t *tls, int past_tolerance,
@@ -102,7 +102,7 @@ int tor_tls_used_v1_handshake(tor_tls_t *tls);
int tor_tls_received_v3_certificate(tor_tls_t *tls);
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
int tor_tls_server_got_renegotiate(tor_tls_t *tls);
-int tor_tls_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out);
+MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out));
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
diff --git a/src/or/channel.c b/src/or/channel.c
index bf0387f..af09502 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -4431,10 +4431,10 @@ channel_num_circuits(channel_t *chan)
* This is called when setting up a channel and replaces the old
* connection_or_set_circid_type()
*/
-void
-channel_set_circid_type(channel_t *chan,
- crypto_pk_t *identity_rcvd,
- int consider_identity)
+MOCK_IMPL(void,
+channel_set_circid_type,(channel_t *chan,
+ crypto_pk_t *identity_rcvd,
+ int consider_identity))
{
int started_here;
crypto_pk_t *our_identity;
diff --git a/src/or/channel.h b/src/or/channel.h
index ecc2a09..2b38ca7 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -562,8 +562,9 @@ int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
int channel_matches_target_addr_for_extend(channel_t *chan,
const tor_addr_t *target);
unsigned int channel_num_circuits(channel_t *chan);
-void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd,
- int consider_identity);
+MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
+ crypto_pk_t *identity_rcvd,
+ int consider_identity));
void channel_timestamp_client(channel_t *chan);
void channel_update_xmit_queue_size(channel_t *chan);
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index af7f474..af63444 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -90,8 +90,6 @@ static void channel_tls_process_versions_cell(var_cell_t *cell,
channel_tls_t *tlschan);
static void channel_tls_process_netinfo_cell(cell_t *cell,
channel_tls_t *tlschan);
-static void channel_tls_process_authenticate_cell(var_cell_t *cell,
- channel_tls_t *tlschan);
static int command_allowed_before_handshake(uint8_t command);
static int enter_v3_handshake_with_cell(var_cell_t *cell,
channel_tls_t *tlschan);
@@ -2037,7 +2035,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
* the identity of the router on the other side of the connection.
*/
-static void
+STATIC void
channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
{
uint8_t expected[V3_AUTH_FIXED_PART_LEN];
diff --git a/src/or/channeltls.h b/src/or/channeltls.h
index 69f6e62..a0df9fa 100644
--- a/src/or/channeltls.h
+++ b/src/or/channeltls.h
@@ -58,6 +58,8 @@ STATIC void channel_tls_process_certs_cell(var_cell_t *cell,
STATIC void channel_tls_process_auth_challenge_cell(var_cell_t *cell,
channel_tls_t *tlschan);
STATIC void channel_tls_common_init(channel_tls_t *tlschan);
+STATIC void channel_tls_process_authenticate_cell(var_cell_t *cell,
+ channel_tls_t *tlschan);
#endif
#endif
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index eb72a0c..e164022 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -12,6 +12,7 @@
#include "connection_or.h"
#include "channeltls.h"
#include "link_handshake.h"
+#include "scheduler.h"
#include "test.h"
@@ -582,6 +583,243 @@ AUTHCHALLENGE_FAIL(truncated,
AUTHCHALLENGE_FAIL(nonzero_circid,
d->cell->circ_id = 1337)
+
+static tor_x509_cert_t *mock_peer_cert = NULL;
+static tor_x509_cert_t *
+mock_get_peer_cert(tor_tls_t *tls)
+{
+ (void)tls;
+ return mock_peer_cert;
+}
+
+static int
+mock_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
+{
+ (void)tls;
+ memcpy(secrets_out, "int getRandomNumber(){return 4;}", 32);
+ return 0;
+}
+
+static void
+mock_set_circid_type(channel_t *chan,
+ crypto_pk_t *identity_rcvd,
+ int consider_identity)
+{
+ (void) chan;
+ (void) identity_rcvd;
+ (void) consider_identity;
+}
+
+typedef struct authenticate_data_s {
+ or_connection_t *c1, *c2;
+ channel_tls_t *chan2;
+ var_cell_t *cell;
+} authenticate_data_t;
+
+static int
+authenticate_data_cleanup(const struct testcase_t *test, void *arg)
+{
+ (void) test;
+ UNMOCK(connection_or_write_var_cell_to_buf);
+ UNMOCK(tor_tls_get_peer_cert);
+ UNMOCK(tor_tls_get_tlssecrets);
+ UNMOCK(connection_or_close_for_error);
+ UNMOCK(channel_set_circid_type);
+ authenticate_data_t *d = arg;
+ if (d) {
+ tor_free(d->cell);
+ connection_free_(TO_CONN(d->c1));
+ connection_free_(TO_CONN(d->c2));
+ tor_free(d->chan2);
+ }
+ mock_peer_cert = NULL;
+
+ return 1;
+}
+
+static void *
+authenticate_data_setup(const struct testcase_t *test)
+{
+ authenticate_data_t *d = tor_malloc_zero(sizeof(*d));
+
+ scheduler_init();
+
+ MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
+ MOCK(tor_tls_get_peer_cert, mock_get_peer_cert);
+ MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets);
+ MOCK(connection_or_close_for_error, mock_close_for_err);
+ MOCK(channel_set_circid_type, mock_set_circid_type);
+ d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
+ d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
+
+ crypto_pk_t *key1 = NULL, *key2 = NULL;
+ key1 = pk_generate(2);
+ key2 = pk_generate(3);
+ tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+ key1, key2, 86400), ==, 0);
+
+ d->c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->c1->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(d->c1, 1), ==, 0);
+
+ d->c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
+ d->c2->link_proto = 3;
+ tt_int_op(connection_init_or_handshake_state(d->c2, 0), ==, 0);
+ var_cell_t *cell = var_cell_new(16);
+ cell->command = CELL_CERTS;
+ or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 1);
+ or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 0);
+ memset(cell->payload, 0xf0, 16);
+ or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 0);
+ or_handshake_state_record_var_cell(d->c2, d->c2->handshake_state, cell, 1);
+ tor_free(cell);
+
+ d->chan2 = tor_malloc_zero(sizeof(*d->chan2));
+ channel_tls_common_init(d->chan2);
+ d->c2->chan = d->chan2;
+ d->chan2->conn = d->c2;
+ d->c2->base_.address = tor_strdup("C2");
+ d->c2->tls = tor_tls_new(-1, 1);
+ d->c2->handshake_state->received_certs_cell = 1;
+
+ const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL, *auth_cert=NULL;
+ tt_assert(! tor_tls_get_my_certs(1, &link_cert, &id_cert));
+
+ const uint8_t *der;
+ size_t sz;
+ tor_x509_cert_get_der(id_cert, &der, &sz);
+ d->c1->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
+ d->c2->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
+
+ tor_x509_cert_get_der(link_cert, &der, &sz);
+ mock_peer_cert = tor_x509_cert_decode(der, sz);
+ tt_assert(mock_peer_cert);
+ tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert));
+ tor_x509_cert_get_der(auth_cert, &der, &sz);
+ d->c2->handshake_state->auth_cert = tor_x509_cert_decode(der, sz);
+
+ /* Make an authenticate cell ... */
+ tt_int_op(0, ==, connection_or_send_authenticate_cell(d->c1,
+ AUTHTYPE_RSA_SHA256_TLSSECRET));
+ tt_assert(mock_got_var_cell);
+ d->cell = mock_got_var_cell;
+ mock_got_var_cell = NULL;
+
+ return d;
+ done:
+ authenticate_data_cleanup(test, d);
+ return NULL;
+}
+
+static struct testcase_setup_t setup_authenticate = {
+ .setup_fn = authenticate_data_setup,
+ .cleanup_fn = authenticate_data_cleanup
+};
+
+static void
+test_link_handshake_auth_cell(void *arg)
+{
+ authenticate_data_t *d = arg;
+ auth1_t *auth1 = NULL;
+
+ /* Is the cell well-formed on the outer layer? */
+ tt_int_op(d->cell->command, ==, CELL_AUTHENTICATE);
+ tt_int_op(d->cell->payload[0], ==, 0);
+ tt_int_op(d->cell->payload[1], ==, 1);
+ tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), ==,
+ d->cell->payload_len - 4);
+
+ /* Check it out for plausibility... */
+ auth_ctx_t ctx;
+ ctx.is_ed = 0;
+ tt_int_op(d->cell->payload_len-4, ==, auth1_parse(&auth1,
+ d->cell->payload+4,
+ d->cell->payload_len - 4, &ctx));
+ tt_assert(auth1);
+
+ tt_mem_op(auth1->type, ==, "AUTH0001", 8);
+ tt_mem_op(auth1->tlssecrets, ==, "int getRandomNumber(){return 4;}", 32);
+ tt_int_op(auth1_getlen_sig(auth1), >, 120);
+
+ /* Is the signature okay? */
+ uint8_t sig[128];
+ uint8_t digest[32];
+ int n = crypto_pk_public_checksig(
+ tor_tls_cert_get_key(d->c2->handshake_state->auth_cert),
+ (char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1),
+ auth1_getlen_sig(auth1));
+ tt_int_op(n, ==, 32);
+ const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed;
+ crypto_digest256((char*)digest,
+ (const char*)start, end-start, DIGEST_SHA256);
+ tt_mem_op(sig, ==, digest, 32);
+
+ /* Then feed it to c2. */
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0);
+ channel_tls_process_authenticate_cell(d->cell, d->chan2);
+ tt_int_op(mock_close_called, ==, 0);
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+
+ done:
+ auth1_free(auth1);
+}
+
+#define AUTHENTICATE_FAIL(name, code) \
+ static void \
+ test_link_handshake_auth_ ## name (void *arg) \
+ { \
+ authenticate_data_t *d = arg; \
+ { code ; } \
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ channel_tls_process_authenticate_cell(d->cell, d->chan2); \
+ tt_int_op(mock_close_called, ==, 1); \
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ done: \
+ ; \
+ }
+
+AUTHENTICATE_FAIL(badstate,
+ d->c2->base_.state = OR_CONN_STATE_CONNECTING)
+AUTHENTICATE_FAIL(badproto,
+ d->c2->link_proto = 2)
+AUTHENTICATE_FAIL(atclient,
+ d->c2->handshake_state->started_here = 1)
+AUTHENTICATE_FAIL(duplicate,
+ d->c2->handshake_state->received_authenticate = 1)
+static void
+test_link_handshake_auth_already_authenticated(void *arg)
+{
+ authenticate_data_t *d = arg;
+ d->c2->handshake_state->authenticated = 1;
+ channel_tls_process_authenticate_cell(d->cell, d->chan2);
+ tt_int_op(mock_close_called, ==, 1);
+ tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+ done:
+ ;
+}
+AUTHENTICATE_FAIL(nocerts,
+ d->c2->handshake_state->received_certs_cell = 0)
+AUTHENTICATE_FAIL(noidcert,
+ d->c2->handshake_state->id_cert = NULL)
+AUTHENTICATE_FAIL(noauthcert,
+ d->c2->handshake_state->auth_cert = NULL)
+AUTHENTICATE_FAIL(tooshort,
+ d->cell->payload_len = 3)
+AUTHENTICATE_FAIL(badtype,
+ d->cell->payload[0] = 0xff)
+AUTHENTICATE_FAIL(truncated_1,
+ d->cell->payload[2]++)
+AUTHENTICATE_FAIL(truncated_2,
+ d->cell->payload[3]++)
+AUTHENTICATE_FAIL(tooshort_1,
+ tt_int_op(d->cell->payload_len, >=, 260);
+ d->cell->payload[2] -= 1;
+ d->cell->payload_len -= 256;)
+AUTHENTICATE_FAIL(badcontent,
+ d->cell->payload[10] ^= 0xff)
+AUTHENTICATE_FAIL(badsig_1,
+ d->cell->payload[d->cell->payload_len - 5] ^= 0xff)
+
#define TEST(name, flags) \
{ #name , test_link_handshake_ ## name, (flags), NULL, NULL }
@@ -595,6 +833,10 @@ AUTHCHALLENGE_FAIL(nonzero_circid,
test_link_handshake_recv_certs_ ## name, TT_FORK, \
&setup_recv_certs, NULL }
+#define TEST_AUTHENTICATE(name) \
+ { "authenticate/" #name , test_link_handshake_auth_ ## name, TT_FORK, \
+ &setup_authenticate, NULL }
+
struct testcase_t link_handshake_tests[] = {
TEST(certs_ok, TT_FORK),
//TEST(certs_bad, TT_FORK),
@@ -632,6 +874,23 @@ struct testcase_t link_handshake_tests[] = {
TEST_RCV_AUTHCHALLENGE(truncated),
TEST_RCV_AUTHCHALLENGE(nonzero_circid),
+ TEST_AUTHENTICATE(cell),
+ TEST_AUTHENTICATE(badstate),
+ TEST_AUTHENTICATE(badproto),
+ TEST_AUTHENTICATE(atclient),
+ TEST_AUTHENTICATE(duplicate),
+ TEST_AUTHENTICATE(already_authenticated),
+ TEST_AUTHENTICATE(nocerts),
+ TEST_AUTHENTICATE(noidcert),
+ TEST_AUTHENTICATE(noauthcert),
+ TEST_AUTHENTICATE(tooshort),
+ TEST_AUTHENTICATE(badtype),
+ TEST_AUTHENTICATE(truncated_1),
+ TEST_AUTHENTICATE(truncated_2),
+ TEST_AUTHENTICATE(tooshort_1),
+ TEST_AUTHENTICATE(badcontent),
+ TEST_AUTHENTICATE(badsig_1),
+ //TEST_AUTHENTICATE(),
+
END_OF_TESTCASES
};
-
1
0

28 May '15
commit d4a6b1a4209f0b3995c0f61ad9cbe687e09a6fb0
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Thu Nov 13 10:03:55 2014 -0500
Implement ed25519 identity collation for voting.
This is a new collator type that follows proposal 220 for deciding
which identities to include. The rule is (approximately):
If a <ed,rsa> identity is listed by more than half of authorities,
include it. And include all <rsa> votes about that node as
matching.
Otherwise, if an <*,rsa> or <rsa> identity is listed by more than
half of the authorities, and no <ed,rsa> has been listed, include
it.
---
src/or/dircollate.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++---
src/or/dircollate.h | 7 ++-
src/or/dirvote.c | 2 +-
src/or/or.h | 1 +
4 files changed, 150 insertions(+), 9 deletions(-)
diff --git a/src/or/dircollate.c b/src/or/dircollate.c
index 92f3dcc..20dfb35 100644
--- a/src/or/dircollate.c
+++ b/src/or/dircollate.c
@@ -12,9 +12,55 @@
#define DIRCOLLATE_PRIVATE
#include "dircollate.h"
+#include "dirvote.h"
static void dircollator_collate_by_rsa(dircollator_t *dc);
+static void dircollator_collate_by_ed25519(dircollator_t *dc);
+typedef struct ddmap_entry_s {
+ HT_ENTRY(ddmap_entry_s) node;
+ uint8_t d[DIGEST_LEN + DIGEST256_LEN];
+ vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
+} ddmap_entry_t;
+
+struct double_digest_map_s *by_both_ids;
+
+static void
+ddmap_entry_free(ddmap_entry_t *e)
+{
+ tor_free(e);
+}
+
+static ddmap_entry_t *
+ddmap_entry_new(int n_votes)
+{
+ return tor_malloc_zero(STRUCT_OFFSET(ddmap_entry_t, vrs_lst) +
+ sizeof(vote_routerstatus_t *) * n_votes);
+}
+
+static unsigned
+ddmap_entry_hash(const ddmap_entry_t *ent)
+{
+ return (unsigned) siphash24g(ent->d, sizeof(ent->d));
+}
+
+static unsigned
+ddmap_entry_eq(const ddmap_entry_t *a, const ddmap_entry_t *b)
+{
+ return fast_memeq(a->d, b->d, sizeof(a->d));
+}
+
+static void
+ddmap_entry_set_digests(ddmap_entry_t *ent,
+ const uint8_t *rsa_sha1,
+ const uint8_t *ed25519)
+{
+ memcpy(ent->d, rsa_sha1, DIGEST_LEN);
+ memcpy(ent->d + DIGEST_LEN, ed25519, DIGEST256_LEN);
+}
+
+HT_PROTOTYPE(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, ddmap_entry_eq);
+HT_GENERATE2(double_digest_map, ddmap_entry_s, node, ddmap_entry_hash, ddmap_entry_eq, 0.6, tor_reallocarray, tor_free_);
static void
dircollator_add_routerstatus(dircollator_t *dc,
int vote_num,
@@ -29,7 +75,24 @@ dircollator_add_routerstatus(dircollator_t *dc,
vrs_lst = tor_calloc(sizeof(vote_routerstatus_t *), dc->n_votes);
digestmap_set(dc->by_rsa_sha1, id, vrs_lst);
}
+ tor_assert(vrs_lst[vote_num] == NULL);
+ vrs_lst[vote_num] = vrs;
+ const uint8_t *ed = vrs->ed25519_id;
+
+ if (tor_mem_is_zero((char*)ed, DIGEST256_LEN))
+ return;
+
+ ddmap_entry_t search, *found;
+ memset(&search, 0, sizeof(search));
+ ddmap_entry_set_digests(&search, (const uint8_t *)id, ed);
+ found = HT_FIND(double_digest_map, &dc->by_both_ids, &search);
+ if (NULL == found) {
+ found = ddmap_entry_new(dc->n_votes);
+ ddmap_entry_set_digests(found, (const uint8_t *)id, ed);
+ HT_INSERT(double_digest_map, &dc->by_both_ids, found);
+ }
+ vrs_lst = found->vrs_lst;
tor_assert(vrs_lst[vote_num] == NULL);
vrs_lst[vote_num] = vrs;
}
@@ -45,6 +108,7 @@ dircollator_new(int n_votes, int n_authorities)
dc->n_authorities = n_authorities;
dc->by_rsa_sha1 = digestmap_new();
+ HT_INIT(double_digest_map, &dc->by_both_ids);
return dc;
}
@@ -55,8 +119,20 @@ dircollator_free(dircollator_t *dc)
if (!dc)
return;
+ if (dc->by_collated_rsa_sha1 != dc->by_rsa_sha1)
+ digestmap_free(dc->by_collated_rsa_sha1, NULL);
+
digestmap_free(dc->by_rsa_sha1, tor_free_);
+ ddmap_entry_t **e, **next, *this;
+ for (e = HT_START(double_digest_map, &dc->by_both_ids);
+ e != NULL; e = next) {
+ this = *e;
+ next = HT_NEXT_RMV(double_digest_map, &dc->by_both_ids, e);
+ ddmap_entry_free(this);
+ }
+ HT_CLEAR(double_digest_map, &dc->by_both_ids);
+
tor_free(dc);
}
@@ -75,21 +151,80 @@ dircollator_add_vote(dircollator_t *dc, networkstatus_t *v)
}
void
-dircollator_collate(dircollator_t *dc)
+dircollator_collate(dircollator_t *dc, int consensus_method)
{
- dircollator_collate_by_rsa(dc);
+ tor_assert(!dc->is_collated);
+ dc->all_rsa_sha1_lst = smartlist_new();
+
+ if (consensus_method < MIN_METHOD_FOR_ED25519_ID_VOTING + 10/*XXX*/)
+ dircollator_collate_by_rsa(dc);
+ else
+ dircollator_collate_by_ed25519(dc);
+
+ smartlist_sort_digests(dc->all_rsa_sha1_lst);
+ dc->is_collated = 1;
}
static void
dircollator_collate_by_rsa(dircollator_t *dc)
{
- tor_assert(!dc->is_collated);
+ const int total_authorities = dc->n_authorities;
- dc->all_rsa_sha1_lst = smartlist_new();
+ DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
+ int n = 0, i;
+ for (i = 0; i < dc->n_votes; ++i) {
+ if (vrs_lst[i] != NULL)
+ ++n;
+ }
+
+ if (n <= total_authorities / 2)
+ continue;
+ smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
+ } DIGESTMAP_FOREACH_END;
+
+ dc->by_collated_rsa_sha1 = dc->by_rsa_sha1;
+}
+
+static void
+dircollator_collate_by_ed25519(dircollator_t *dc)
+{
const int total_authorities = dc->n_authorities;
+ digestmap_t *rsa_digests = digestmap_new();
+
+ ddmap_entry_t **iter;
+
+ HT_FOREACH(iter, double_digest_map, &dc->by_both_ids) {
+ ddmap_entry_t *ent = *iter;
+ int n = 0, i;
+ for (i = 0; i < dc->n_votes; ++i) {
+ if (ent->vrs_lst[i] != NULL)
+ ++n;
+ }
+
+ if (n <= total_authorities / 2)
+ continue;
+
+ vote_routerstatus_t **vrs_lst2 = digestmap_get(dc->by_rsa_sha1,
+ (char*)ent->d);
+ tor_assert(vrs_lst2);
+
+ for (i = 0; i < dc->n_votes; ++i) {
+ if (ent->vrs_lst[i] != NULL) {
+ ent->vrs_lst[i]->ed25519_reflects_consensus = 1;
+ } else if (vrs_lst2[i] && ! vrs_lst2[i]->has_ed25519_listing) {
+ ent->vrs_lst[i] = vrs_lst2[i];
+ }
+ }
+
+ digestmap_set(rsa_digests, (char*)ent->d, ent->vrs_lst);
+ smartlist_add(dc->all_rsa_sha1_lst, ent->d);
+ }
DIGESTMAP_FOREACH(dc->by_rsa_sha1, k, vote_routerstatus_t **, vrs_lst) {
+ if (digestmap_get(rsa_digests, k) != NULL)
+ continue;
+
int n = 0, i;
for (i = 0; i < dc->n_votes; ++i) {
if (vrs_lst[i] != NULL)
@@ -99,11 +234,11 @@ dircollator_collate_by_rsa(dircollator_t *dc)
if (n <= total_authorities / 2)
continue;
+ digestmap_set(rsa_digests, k, vrs_lst);
smartlist_add(dc->all_rsa_sha1_lst, (char *)k);
} DIGESTMAP_FOREACH_END;
- smartlist_sort_digests(dc->all_rsa_sha1_lst);
- dc->is_collated = 1;
+ dc->by_collated_rsa_sha1 = rsa_digests;
}
int
@@ -116,7 +251,7 @@ vote_routerstatus_t **
dircollator_get_votes_for_router(dircollator_t *dc, int idx)
{
tor_assert(idx < smartlist_len(dc->all_rsa_sha1_lst));
- return digestmap_get(dc->by_rsa_sha1,
+ return digestmap_get(dc->by_collated_rsa_sha1,
smartlist_get(dc->all_rsa_sha1_lst, idx));
}
diff --git a/src/or/dircollate.h b/src/or/dircollate.h
index 073b611..9eba37a 100644
--- a/src/or/dircollate.h
+++ b/src/or/dircollate.h
@@ -21,13 +21,15 @@ dircollator_t *dircollator_new(int n_votes, int n_authorities);
void dircollator_free(dircollator_t *obj);
void dircollator_add_vote(dircollator_t *dc, networkstatus_t *v);
-void dircollator_collate(dircollator_t *dc);
+void dircollator_collate(dircollator_t *dc, int consensus_method);
int dircollator_n_routers(dircollator_t *dc);
vote_routerstatus_t **dircollator_get_votes_for_router(dircollator_t *dc,
int idx);
#ifdef DIRCOLLATE_PRIVATE
+struct ddmap_entry_s;
+typedef HT_HEAD(double_digest_map, ddmap_entry_s) double_digest_map_t;
struct dircollator_s {
/**DOCDOC */
int is_collated;
@@ -36,6 +38,9 @@ struct dircollator_s {
int next_vote_num;
digestmap_t *by_rsa_sha1;
+ struct double_digest_map by_both_ids;
+
+ digestmap_t *by_collated_rsa_sha1;
smartlist_t *all_rsa_sha1_lst;
};
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 6a70c13..549dec1 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -1502,7 +1502,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
dircollator_add_vote(collator, v);
} SMARTLIST_FOREACH_END(v);
- dircollator_collate(collator);
+ dircollator_collate(collator, consensus_method);
/* Now go through all the votes */
flag_counts = tor_calloc(smartlist_len(flags), sizeof(int));
diff --git a/src/or/or.h b/src/or/or.h
index a41a14e..b07a596 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2357,6 +2357,7 @@ typedef struct vote_routerstatus_t {
* running. */
unsigned int has_measured_bw:1; /**< The vote had a measured bw */
unsigned int has_ed25519_listing:1; /** DOCDOC */
+ unsigned int ed25519_reflects_consensus:1; /** DOCDOC */
uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */
/** The hash or hashes that the authority claims this microdesc has. */
vote_microdesc_hash_t *microdesc;
1
0