Merge branch 'feature_15055_v2'

This commit is contained in:
Nick Mathewson 2016-11-03 08:44:46 -04:00
commit d9ca4e20bd
28 changed files with 2464 additions and 413 deletions

6
changes/bug17779 Normal file
View File

@ -0,0 +1,6 @@
o Minor bugfixes (leak at exit):
- Fix a small harmless memory leak at exit of the previously unused
RSA->Ed identity cross-certificate. Fixes 17779; bugfix on
0.2.7.2-alpha.

3
changes/bug20027 Normal file
View File

@ -0,0 +1,3 @@
o Minor bugfixes (ed25519 certificates):
- Correctly interpret ed25519 certificates that would expire some
time after 19 Jan 2038. Fixes bug 20027; bugfix on 0.2.7.2-alpha.

4
changes/feature13752 Normal file
View File

@ -0,0 +1,4 @@
o Minor features (fingerprinting resistence, authentication):
- Extend the length of RSA keys used for TLS link authentication to
2048 bits. (These weren't used for forward secrecy; for forward
secrecy, we used P256.) Closes ticket 13752.

6
changes/feature15055 Normal file
View File

@ -0,0 +1,6 @@
o Major features (protocol, Ed25519):
- Tor relays now use Ed25519 to prove their Ed25519 identities and
Ed25519 to one another, and to clients. This algorithm is faster
and more secure than the RSA-based handshake we've been doing until
now. Implements the second big part of proposal 220; Closes ticket
15055.

View File

@ -136,6 +136,7 @@ static void tor_tls_context_decref(tor_tls_context_t *ctx);
static void tor_tls_context_incref(tor_tls_context_t *ctx);
static int check_cert_lifetime_internal(int severity, const X509 *cert,
time_t now,
int past_tolerance, int future_tolerance);
/** Global TLS contexts. We keep them here because nobody else needs
@ -522,7 +523,8 @@ MOCK_IMPL(STATIC X509 *,
goto error;
if (!X509_set_pubkey(x509, pkey))
goto error;
if (!X509_sign(x509, sign_pkey, EVP_sha1()))
if (!X509_sign(x509, sign_pkey, EVP_sha256()))
goto error;
goto done;
@ -677,6 +679,13 @@ MOCK_IMPL(STATIC tor_x509_cert_t *,
return cert;
}
/** Return a copy of <b>cert</b> */
tor_x509_cert_t *
tor_x509_cert_dup(const tor_x509_cert_t *cert)
{
return tor_x509_cert_new(X509_dup(cert->cert));
}
/** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>,
* from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on
* success and NULL on failure. */
@ -769,8 +778,8 @@ tor_tls_context_decref(tor_tls_context_t *ctx)
/** Set *<b>link_cert_out</b> and *<b>id_cert_out</b> to the link certificate
* and ID certificate that we're currently using for our V3 in-protocol
* handshake's certificate chain. If <b>server</b> is true, provide the certs
* that we use in server mode; otherwise, provide the certs that we use in
* client mode. */
* that we use in server mode (auth, ID); otherwise, provide the certs that we
* use in client mode. (link, ID) */
int
tor_tls_get_my_certs(int server,
const tor_x509_cert_t **link_cert_out,
@ -800,7 +809,7 @@ tor_tls_get_my_client_auth_key(void)
/**
* Return a newly allocated copy of the public key that a certificate
* certifies. Return NULL if the cert's key is not RSA.
* certifies. Watch out! This returns NULL if the cert's key is not RSA.
*/
crypto_pk_t *
tor_tls_cert_get_key(tor_x509_cert_t *cert)
@ -855,6 +864,7 @@ int
tor_tls_cert_is_valid(int severity,
const tor_x509_cert_t *cert,
const tor_x509_cert_t *signing_cert,
time_t now,
int check_rsa_1024)
{
check_no_tls_errors();
@ -874,7 +884,7 @@ tor_tls_cert_is_valid(int severity,
/* okay, the signature checked out right. Now let's check the check the
* lifetime. */
if (check_cert_lifetime_internal(severity, cert->cert,
if (check_cert_lifetime_internal(severity, cert->cert, now,
48*60*60, 30*24*60*60) < 0)
goto bad;
@ -1019,6 +1029,8 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
/** The group we should use for ecdhe when none was selected. */
#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1
#define RSA_LINK_KEY_BITS 2048
/** Create a new TLS context for use with Tor TLS handshakes.
* <b>identity</b> should be set to the identity key used to sign the
* certificate.
@ -1044,7 +1056,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
/* Generate short-term RSA key for use with TLS. */
if (!(rsa = crypto_pk_new()))
goto error;
if (crypto_pk_generate_key(rsa)<0)
if (crypto_pk_generate_key_with_bits(rsa, RSA_LINK_KEY_BITS)<0)
goto error;
if (!is_client) {
/* Generate short-term RSA key for use in the in-protocol ("v3")
@ -2023,13 +2035,13 @@ tor_tls_get_peer_cert,(tor_tls_t *tls))
/** Warn that a certificate lifetime extends through a certain range. */
static void
log_cert_lifetime(int severity, const X509 *cert, const char *problem)
log_cert_lifetime(int severity, const X509 *cert, const char *problem,
time_t now)
{
BIO *bio = NULL;
BUF_MEM *buf;
char *s1=NULL, *s2=NULL;
char mytime[33];
time_t now = time(NULL);
struct tm tm;
size_t n;
@ -2177,6 +2189,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
*/
int
tor_tls_check_lifetime(int severity, tor_tls_t *tls,
time_t now,
int past_tolerance, int future_tolerance)
{
X509 *cert;
@ -2185,7 +2198,7 @@ tor_tls_check_lifetime(int severity, tor_tls_t *tls,
if (!(cert = SSL_get_peer_certificate(tls->ssl)))
goto done;
if (check_cert_lifetime_internal(severity, cert,
if (check_cert_lifetime_internal(severity, cert, now,
past_tolerance, future_tolerance) < 0)
goto done;
@ -2201,24 +2214,24 @@ tor_tls_check_lifetime(int severity, tor_tls_t *tls,
/** Helper: check whether <b>cert</b> is expired give or take
* <b>past_tolerance</b> seconds, or not-yet-valid give or take
* <b>future_tolerance</b> seconds. If it is live, return 0. If it is not
* live, log a message and return -1. */
* <b>future_tolerance</b> seconds. (Relative to the current time
* <b>now</b>.) If it is live, return 0. If it is not live, log a message
* and return -1. */
static int
check_cert_lifetime_internal(int severity, const X509 *cert,
time_t now,
int past_tolerance, int future_tolerance)
{
time_t now, t;
now = time(NULL);
time_t t;
t = now + future_tolerance;
if (X509_cmp_time(X509_get_notBefore_const(cert), &t) > 0) {
log_cert_lifetime(severity, cert, "not yet valid");
log_cert_lifetime(severity, cert, "not yet valid", now);
return -1;
}
t = now - past_tolerance;
if (X509_cmp_time(X509_get_notAfter_const(cert), &t) < 0) {
log_cert_lifetime(severity, cert, "already expired");
log_cert_lifetime(severity, cert, "already expired", now);
return -1;
}
@ -2443,6 +2456,28 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
return 0;
}
/** Using the RFC5705 key material exporting construction, and the
* provided <b>context</b> (<b>context_len</b> bytes long) and
* <b>label</b> (a NUL-terminated string), compute a 32-byte secret in
* <b>secrets_out</b> that only the parties to this TLS session can
* compute. Return 0 on success and -1 on failure.
*/
MOCK_IMPL(int,
tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
const uint8_t *context,
size_t context_len,
const char *label))
{
tor_assert(tls);
tor_assert(tls->ssl);
int r = SSL_export_keying_material(tls->ssl,
secrets_out, DIGEST256_LEN,
label, strlen(label),
context, context_len, 1);
return (r == 1) ? 0 : -1;
}
/** Examine the amount of memory used and available for buffers in <b>tls</b>.
* Set *<b>rbuf_capacity</b> to the amount of storage allocated for the read
* buffer and *<b>rbuf_bytes</b> to the amount actually used.

View File

@ -176,6 +176,7 @@ extern uint64_t total_bytes_written_by_tls;
#endif /* endif TORTLS_PRIVATE */
tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert);
const char *tor_tls_err_to_string(int err);
void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz);
@ -200,7 +201,8 @@ int tor_tls_peer_has_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,
tor_tls_t *tls, time_t now,
int past_tolerance,
int future_tolerance);
MOCK_DECL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len));
int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n);
@ -226,6 +228,11 @@ int tor_tls_used_v1_handshake(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);
MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out));
MOCK_DECL(int,tor_tls_export_key_material,(
tor_tls_t *tls, uint8_t *secrets_out,
const uint8_t *context,
size_t context_len,
const char *label));
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
@ -254,6 +261,7 @@ MOCK_DECL(int,tor_tls_cert_matches_key,(const tor_tls_t *tls,
int tor_tls_cert_is_valid(int severity,
const tor_x509_cert_t *cert,
const tor_x509_cert_t *signing_cert,
time_t now,
int check_rsa_1024);
const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls);

View File

@ -3220,9 +3220,10 @@ channel_free_all(void)
channel_t *
channel_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest)
const char *id_digest,
const ed25519_public_key_t *ed_id)
{
return channel_tls_connect(addr, port, id_digest);
return channel_tls_connect(addr, port, id_digest, ed_id);
}
/**

View File

@ -489,7 +489,8 @@ int channel_send_destroy(circid_t circ_id, channel_t *chan,
*/
channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest);
const char *id_digest,
const ed25519_public_key_t *ed_id);
channel_t * channel_get_for_extend(const char *digest,
const tor_addr_t *target_addr,

View File

@ -55,6 +55,7 @@
#include "router.h"
#include "routerlist.h"
#include "scheduler.h"
#include "torcert.h"
/** How many CELL_PADDING cells have we received, ever? */
uint64_t stats_n_padding_cells_processed = 0;
@ -170,8 +171,10 @@ channel_tls_common_init(channel_tls_t *tlschan)
channel_t *
channel_tls_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest)
const char *id_digest,
const ed25519_public_key_t *ed_id)
{
(void) ed_id; // XXXX not fully used yet
channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
channel_t *chan = &(tlschan->base_);
@ -198,7 +201,7 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port,
channel_mark_outgoing(chan);
/* Set up or_connection stuff */
tlschan->conn = connection_or_connect(addr, port, id_digest, tlschan);
tlschan->conn = connection_or_connect(addr, port, id_digest, ed_id, tlschan);
/* connection_or_connect() will fill in tlschan->conn */
if (!(tlschan->conn)) {
chan->reason_for_closing = CHANNEL_CLOSE_FOR_ERROR;
@ -1639,7 +1642,10 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
if (!(chan->conn->handshake_state->authenticated)) {
tor_assert(tor_digest_is_zero(
(const char*)(chan->conn->handshake_state->
authenticated_peer_id)));
authenticated_rsa_peer_id)));
tor_assert(tor_mem_is_zero(
(const char*)(chan->conn->handshake_state->
authenticated_ed25519_peer_id.pubkey), 32));
channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
@ -1647,7 +1653,8 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
&(chan->conn->base_.addr),
chan->conn->base_.port,
(const char*)(chan->conn->handshake_state->
authenticated_peer_id),
authenticated_rsa_peer_id),
NULL, // XXXX Ed key
0);
}
}
@ -1744,6 +1751,41 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
assert_connection_ok(TO_CONN(chan->conn),time(NULL));
}
/** Types of certificates that we know how to parse from CERTS cells. Each
* type corresponds to a different encoding format. */
typedef enum cert_encoding_t {
CERT_ENCODING_UNKNOWN, /**< We don't recognize this. */
CERT_ENCODING_X509, /**< It's an RSA key, signed with RSA, encoded in x509.
* (Actually, it might not be RSA. We test that later.) */
CERT_ENCODING_ED25519, /**< It's something signed with an Ed25519 key,
* encoded asa a tor_cert_t.*/
CERT_ENCODING_RSA_CROSSCERT, /**< It's an Ed key signed with an RSA key. */
} cert_encoding_t;
/**
* Given one of the certificate type codes used in a CERTS cell,
* return the corresponding cert_encoding_t that we should use to parse
* the certificate.
*/
static cert_encoding_t
certs_cell_typenum_to_cert_type(int typenum)
{
switch (typenum) {
case CERTTYPE_RSA1024_ID_LINK:
case CERTTYPE_RSA1024_ID_ID:
case CERTTYPE_RSA1024_ID_AUTH:
return CERT_ENCODING_X509;
case CERTTYPE_ED_ID_SIGN:
case CERTTYPE_ED_SIGN_LINK:
case CERTTYPE_ED_SIGN_AUTH:
return CERT_ENCODING_ED25519;
case CERTTYPE_RSA1024_ID_EDID:
return CERT_ENCODING_RSA_CROSSCERT;
default:
return CERT_ENCODING_UNKNOWN;
}
}
/**
* Process a CERTS cell from a channel.
*
@ -1763,14 +1805,21 @@ 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)
{
#define MAX_CERT_TYPE_WANTED OR_CERT_TYPE_AUTH_1024
tor_x509_cert_t *certs[MAX_CERT_TYPE_WANTED + 1];
#define MAX_CERT_TYPE_WANTED CERTTYPE_RSA1024_ID_EDID
/* These arrays will be sparse, since a cert type can be at most one
* of ed/x509 */
tor_x509_cert_t *x509_certs[MAX_CERT_TYPE_WANTED + 1];
tor_cert_t *ed_certs[MAX_CERT_TYPE_WANTED + 1];
uint8_t *rsa_ed_cc_cert = NULL;
size_t rsa_ed_cc_cert_len = 0;
int n_certs, i;
certs_cell_t *cc = NULL;
int send_netinfo = 0;
memset(certs, 0, sizeof(certs));
memset(x509_certs, 0, sizeof(x509_certs));
memset(ed_certs, 0, sizeof(ed_certs));
tor_assert(cell);
tor_assert(chan);
tor_assert(chan->conn);
@ -1814,77 +1863,145 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
if (cert_type > MAX_CERT_TYPE_WANTED)
continue;
const cert_encoding_t ct = certs_cell_typenum_to_cert_type(cert_type);
switch (ct) {
default:
case CERT_ENCODING_UNKNOWN:
break;
case CERT_ENCODING_X509: {
tor_x509_cert_t *x509_cert = tor_x509_cert_decode(cert_body, cert_len);
if (!x509_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 (x509_certs[cert_type]) {
tor_x509_cert_free(x509_cert);
ERR("Duplicate x509 certificate");
} else {
x509_certs[cert_type] = x509_cert;
}
}
break;
}
case CERT_ENCODING_ED25519: {
tor_cert_t *ed_cert = tor_cert_parse(cert_body, cert_len);
if (!ed_cert) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received undecodable Ed certificate in CERTS cell from %s:%d",
safe_str(chan->conn->base_.address),
chan->conn->base_.port);
} else {
if (ed_certs[cert_type]) {
tor_cert_free(ed_cert);
ERR("Duplicate Ed25519 certificate");
} else {
ed_certs[cert_type] = ed_cert;
}
}
break;
}
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 {
certs[cert_type] = cert;
case CERT_ENCODING_RSA_CROSSCERT: {
if (rsa_ed_cc_cert) {
ERR("Duplicate RSA->Ed25519 crosscert");
} else {
rsa_ed_cc_cert = tor_memdup(cert_body, cert_len);
rsa_ed_cc_cert_len = cert_len;
}
break;
}
}
}
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];
/* Move the certificates we (might) want into the handshake_state->certs
* structure. */
tor_x509_cert_t *id_cert = x509_certs[CERTTYPE_RSA1024_ID_ID];
tor_x509_cert_t *auth_cert = x509_certs[CERTTYPE_RSA1024_ID_AUTH];
tor_x509_cert_t *link_cert = x509_certs[CERTTYPE_RSA1024_ID_LINK];
chan->conn->handshake_state->certs->auth_cert = auth_cert;
chan->conn->handshake_state->certs->link_cert = link_cert;
chan->conn->handshake_state->certs->id_cert = id_cert;
x509_certs[CERTTYPE_RSA1024_ID_ID] =
x509_certs[CERTTYPE_RSA1024_ID_AUTH] =
x509_certs[CERTTYPE_RSA1024_ID_LINK] = NULL;
tor_cert_t *ed_id_sign = ed_certs[CERTTYPE_ED_ID_SIGN];
tor_cert_t *ed_sign_link = ed_certs[CERTTYPE_ED_SIGN_LINK];
tor_cert_t *ed_sign_auth = ed_certs[CERTTYPE_ED_SIGN_AUTH];
chan->conn->handshake_state->certs->ed_id_sign = ed_id_sign;
chan->conn->handshake_state->certs->ed_sign_link = ed_sign_link;
chan->conn->handshake_state->certs->ed_sign_auth = ed_sign_auth;
ed_certs[CERTTYPE_ED_ID_SIGN] =
ed_certs[CERTTYPE_ED_SIGN_LINK] =
ed_certs[CERTTYPE_ED_SIGN_AUTH] = NULL;
chan->conn->handshake_state->certs->ed_rsa_crosscert = rsa_ed_cc_cert;
chan->conn->handshake_state->certs->ed_rsa_crosscert_len =
rsa_ed_cc_cert_len;
rsa_ed_cc_cert = NULL;
int severity;
/* Note that this warns more loudly about time and validity if we were
* _trying_ to connect to an authority, not necessarily if we _did_ connect
* to one. */
if (chan->conn->handshake_state->started_here &&
router_digest_is_trusted_dir(TLS_CHAN_TO_BASE(chan)->identity_digest))
severity = LOG_WARN;
else
severity = LOG_PROTOCOL_WARN;
const ed25519_public_key_t *checked_ed_id = NULL;
const common_digests_t *checked_rsa_id = NULL;
or_handshake_certs_check_both(severity,
chan->conn->handshake_state->certs,
chan->conn->tls,
time(NULL),
&checked_ed_id,
&checked_rsa_id);
if (!checked_rsa_id)
ERR("Invalid certificate chain!");
if (chan->conn->handshake_state->started_here) {
int severity;
if (! (id_cert && link_cert))
ERR("The certs we wanted were missing");
/* Okay. We should be able to check the certificates now. */
if (! tor_tls_cert_matches_key(chan->conn->tls, link_cert)) {
ERR("The link certificate didn't match the TLS public key");
}
/* Note that this warns more loudly about time and validity if we were
* _trying_ to connect to an authority, not necessarily if we _did_ connect
* to one. */
if (router_digest_is_trusted_dir(
TLS_CHAN_TO_BASE(chan)->identity_digest))
severity = LOG_WARN;
else
severity = LOG_PROTOCOL_WARN;
if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
ERR("The link certificate was not valid");
if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
ERR("The ID certificate was not valid");
/* No more information is needed. */
chan->conn->handshake_state->authenticated = 1;
chan->conn->handshake_state->authenticated_rsa = 1;
{
const common_digests_t *id_digests =
tor_x509_cert_get_id_digests(id_cert);
const common_digests_t *id_digests = checked_rsa_id;
crypto_pk_t *identity_rcvd;
if (!id_digests)
ERR("Couldn't compute digests for key in ID cert");
identity_rcvd = tor_tls_cert_get_key(id_cert);
if (!identity_rcvd)
ERR("Internal error: Couldn't get RSA key from ID cert.");
memcpy(chan->conn->handshake_state->authenticated_peer_id,
if (!identity_rcvd) {
ERR("Couldn't get RSA key from ID cert.");
}
memcpy(chan->conn->handshake_state->authenticated_rsa_peer_id,
id_digests->d[DIGEST_SHA1], DIGEST_LEN);
channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd,
chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
crypto_pk_free(identity_rcvd);
}
if (checked_ed_id) {
chan->conn->handshake_state->authenticated_ed25519 = 1;
memcpy(&chan->conn->handshake_state->authenticated_ed25519_peer_id,
checked_ed_id, sizeof(ed25519_public_key_t));
}
if (connection_or_client_learned_peer_id(chan->conn,
chan->conn->handshake_state->authenticated_peer_id) < 0)
chan->conn->handshake_state->authenticated_rsa_peer_id,
checked_ed_id) < 0)
ERR("Problem setting or checking peer id");
log_info(LD_OR,
"Got some good certificates from %s:%d: Authenticated it.",
safe_str(chan->conn->base_.address), chan->conn->base_.port);
chan->conn->handshake_state->id_cert = id_cert;
certs[OR_CERT_TYPE_ID_1024] = NULL;
"Got some good certificates from %s:%d: Authenticated it with "
"RSA%s",
safe_str(chan->conn->base_.address), chan->conn->base_.port,
checked_ed_id ? " and Ed25519" : "");
if (!public_server_mode(get_options())) {
/* If we initiated the connection and we are not a public server, we
@ -1893,25 +2010,14 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
send_netinfo = 1;
}
} else {
if (! (id_cert && auth_cert))
ERR("The certs we wanted were missing");
/* Remember these certificates so we can check an AUTHENTICATE cell */
if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
ERR("The authentication certificate was not valid");
if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
ERR("The ID certificate was not valid");
/* We can't call it authenticated till we see an AUTHENTICATE cell. */
log_info(LD_OR,
"Got some good certificates from %s:%d: "
"Got some good RSA%s certificates from %s:%d. "
"Waiting for AUTHENTICATE.",
checked_ed_id ? " and Ed25519" : "",
safe_str(chan->conn->base_.address),
chan->conn->base_.port);
/* XXXX check more stuff? */
chan->conn->handshake_state->id_cert = id_cert;
chan->conn->handshake_state->auth_cert = auth_cert;
certs[OR_CERT_TYPE_ID_1024] = certs[OR_CERT_TYPE_AUTH_1024] = NULL;
}
chan->conn->handshake_state->received_certs_cell = 1;
@ -1925,9 +2031,13 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
}
err:
for (unsigned u = 0; u < ARRAY_LENGTH(certs); ++u) {
tor_x509_cert_free(certs[u]);
for (unsigned u = 0; u < ARRAY_LENGTH(x509_certs); ++u) {
tor_x509_cert_free(x509_certs[u]);
}
for (unsigned u = 0; u < ARRAY_LENGTH(ed_certs); ++u) {
tor_cert_free(ed_certs[u]);
}
tor_free(rsa_ed_cc_cert);
certs_cell_free(cc);
#undef ERR
}
@ -1984,8 +2094,12 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
/* Now see if there is an authentication type we can use */
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;
if (authchallenge_type_is_supported(authtype)) {
if (use_type == -1 ||
authchallenge_type_is_better(authtype, use_type)) {
use_type = authtype;
}
}
}
chan->conn->handshake_state->received_auth_challenge = 1;
@ -2000,9 +2114,10 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
if (use_type >= 0) {
log_info(LD_OR,
"Got an AUTH_CHALLENGE cell from %s:%d: Sending "
"authentication",
"authentication type %d",
safe_str(chan->conn->base_.address),
chan->conn->base_.port);
chan->conn->base_.port,
use_type);
if (connection_or_send_authenticate_cell(chan->conn, use_type) < 0) {
log_warn(LD_OR,
@ -2043,9 +2158,11 @@ 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+256];
var_cell_t *expected_cell = NULL;
const uint8_t *auth;
int authlen;
int authtype;
int bodylen;
tor_assert(cell);
tor_assert(chan);
@ -2058,6 +2175,7 @@ channel_tls_process_authenticate_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); \
var_cell_free(expected_cell); \
return; \
} while (0)
@ -2075,9 +2193,7 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
}
if (!(chan->conn->handshake_state->received_certs_cell))
ERR("We never got a certs cell");
if (chan->conn->handshake_state->auth_cert == NULL)
ERR("We never got an authentication certificate");
if (chan->conn->handshake_state->id_cert == NULL)
if (chan->conn->handshake_state->certs->id_cert == NULL)
ERR("We never got an identity certificate");
if (cell->payload_len < 4)
ERR("Cell was way too short");
@ -2089,8 +2205,9 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
if (4 + len > cell->payload_len)
ERR("Authenticator was truncated");
if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
if (! authchallenge_type_is_supported(type))
ERR("Authenticator type was not recognized");
authtype = type;
auth += 4;
authlen = len;
@ -2099,25 +2216,55 @@ 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");
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)
expected_cell = connection_or_compute_authenticate_cell_body(
chan->conn, authtype, NULL, NULL, 1);
if (! expected_cell)
ERR("Couldn't compute expected AUTHENTICATE cell body");
if (tor_memneq(expected, auth, bodylen))
int sig_is_rsa;
if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET ||
authtype == AUTHTYPE_RSA_SHA256_RFC5705) {
bodylen = V3_AUTH_BODY_LEN;
sig_is_rsa = 1;
} else {
tor_assert(authtype == AUTHTYPE_ED25519_SHA256_RFC5705);
/* Our earlier check had better have made sure we had room
* for an ed25519 sig (inadvertently) */
tor_assert(V3_AUTH_BODY_LEN > ED25519_SIG_LEN);
bodylen = authlen - ED25519_SIG_LEN;
sig_is_rsa = 0;
}
if (expected_cell->payload_len != bodylen+4) {
ERR("Expected AUTHENTICATE cell body len not as expected.");
}
/* Length of random part. */
if (BUG(bodylen < 24)) {
// LCOV_EXCL_START
ERR("Bodylen is somehow less than 24, which should really be impossible");
// LCOV_EXCL_STOP
}
if (tor_memneq(expected_cell->payload+4, auth, bodylen-24))
ERR("Some field in the AUTHENTICATE cell body was not as expected");
{
if (sig_is_rsa) {
if (chan->conn->handshake_state->certs->ed_id_sign != NULL)
ERR("RSA-signed AUTHENTICATE response provided with an ED25519 cert");
if (chan->conn->handshake_state->certs->auth_cert == NULL)
ERR("We never got an RSA authentication certificate");
crypto_pk_t *pk = tor_tls_cert_get_key(
chan->conn->handshake_state->auth_cert);
chan->conn->handshake_state->certs->auth_cert);
char d[DIGEST256_LEN];
char *signed_data;
size_t keysize;
int signed_len;
if (!pk)
ERR("Internal error: couldn't get RSA key from AUTH cert.");
if (! pk) {
ERR("Couldn't get RSA key from AUTH cert.");
}
crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);
keysize = crypto_pk_keysize(pk);
@ -2128,7 +2275,7 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
crypto_pk_free(pk);
if (signed_len < 0) {
tor_free(signed_data);
ERR("Signature wasn't valid");
ERR("RSA signature wasn't valid");
}
if (signed_len < DIGEST256_LEN) {
tor_free(signed_data);
@ -2141,22 +2288,46 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
ERR("Signature did not match data to be signed.");
}
tor_free(signed_data);
} else {
if (chan->conn->handshake_state->certs->ed_id_sign == NULL)
ERR("We never got an Ed25519 identity certificate.");
if (chan->conn->handshake_state->certs->ed_sign_auth == NULL)
ERR("We never got an Ed25519 authentication certificate.");
const ed25519_public_key_t *authkey =
&chan->conn->handshake_state->certs->ed_sign_auth->signed_key;
ed25519_signature_t sig;
tor_assert(authlen > ED25519_SIG_LEN);
memcpy(&sig.sig, auth + authlen - ED25519_SIG_LEN, ED25519_SIG_LEN);
if (ed25519_checksig(&sig, auth, authlen - ED25519_SIG_LEN, authkey)<0) {
ERR("Ed25519 signature wasn't valid.");
}
}
/* Okay, we are authenticated. */
chan->conn->handshake_state->received_authenticate = 1;
chan->conn->handshake_state->authenticated = 1;
chan->conn->handshake_state->authenticated_rsa = 1;
chan->conn->handshake_state->digest_received_data = 0;
{
crypto_pk_t *identity_rcvd =
tor_tls_cert_get_key(chan->conn->handshake_state->id_cert);
tor_tls_cert_get_key(chan->conn->handshake_state->certs->id_cert);
const common_digests_t *id_digests =
tor_x509_cert_get_id_digests(chan->conn->handshake_state->id_cert);
tor_x509_cert_get_id_digests(chan->conn->handshake_state->certs->id_cert);
const ed25519_public_key_t *ed_identity_received = NULL;
if (! sig_is_rsa) {
chan->conn->handshake_state->authenticated_ed25519 = 1;
ed_identity_received =
&chan->conn->handshake_state->certs->ed_id_sign->signing_key;
memcpy(&chan->conn->handshake_state->authenticated_ed25519_peer_id,
ed_identity_received, sizeof(ed25519_public_key_t));
}
/* This must exist; we checked key type when reading the cert. */
tor_assert(id_digests);
memcpy(chan->conn->handshake_state->authenticated_peer_id,
memcpy(chan->conn->handshake_state->authenticated_rsa_peer_id,
id_digests->d[DIGEST_SHA1], DIGEST_LEN);
channel_set_circid_type(TLS_CHAN_TO_BASE(chan), identity_rcvd,
@ -2167,15 +2338,19 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
&(chan->conn->base_.addr),
chan->conn->base_.port,
(const char*)(chan->conn->handshake_state->
authenticated_peer_id),
authenticated_rsa_peer_id),
ed_identity_received,
0);
log_info(LD_OR,
"Got an AUTHENTICATE cell from %s:%d: Looks good.",
"Got an AUTHENTICATE cell from %s:%d, type %d: Looks good.",
safe_str(chan->conn->base_.address),
chan->conn->base_.port);
chan->conn->base_.port,
authtype);
}
var_cell_free(expected_cell);
#undef ERR
}

View File

@ -29,7 +29,8 @@ struct channel_tls_s {
#endif /* TOR_CHANNEL_INTERNAL_ */
channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
const char *id_digest);
const char *id_digest,
const ed25519_public_key_t *ed_id);
channel_listener_t * channel_tls_get_listener(void);
channel_listener_t * channel_tls_start_listener(void);
channel_t * channel_tls_handle_incoming(or_connection_t *orconn);

View File

@ -84,7 +84,10 @@ channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
{
channel_t *chan;
chan = channel_connect(addr, port, id_digest);
chan = channel_connect(addr, port, id_digest,
NULL // XXXX Ed25519 id.
);
if (chan) command_setup_channel(chan);
return chan;

View File

@ -49,9 +49,11 @@
#include "relay.h"
#include "rephist.h"
#include "router.h"
#include "routerkeys.h"
#include "routerlist.h"
#include "ext_orport.h"
#include "scheduler.h"
#include "torcert.h"
static int connection_tls_finish_handshake(or_connection_t *conn);
static int connection_or_launch_v3_or_handshake(or_connection_t *conn);
@ -143,15 +145,18 @@ connection_or_clear_identity_map(void)
/** Change conn->identity_digest to digest, and add conn into
* orconn_digest_map. */
static void
connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
connection_or_set_identity_digest(or_connection_t *conn,
const char *rsa_digest,
const ed25519_public_key_t *ed_id)
{
(void) ed_id; // DOCDOC // XXXX not implemented yet.
or_connection_t *tmp;
tor_assert(conn);
tor_assert(digest);
tor_assert(rsa_digest);
if (!orconn_identity_map)
orconn_identity_map = digestmap_new();
if (tor_memeq(conn->identity_digest, digest, DIGEST_LEN))
if (tor_memeq(conn->identity_digest, rsa_digest, DIGEST_LEN))
return;
/* If the identity was set previously, remove the old mapping. */
@ -161,23 +166,23 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
channel_clear_identity_digest(TLS_CHAN_TO_BASE(conn->chan));
}
memcpy(conn->identity_digest, digest, DIGEST_LEN);
memcpy(conn->identity_digest, rsa_digest, DIGEST_LEN);
/* If we're setting the ID to zero, don't add a mapping. */
if (tor_digest_is_zero(digest))
if (tor_digest_is_zero(rsa_digest))
return;
tmp = digestmap_set(orconn_identity_map, digest, conn);
tmp = digestmap_set(orconn_identity_map, rsa_digest, conn);
conn->next_with_same_id = tmp;
/* Deal with channels */
if (conn->chan)
channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), digest);
channel_set_identity_digest(TLS_CHAN_TO_BASE(conn->chan), rsa_digest);
#if 1
/* Testing code to check for bugs in representation. */
for (; tmp; tmp = tmp->next_with_same_id) {
tor_assert(tor_memeq(tmp->identity_digest, digest, DIGEST_LEN));
tor_assert(tor_memeq(tmp->identity_digest, rsa_digest, DIGEST_LEN));
tor_assert(tmp != conn);
}
#endif
@ -875,10 +880,12 @@ void
connection_or_init_conn_from_address(or_connection_t *conn,
const tor_addr_t *addr, uint16_t port,
const char *id_digest,
const ed25519_public_key_t *ed_id,
int started_here)
{
(void) ed_id; // not fully used yet.
const node_t *r = node_get_by_id(id_digest);
connection_or_set_identity_digest(conn, id_digest);
connection_or_set_identity_digest(conn, id_digest, ed_id);
connection_or_update_token_buckets_helper(conn, 1, get_options());
conn->base_.port = port;
@ -1171,8 +1178,11 @@ connection_or_notify_error(or_connection_t *conn,
MOCK_IMPL(or_connection_t *,
connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
const char *id_digest, channel_tls_t *chan))
const char *id_digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *chan))
{
(void) ed_id; // XXXX not fully used yet.
or_connection_t *conn;
const or_options_t *options = get_options();
int socket_error = 0;
@ -1203,7 +1213,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
*/
conn->chan = chan;
chan->conn = conn;
connection_or_init_conn_from_address(conn, &addr, port, id_digest, 1);
connection_or_init_conn_from_address(conn, &addr, port, id_digest, ed_id, 1);
connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
@ -1562,7 +1572,9 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
if (started_here)
return connection_or_client_learned_peer_id(conn,
(const uint8_t*)digest_rcvd_out);
(const uint8_t*)digest_rcvd_out,
NULL // Ed25519 ID
);
return 0;
}
@ -1592,12 +1604,16 @@ connection_or_check_valid_tls_handshake(or_connection_t *conn,
*/
int
connection_or_client_learned_peer_id(or_connection_t *conn,
const uint8_t *peer_id)
const uint8_t *rsa_peer_id,
const ed25519_public_key_t *ed_peer_id)
{
(void) ed_peer_id; // not used yet.
const or_options_t *options = get_options();
if (tor_digest_is_zero(conn->identity_digest)) {
connection_or_set_identity_digest(conn, (const char*)peer_id);
connection_or_set_identity_digest(conn,
(const char*)rsa_peer_id, ed_peer_id);
tor_free(conn->nickname);
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
conn->nickname[0] = '$';
@ -1609,14 +1625,14 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
/* if it's a bridge and we didn't know its identity fingerprint, now
* we do -- remember it for future attempts. */
learned_router_identity(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
(const char*)rsa_peer_id /*, ed_peer_id XXXX */);
}
if (tor_memneq(peer_id, conn->identity_digest, DIGEST_LEN)) {
if (tor_memneq(rsa_peer_id, conn->identity_digest, DIGEST_LEN)) {
/* I was aiming for a particular digest. I didn't get it! */
char seen[HEX_DIGEST_LEN+1];
char expected[HEX_DIGEST_LEN+1];
base16_encode(seen, sizeof(seen), (const char*)peer_id, DIGEST_LEN);
base16_encode(seen, sizeof(seen), (const char*)rsa_peer_id, DIGEST_LEN);
base16_encode(expected, sizeof(expected), conn->identity_digest,
DIGEST_LEN);
const int using_hardcoded_fingerprints =
@ -1669,7 +1685,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
}
if (authdir_mode_tests_reachability(options)) {
dirserv_orconn_tls_done(&conn->base_.addr, conn->base_.port,
(const char*)peer_id);
(const char*)rsa_peer_id /*, ed_id XXXX */);
}
return 0;
@ -1725,7 +1741,8 @@ connection_tls_finish_handshake(or_connection_t *conn)
if (tor_tls_used_v1_handshake(conn->tls)) {
conn->link_proto = 1;
connection_or_init_conn_from_address(conn, &conn->base_.addr,
conn->base_.port, digest_rcvd, 0);
conn->base_.port, digest_rcvd,
NULL, 0);
tor_tls_block_renegotiation(conn->tls);
rep_hist_note_negotiated_link_proto(1, started_here);
return connection_or_set_state_open(conn);
@ -1734,7 +1751,8 @@ connection_tls_finish_handshake(or_connection_t *conn)
if (connection_init_or_handshake_state(conn, started_here) < 0)
return -1;
connection_or_init_conn_from_address(conn, &conn->base_.addr,
conn->base_.port, digest_rcvd, 0);
conn->base_.port, digest_rcvd,
NULL, 0);
return connection_or_send_versions(conn, 0);
}
}
@ -1773,6 +1791,8 @@ connection_init_or_handshake_state(or_connection_t *conn, int started_here)
s->started_here = started_here ? 1 : 0;
s->digest_sent_data = 1;
s->digest_received_data = 1;
s->certs = or_handshake_certs_new();
s->certs->started_here = s->started_here;
return 0;
}
@ -1784,8 +1804,7 @@ or_handshake_state_free(or_handshake_state_t *state)
return;
crypto_digest_free(state->digest_sent);
crypto_digest_free(state->digest_received);
tor_x509_cert_free(state->auth_cert);
tor_x509_cert_free(state->id_cert);
or_handshake_certs_free(state->certs);
memwipe(state, 0xBE, sizeof(or_handshake_state_t));
tor_free(state);
}
@ -2132,57 +2151,171 @@ connection_or_send_netinfo,(or_connection_t *conn))
return 0;
}
/** Helper used to add an encoded certs to a cert cell */
static void
add_certs_cell_cert_helper(certs_cell_t *certs_cell,
uint8_t cert_type,
const uint8_t *cert_encoded,
size_t cert_len)
{
tor_assert(cert_len <= UINT16_MAX);
certs_cell_cert_t *ccc = certs_cell_cert_new();
ccc->cert_type = cert_type;
ccc->cert_len = cert_len;
certs_cell_cert_setlen_body(ccc, cert_len);
memcpy(certs_cell_cert_getarray_body(ccc), cert_encoded, cert_len);
certs_cell_add_certs(certs_cell, ccc);
}
/** Add an encoded X509 cert (stored as <b>cert_len</b> bytes at
* <b>cert_encoded</b>) to the trunnel certs_cell_t object that we are
* building in <b>certs_cell</b>. Set its type field to <b>cert_type</b>. */
static void
add_x509_cert(certs_cell_t *certs_cell,
uint8_t cert_type,
const tor_x509_cert_t *cert)
{
if (NULL == cert)
return;
const uint8_t *cert_encoded = NULL;
size_t cert_len;
tor_x509_cert_get_der(cert, &cert_encoded, &cert_len);
add_certs_cell_cert_helper(certs_cell, cert_type, cert_encoded, cert_len);
}
/** Add an Ed25519 cert from <b>cert</b> to the trunnel certs_cell_t object
* that we are building in <b>certs_cell</b>. Set its type field to
* <b>cert_type</b>. */
static void
add_ed25519_cert(certs_cell_t *certs_cell,
uint8_t cert_type,
const tor_cert_t *cert)
{
if (NULL == cert)
return;
add_certs_cell_cert_helper(certs_cell, cert_type,
cert->encoded, cert->encoded_len);
}
/** Send a CERTS cell on the connection <b>conn</b>. Return 0 on success, -1
* on failure. */
int
connection_or_send_certs_cell(or_connection_t *conn)
{
const tor_x509_cert_t *link_cert = NULL, *id_cert = NULL;
const uint8_t *link_encoded = NULL, *id_encoded = NULL;
size_t link_len, id_len;
var_cell_t *cell;
size_t cell_len;
ssize_t pos;
certs_cell_t *certs_cell = NULL;
tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
if (! conn->handshake_state)
return -1;
const int conn_in_server_mode = ! conn->handshake_state->started_here;
/* Get the encoded values of the X509 certificates */
if (tor_tls_get_my_certs(conn_in_server_mode, &link_cert, &id_cert) < 0)
return -1;
tor_x509_cert_get_der(link_cert, &link_encoded, &link_len);
tor_x509_cert_get_der(id_cert, &id_encoded, &id_len);
cell_len = 1 /* 1 byte: num certs in cell */ +
2 * ( 1 + 2 ) /* For each cert: 1 byte for type, 2 for length */ +
link_len + id_len;
cell = var_cell_new(cell_len);
tor_assert(link_cert);
tor_assert(id_cert);
certs_cell = certs_cell_new();
/* Start adding certs. First the link cert or auth1024 cert. */
if (conn_in_server_mode) {
add_x509_cert(certs_cell,
OR_CERT_TYPE_TLS_LINK, link_cert);
} else {
add_x509_cert(certs_cell,
OR_CERT_TYPE_AUTH_1024, link_cert);
}
/* Next the RSA->RSA ID cert */
add_x509_cert(certs_cell,
OR_CERT_TYPE_ID_1024, id_cert);
/* Next the Ed25519 certs */
add_ed25519_cert(certs_cell,
CERTTYPE_ED_ID_SIGN,
get_master_signing_key_cert());
if (conn_in_server_mode) {
add_ed25519_cert(certs_cell,
CERTTYPE_ED_SIGN_LINK,
get_current_link_cert_cert());
} else {
add_ed25519_cert(certs_cell,
CERTTYPE_ED_SIGN_AUTH,
get_current_auth_key_cert());
}
/* And finally the crosscert. */
{
const uint8_t *crosscert=NULL;
size_t crosscert_len;
get_master_rsa_crosscert(&crosscert, &crosscert_len);
if (crosscert) {
add_certs_cell_cert_helper(certs_cell,
CERTTYPE_RSA1024_ID_EDID,
crosscert, crosscert_len);
}
}
/* We've added all the certs; make the cell. */
certs_cell->n_certs = certs_cell_getlen_certs(certs_cell);
ssize_t alloc_len = certs_cell_encoded_len(certs_cell);
tor_assert(alloc_len >= 0 && alloc_len <= UINT16_MAX);
cell = var_cell_new(alloc_len);
cell->command = CELL_CERTS;
cell->payload[0] = 2;
pos = 1;
if (conn_in_server_mode)
cell->payload[pos] = OR_CERT_TYPE_TLS_LINK; /* Link cert */
else
cell->payload[pos] = OR_CERT_TYPE_AUTH_1024; /* client authentication */
set_uint16(&cell->payload[pos+1], htons(link_len));
memcpy(&cell->payload[pos+3], link_encoded, link_len);
pos += 3 + link_len;
cell->payload[pos] = OR_CERT_TYPE_ID_1024; /* ID cert */
set_uint16(&cell->payload[pos+1], htons(id_len));
memcpy(&cell->payload[pos+3], id_encoded, id_len);
pos += 3 + id_len;
tor_assert(pos == (int)cell_len); /* Otherwise we just smashed the heap */
ssize_t enc_len = certs_cell_encode(cell->payload, alloc_len, certs_cell);
tor_assert(enc_len > 0 && enc_len <= alloc_len);
cell->payload_len = enc_len;
connection_or_write_var_cell_to_buf(cell, conn);
var_cell_free(cell);
certs_cell_free(certs_cell);
return 0;
}
/** Return true iff <b>challenge_type</b> is an AUTHCHALLENGE type that
* we can send and receive. */
int
authchallenge_type_is_supported(uint16_t challenge_type)
{
switch (challenge_type) {
case AUTHTYPE_RSA_SHA256_TLSSECRET:
case AUTHTYPE_ED25519_SHA256_RFC5705:
return 1;
case AUTHTYPE_RSA_SHA256_RFC5705:
default:
return 0;
}
}
/** Return true iff <b>challenge_type_a</b> is one that we would rather
* use than <b>challenge_type_b</b>. */
int
authchallenge_type_is_better(uint16_t challenge_type_a,
uint16_t challenge_type_b)
{
/* Any supported type is better than an unsupported one;
* all unsupported types are equally bad. */
if (!authchallenge_type_is_supported(challenge_type_a))
return 0;
if (!authchallenge_type_is_supported(challenge_type_b))
return 1;
/* It happens that types are superior in numerically ascending order.
* If that ever changes, this must change too. */
return (challenge_type_a > challenge_type_b);
}
/** Send an AUTH_CHALLENGE cell on the connection <b>conn</b>. Return 0
* on success, -1 on failure. */
int
@ -2197,17 +2330,26 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn)
auth_challenge_cell_t *ac = auth_challenge_cell_new();
tor_assert(sizeof(ac->challenge) == 32);
crypto_rand((char*)ac->challenge, sizeof(ac->challenge));
auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
/* Disabled, because everything that supports this method also supports
* the much-superior ED25519_SHA256_RFC5705 */
/* auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_RFC5705); */
auth_challenge_cell_add_methods(ac, AUTHTYPE_ED25519_SHA256_RFC5705);
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)
if (len != cell->payload_len) {
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Encoded auth challenge cell length not as expected");
goto done;
/* LCOV_EXCL_STOP */
}
cell->command = CELL_AUTH_CHALLENGE;
connection_or_write_var_cell_to_buf(cell, conn);
@ -2221,8 +2363,8 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn)
}
/** Compute the main body of an AUTHENTICATE cell that a client can use
* to authenticate itself on a v3 handshake for <b>conn</b>. Write it to the
* <b>outlen</b>-byte buffer at <b>out</b>.
* to authenticate itself on a v3 handshake for <b>conn</b>. Return it
* in a var_cell_t.
*
* If <b>server</b> is true, only calculate the first
* V3_AUTH_FIXED_PART_LEN bytes -- the part of the authenticator that's
@ -2238,24 +2380,44 @@ connection_or_send_auth_challenge_cell(or_connection_t *conn)
*
* Return the length of the cell body on success, and -1 on failure.
*/
int
var_cell_t *
connection_or_compute_authenticate_cell_body(or_connection_t *conn,
uint8_t *out, size_t outlen,
const int authtype,
crypto_pk_t *signing_key,
int server)
const ed25519_keypair_t *ed_signing_key,
int server)
{
auth1_t *auth = NULL;
auth_ctx_t *ctx = auth_ctx_new();
int result;
var_cell_t *result = NULL;
int old_tlssecrets_algorithm = 0;
const char *authtype_str = NULL;
int is_ed = 0;
/* assert state is reasonable XXXX */
ctx->is_ed = 0;
switch (authtype) {
case AUTHTYPE_RSA_SHA256_TLSSECRET:
authtype_str = "AUTH0001";
old_tlssecrets_algorithm = 1;
break;
case AUTHTYPE_RSA_SHA256_RFC5705:
authtype_str = "AUTH0002";
break;
case AUTHTYPE_ED25519_SHA256_RFC5705:
authtype_str = "AUTH0003";
is_ed = 1;
break;
default:
tor_assert(0);
break;
}
auth = auth1_new();
ctx->is_ed = is_ed;
/* Type: 8 bytes. */
memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
memcpy(auth1_getarray_type(auth), authtype_str, 8);
{
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
@ -2265,7 +2427,7 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
goto err;
my_digests = tor_x509_cert_get_id_digests(id_cert);
their_digests =
tor_x509_cert_get_id_digests(conn->handshake_state->id_cert);
tor_x509_cert_get_id_digests(conn->handshake_state->certs->id_cert);
tor_assert(my_digests);
tor_assert(their_digests);
my_id = (uint8_t*)my_digests->d[DIGEST_SHA256];
@ -2281,6 +2443,22 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
memcpy(auth->sid, server_id, 32);
}
if (is_ed) {
const ed25519_public_key_t *my_ed_id, *their_ed_id;
if (!conn->handshake_state->certs->ed_id_sign) {
log_warn(LD_OR, "Ed authenticate without Ed ID cert from peer.");
goto err;
}
my_ed_id = get_master_identity_key();
their_ed_id = &conn->handshake_state->certs->ed_id_sign->signing_key;
const uint8_t *cid_ed = (server ? their_ed_id : my_ed_id)->pubkey;
const uint8_t *sid_ed = (server ? my_ed_id : their_ed_id)->pubkey;
memcpy(auth->u1_cid_ed, cid_ed, ED25519_PUBKEY_LEN);
memcpy(auth->u1_sid_ed, sid_ed, ED25519_PUBKEY_LEN);
}
{
crypto_digest_t *server_d, *client_d;
if (server) {
@ -2309,7 +2487,8 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
cert = freecert;
}
if (!cert) {
log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
log_warn(LD_OR, "Unable to find cert when making %s data.",
authtype_str);
goto err;
}
@ -2321,36 +2500,79 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
}
/* HMAC of clientrandom and serverrandom using master key : 32 octets */
tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
if (old_tlssecrets_algorithm) {
tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
} else {
char label[128];
tor_snprintf(label, sizeof(label),
"EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
tor_tls_export_key_material(conn->tls, auth->tlssecrets,
auth->cid, sizeof(auth->cid),
label);
}
/* 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*)auth->rand, 24);
ssize_t maxlen = auth1_encoded_len(auth, ctx);
if (ed_signing_key && is_ed) {
maxlen += ED25519_SIG_LEN;
} else if (signing_key && !is_ed) {
maxlen += crypto_pk_keysize(signing_key);
}
const int AUTH_CELL_HEADER_LEN = 4; /* 2 bytes of type, 2 bytes of length */
result = var_cell_new(AUTH_CELL_HEADER_LEN + maxlen);
uint8_t *const out = result->payload + AUTH_CELL_HEADER_LEN;
const size_t outlen = maxlen;
ssize_t len;
result->command = CELL_AUTHENTICATE;
set_uint16(result->payload, htons(authtype));
if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
log_warn(LD_OR, "Unable to encode signed part of AUTH1 data.");
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Unable to encode signed part of AUTH1 data.");
goto err;
/* LCOV_EXCL_STOP */
}
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.");
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Unable to parse signed part of AUTH1 data that we just "
"encoded");
goto err;
/* LCOV_EXCL_STOP */
}
result = (int) (tmp->end_of_fixed_part - out);
result->payload_len = (tmp->end_of_signed - result->payload);
auth1_free(tmp);
if (len2 != len) {
log_warn(LD_OR, "Mismatched length when re-parsing AUTH1 data.");
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Mismatched length when re-parsing AUTH1 data.");
goto err;
/* LCOV_EXCL_STOP */
}
goto done;
}
if (signing_key) {
if (ed_signing_key && is_ed) {
ed25519_signature_t sig;
if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Unable to sign ed25519 authentication data");
goto err;
/* LCOV_EXCL_STOP */
}
auth1_setlen_sig(auth, ED25519_SIG_LEN);
memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
} else if (signing_key && !is_ed) {
auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
char d[32];
@ -2365,18 +2587,24 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
}
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;
len = auth1_encode(out, outlen, auth, ctx);
if (len < 0) {
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Unable to encode signed AUTH1 data.");
goto err;
/* LCOV_EXCL_STOP */
}
tor_assert(len + AUTH_CELL_HEADER_LEN <= result->payload_len);
result->payload_len = len + AUTH_CELL_HEADER_LEN;
set_uint16(result->payload+2, htons(len));
goto done;
err:
result = -1;
var_cell_free(result);
result = NULL;
done:
auth1_free(auth);
auth_ctx_free(ctx);
@ -2390,44 +2618,29 @@ connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype))
{
var_cell_t *cell;
crypto_pk_t *pk = tor_tls_get_my_client_auth_key();
int authlen;
size_t cell_maxlen;
/* XXXX make sure we're actually supposed to send this! */
if (!pk) {
log_warn(LD_BUG, "Can't compute authenticate cell: no client auth key");
return -1;
}
if (authtype != AUTHTYPE_RSA_SHA256_TLSSECRET) {
if (! authchallenge_type_is_supported(authtype)) {
log_warn(LD_BUG, "Tried to send authenticate cell with unknown "
"authentication type %d", authtype);
return -1;
}
cell_maxlen = 4 + /* overhead */
V3_AUTH_BODY_LEN + /* Authentication body */
crypto_pk_keysize(pk) + /* Max signature length */
16 /* add a few extra bytes just in case. */;
cell = var_cell_new(cell_maxlen);
cell->command = CELL_AUTHENTICATE;
set_uint16(cell->payload, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
/* skip over length ; we don't know that yet. */
authlen = connection_or_compute_authenticate_cell_body(conn,
cell->payload+4,
cell_maxlen-4,
pk,
0 /* not server */);
if (authlen < 0) {
cell = connection_or_compute_authenticate_cell_body(conn,
authtype,
pk,
get_current_auth_keypair(),
0 /* not server */);
if (! cell) {
/* LCOV_EXCL_START */
log_warn(LD_BUG, "Unable to compute authenticate cell!");
var_cell_free(cell);
return -1;
/* LCOV_EXCL_STOP */
}
tor_assert(authlen + 4 <= cell->payload_len);
set_uint16(cell->payload+2, htons(authlen));
cell->payload_len = authlen + 4;
connection_or_write_var_cell_to_buf(cell, conn);
var_cell_free(cell);

View File

@ -40,7 +40,9 @@ void connection_or_notify_error(or_connection_t *conn,
MOCK_DECL(or_connection_t *,
connection_or_connect,
(const tor_addr_t *addr, uint16_t port,
const char *id_digest, channel_tls_t *chan));
const char *id_digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *chan));
void connection_or_close_normally(or_connection_t *orconn, int flush);
MOCK_DECL(void,connection_or_close_for_error,
@ -59,10 +61,12 @@ int connection_init_or_handshake_state(or_connection_t *conn,
void connection_or_init_conn_from_address(or_connection_t *conn,
const tor_addr_t *addr,
uint16_t port,
const char *id_digest,
const char *rsa_id_digest,
const ed25519_public_key_t *ed_id,
int started_here);
int connection_or_client_learned_peer_id(or_connection_t *conn,
const uint8_t *peer_id);
const uint8_t *rsa_peer_id,
const ed25519_public_key_t *ed_peer_id);
time_t connection_or_client_used(or_connection_t *conn);
MOCK_DECL(int, connection_or_get_num_circuits, (or_connection_t *conn));
void or_handshake_state_free(or_handshake_state_t *state);
@ -84,10 +88,14 @@ int connection_or_send_versions(or_connection_t *conn, int v3_plus);
MOCK_DECL(int,connection_or_send_netinfo,(or_connection_t *conn));
int connection_or_send_certs_cell(or_connection_t *conn);
int connection_or_send_auth_challenge_cell(or_connection_t *conn);
int connection_or_compute_authenticate_cell_body(or_connection_t *conn,
uint8_t *out, size_t outlen,
crypto_pk_t *signing_key,
int server);
int authchallenge_type_is_supported(uint16_t challenge_type);
int authchallenge_type_is_better(uint16_t challenge_type_a,
uint16_t challenge_type_b);
var_cell_t *connection_or_compute_authenticate_cell_body(or_connection_t *conn,
const int authtype,
crypto_pk_t *signing_key,
const ed25519_keypair_t *ed_signing_key,
int server);
MOCK_DECL(int,connection_or_send_authenticate_cell,
(or_connection_t *conn, int type));

View File

@ -3253,7 +3253,9 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
router->nickname, fmt_addr32(router->addr), router->or_port);
tor_addr_from_ipv4h(&router_addr, router->addr);
chan = channel_tls_connect(&router_addr, router->or_port,
router->cache_info.identity_digest);
router->cache_info.identity_digest,
NULL // XXXX Ed25519 ID.
);
if (chan) command_setup_channel(chan);
/* Possible IPv6. */
@ -3265,7 +3267,9 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1),
router->ipv6_orport);
chan = channel_tls_connect(&router->ipv6_addr, router->ipv6_orport,
router->cache_info.identity_digest);
router->cache_info.identity_digest,
NULL // XXXX Ed25519 ID.
);
if (chan) command_setup_channel(chan);
}
}

View File

@ -1348,13 +1348,34 @@ typedef struct listener_connection_t {
#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7
/**@}*/
/** The one currently supported type of AUTHENTICATE cell. It contains
/** The first supported type of AUTHENTICATE cell. It contains
* a bunch of structures signed with an RSA1024 key. The signed
* structures include a HMAC using negotiated TLS secrets, and a digest
* of all cells sent or received before the AUTHENTICATE cell (including
* the random server-generated AUTH_CHALLENGE cell).
*/
#define AUTHTYPE_RSA_SHA256_TLSSECRET 1
/** As AUTHTYPE_RSA_SHA256_TLSSECRET, but instead of using the
* negotiated TLS secrets, uses exported keying material from the TLS
* session as described in RFC 5705.
*
* Not used by today's tors, since everything that supports this
* also supports ED25519_SHA3_5705, which is better.
**/
#define AUTHTYPE_RSA_SHA256_RFC5705 2
/** As AUTHTYPE_RSA_SHA256_RFC5705, but uses an Ed25519 identity key to
* authenticate. */
#define AUTHTYPE_ED25519_SHA256_RFC5705 3
/*
* NOTE: authchallenge_type_is_better() relies on these AUTHTYPE codes
* being sorted in order of preference. If we someday add one with
* a higher numerical value that we don't like as much, we should revise
* authchallenge_type_is_better().
*/
/** The length of the part of the AUTHENTICATE cell body that the client and
* server can generate independently (when using RSA_SHA256_TLSSECRET). It
@ -1365,6 +1386,34 @@ typedef struct listener_connection_t {
* signs. */
#define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16)
/** Structure to hold all the certificates we've received on an OR connection
*/
typedef struct or_handshake_certs_t {
/** True iff we originated this connection. */
int started_here;
/** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE
* cell. Signed with the RSA identity key. */
tor_x509_cert_t *auth_cert;
/** The cert for the 'link' RSA key that was used to negotiate the TLS
* connection. Signed with the RSA identity key. */
tor_x509_cert_t *link_cert;
/** A self-signed identity certificate: the RSA identity key signed
* with itself. */
tor_x509_cert_t *id_cert;
/** The Ed25519 signing key, signed with the Ed25519 identity key. */
struct tor_cert_st *ed_id_sign;
/** A digest of the X509 link certificate for the TLS connection, signed
* with the Ed25519 siging key. */
struct tor_cert_st *ed_sign_link;
/** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE
* cell) , signed with the Ed25519 siging key. */
struct tor_cert_st *ed_sign_auth;
/** The Ed25519 identity key, crosssigned with the RSA identity key. */
uint8_t *ed_rsa_crosscert;
/** The length of <b>ed_rsa_crosscert</b> in bytes */
size_t ed_rsa_crosscert_len;
} or_handshake_certs_t;
/** Stores flags and information related to the portion of a v2/v3 Tor OR
* connection handshake that happens after the TLS handshake is finished.
*/
@ -1385,6 +1434,8 @@ typedef struct or_handshake_state_t {
/* True iff we've received valid authentication to some identity. */
unsigned int authenticated : 1;
unsigned int authenticated_rsa : 1;
unsigned int authenticated_ed25519 : 1;
/* True iff we have sent a netinfo cell */
unsigned int sent_netinfo : 1;
@ -1402,9 +1453,12 @@ typedef struct or_handshake_state_t {
unsigned int digest_received_data : 1;
/**@}*/
/** Identity digest that we have received and authenticated for our peer
/** Identity RSA digest that we have received and authenticated for our peer
* on this connection. */
uint8_t authenticated_peer_id[DIGEST_LEN];
uint8_t authenticated_rsa_peer_id[DIGEST_LEN];
/** Identity Ed25519 public key that we have received and authenticated for
* our peer on this connection. */
ed25519_public_key_t authenticated_ed25519_peer_id;
/** Digests of the cells that we have sent or received as part of a V3
* handshake. Used for making and checking AUTHENTICATE cells.
@ -1417,14 +1471,8 @@ typedef struct or_handshake_state_t {
/** Certificates that a connection initiator sent us in a CERTS cell; we're
* holding on to them until we get an AUTHENTICATE cell.
*
* @{
*/
/** The cert for the key that's supposed to sign the AUTHENTICATE cell */
tor_x509_cert_t *auth_cert;
/** A self-signed identity certificate */
tor_x509_cert_t *id_cert;
/**@}*/
or_handshake_certs_t *certs;
} or_handshake_state_t;
/** Length of Extended ORPort connection identifier. */

View File

@ -24,6 +24,7 @@
#define ENC_KEY_HEADER "Boxed Ed25519 key"
#define ENC_KEY_TAG "master"
/* DOCDOC */
static ssize_t
do_getpass(const char *prompt, char *buf, size_t buflen,
int twice, const or_options_t *options)
@ -90,6 +91,7 @@ do_getpass(const char *prompt, char *buf, size_t buflen,
return length;
}
/* DOCDOC */
int
read_encrypted_secret_key(ed25519_secret_key_t *out,
const char *fname)
@ -162,6 +164,7 @@ read_encrypted_secret_key(ed25519_secret_key_t *out,
return r;
}
/* DOCDOC */
int
write_encrypted_secret_key(const ed25519_secret_key_t *key,
const char *fname)
@ -205,6 +208,7 @@ write_encrypted_secret_key(const ed25519_secret_key_t *key,
return r;
}
/* DOCDOC */
static int
write_secret_key(const ed25519_secret_key_t *key, int encrypted,
const char *fname,
@ -932,7 +936,18 @@ load_ed_keys(const or_options_t *options, time_t now)
return -1;
}
/* DOCDOC */
/**
* Retrieve our currently-in-use Ed25519 link certificate and id certificate,
* and, if they would expire soon (based on the time <b>now</b>, generate new
* certificates (without embedding the public part of the signing key inside).
*
* The signed_key from the expiring certificate will be used to sign the new
* key within newly generated X509 certificate.
*
* Returns -1 upon error. Otherwise, returns 0 upon success (either when the
* current certificate is still valid, or when a new certificate was
* successfully generated).
*/
int
generate_ed_link_cert(const or_options_t *options, time_t now)
{
@ -972,6 +987,17 @@ generate_ed_link_cert(const or_options_t *options, time_t now)
#undef SET_KEY
#undef SET_CERT
/**
* Return 1 if any of the following are true:
*
* - if one of our Ed25519 signing, auth, or link certificates would expire
* soon w.r.t. the time <b>now</b>,
* - if we do not currently have a link certificate, or
* - if our cached Ed25519 link certificate is not same as the one we're
* currently using.
*
* Otherwise, returns 0.
*/
int
should_make_new_ed_keys(const or_options_t *options, const time_t now)
{
@ -1002,6 +1028,60 @@ should_make_new_ed_keys(const or_options_t *options, const time_t now)
#undef EXPIRES_SOON
#ifdef TOR_UNIT_TESTS
/* Helper for unit tests: populate the ed25519 keys without saving or loading */
void
init_mock_ed_keys(const crypto_pk_t *rsa_identity_key)
{
routerkeys_free_all();
#define MAKEKEY(k) \
k = tor_malloc_zero(sizeof(*k)); \
if (ed25519_keypair_generate(k, 0) < 0) { \
log_warn(LD_BUG, "Couldn't make a keypair"); \
goto err; \
}
MAKEKEY(master_identity_key);
MAKEKEY(master_signing_key);
MAKEKEY(current_auth_key);
#define MAKECERT(cert, signing, signed_, type, flags) \
cert = tor_cert_create(signing, \
type, \
&signed_->pubkey, \
time(NULL), 86400, \
flags); \
if (!cert) { \
log_warn(LD_BUG, "Couldn't make a %s certificate!", #cert); \
goto err; \
}
MAKECERT(signing_key_cert,
master_identity_key, master_signing_key, CERT_TYPE_ID_SIGNING,
CERT_FLAG_INCLUDE_SIGNING_KEY);
MAKECERT(auth_key_cert,
master_signing_key, current_auth_key, CERT_TYPE_SIGNING_AUTH, 0);
if (generate_ed_link_cert(get_options(), time(NULL)) < 0) {
log_warn(LD_BUG, "Couldn't make link certificate");
goto err;
}
rsa_ed_crosscert_len = tor_make_rsa_ed25519_crosscert(
&master_identity_key->pubkey,
rsa_identity_key,
time(NULL)+86400,
&rsa_ed_crosscert);
return;
err:
routerkeys_free_all();
tor_assert_nonfatal_unreached();
}
#undef MAKEKEY
#undef MAKECERT
#endif
const ed25519_public_key_t *
get_master_identity_key(void)
{
@ -1010,6 +1090,16 @@ get_master_identity_key(void)
return &master_identity_key->pubkey;
}
#ifdef TOR_UNIT_TESTS
/* only exists for the unit tests, since otherwise the identity key
* should be used to sign nothing but the signing key. */
const ed25519_keypair_t *
get_master_identity_keypair(void)
{
return master_identity_key;
}
#endif
const ed25519_keypair_t *
get_master_signing_keypair(void)
{
@ -1144,9 +1234,12 @@ routerkeys_free_all(void)
tor_cert_free(signing_key_cert);
tor_cert_free(link_cert_cert);
tor_cert_free(auth_key_cert);
tor_free(rsa_ed_crosscert);
master_identity_key = master_signing_key = NULL;
current_auth_key = NULL;
signing_key_cert = link_cert_cert = auth_key_cert = NULL;
rsa_ed_crosscert = NULL; // redundant
rsa_ed_crosscert_len = 0;
}

View File

@ -73,5 +73,10 @@ int write_encrypted_secret_key(const ed25519_secret_key_t *out,
void routerkeys_free_all(void);
#ifdef TOR_UNIT_TESTS
const ed25519_keypair_t *get_master_identity_keypair(void);
void init_mock_ed_keys(const crypto_pk_t *rsa_identity_key);
#endif
#endif

View File

@ -2100,12 +2100,13 @@ router_parse_entry_from_string(const char *s, const char *end,
ed25519_checkable_t check[3];
int check_ok[3];
if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
time_t expires = TIME_MAX;
if (tor_cert_get_checkable_sig(&check[0], cert, NULL, &expires) < 0) {
log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
goto err;
}
if (tor_cert_get_checkable_sig(&check[1],
ntor_cc_cert, &ntor_cc_pk) < 0) {
ntor_cc_cert, &ntor_cc_pk, &expires) < 0) {
log_err(LD_BUG, "Couldn't create 'checkable' for ntor_cc_cert.");
goto err;
}
@ -2135,10 +2136,7 @@ router_parse_entry_from_string(const char *s, const char *end,
}
/* We check this before adding it to the routerlist. */
if (cert->valid_until < ntor_cc_cert->valid_until)
router->cert_expiration_time = cert->valid_until;
else
router->cert_expiration_time = ntor_cc_cert->valid_until;
router->cert_expiration_time = expires;
}
}
@ -2452,7 +2450,7 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
ed25519_checkable_t check[2];
int check_ok[2];
if (tor_cert_get_checkable_sig(&check[0], cert, NULL) < 0) {
if (tor_cert_get_checkable_sig(&check[0], cert, NULL, NULL) < 0) {
log_err(LD_BUG, "Couldn't create 'checkable' for cert.");
goto err;
}

View File

@ -25,6 +25,8 @@
* that one is authority_cert_t, and it's mostly handled in routerlist.c.
*/
#include "or.h"
#include "config.h"
#include "crypto.h"
#include "torcert.h"
#include "ed25519_cert.h"
@ -154,7 +156,11 @@ tor_cert_parse(const uint8_t *encoded, const size_t len)
cert->encoded_len = len;
memcpy(cert->signed_key.pubkey, parsed->certified_key, 32);
cert->valid_until = parsed->exp_field * 3600;
const int64_t valid_until_64 = ((int64_t)parsed->exp_field) * 3600;
if (valid_until_64 > TIME_MAX)
cert->valid_until = TIME_MAX - 1;
else
cert->valid_until = (time_t) valid_until_64;
cert->cert_type = parsed->cert_type;
for (unsigned i = 0; i < ed25519_cert_getlen_ext(parsed); ++i) {
@ -181,11 +187,17 @@ tor_cert_parse(const uint8_t *encoded, const size_t len)
}
/** Fill in <b>checkable_out</b> with the information needed to check
* the signature on <b>cert</b> with <b>pubkey</b>. */
* the signature on <b>cert</b> with <b>pubkey</b>.
*
* On success, if <b>expiration_out</b> is provided, and it is some time
* _after_ the expiration time of this certificate, set it to the
* expiration time of this certificate.
*/
int
tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
const tor_cert_t *cert,
const ed25519_public_key_t *pubkey)
const ed25519_public_key_t *pubkey,
time_t *expiration_out)
{
if (! pubkey) {
if (cert->signing_key_included)
@ -202,6 +214,10 @@ tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
memcpy(checkable_out->signature.sig,
cert->encoded + signed_len, ED25519_SIG_LEN);
if (expiration_out) {
*expiration_out = MIN(*expiration_out, cert->valid_until);
}
return 0;
}
@ -216,15 +232,16 @@ tor_cert_checksig(tor_cert_t *cert,
{
ed25519_checkable_t checkable;
int okay;
time_t expires = TIME_MAX;
if (now && now > cert->valid_until) {
if (tor_cert_get_checkable_sig(&checkable, cert, pubkey, &expires) < 0)
return -1;
if (now && now > expires) {
cert->cert_expired = 1;
return -1;
}
if (tor_cert_get_checkable_sig(&checkable, cert, pubkey) < 0)
return -1;
if (ed25519_checksig_batch(&okay, &checkable, 1) < 0) {
cert->sig_bad = 1;
return -1;
@ -272,6 +289,8 @@ tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2)
return tor_cert_eq(cert1, cert2);
}
#define RSA_ED_CROSSCERT_PREFIX "Tor TLS RSA/Ed25519 cross-certificate"
/** Create new cross-certification object to certify <b>ed_key</b> as the
* master ed25519 identity key for the RSA identity key <b>rsa_key</b>.
* Allocates and stores the encoded certificate in *<b>cert</b>, and returns
@ -296,11 +315,21 @@ tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key,
ssize_t sz = rsa_ed_crosscert_encode(res, alloc_sz, cc);
tor_assert(sz > 0 && sz <= alloc_sz);
crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
crypto_digest_add_bytes(d, RSA_ED_CROSSCERT_PREFIX,
strlen(RSA_ED_CROSSCERT_PREFIX));
const int signed_part_len = 32 + 4;
crypto_digest_add_bytes(d, (char*)res, signed_part_len);
uint8_t digest[DIGEST256_LEN];
crypto_digest_get_digest(d, (char*)digest, sizeof(digest));
crypto_digest_free(d);
int siglen = crypto_pk_private_sign(rsa_key,
(char*)rsa_ed_crosscert_getarray_sig(cc),
rsa_ed_crosscert_getlen_sig(cc),
(char*)res, signed_part_len);
(char*)digest, sizeof(digest));
tor_assert(siglen > 0 && siglen <= (int)crypto_pk_keysize(rsa_key));
tor_assert(siglen <= UINT8_MAX);
cc->sig_len = siglen;
@ -312,3 +341,310 @@ tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key,
return sz;
}
/**
* Check whether the <b>crosscert_len</b> byte certificate in <b>crosscert</b>
* is in fact a correct cross-certification of <b>master_key</b> using
* the RSA key <b>rsa_id_key</b>.
*
* Also reject the certificate if it expired before
* <b>reject_if_expired_before</b>.
*
* Return 0 on success, negative on failure.
*/
int
rsa_ed25519_crosscert_check(const uint8_t *crosscert,
const size_t crosscert_len,
const crypto_pk_t *rsa_id_key,
const ed25519_public_key_t *master_key,
const time_t reject_if_expired_before)
{
rsa_ed_crosscert_t *cc = NULL;
int rv;
#define ERR(code, s) \
do { \
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \
"Received a bad RSA->Ed25519 crosscert: %s", \
(s)); \
rv = (code); \
goto err; \
} while (0)
if (BUG(crypto_pk_keysize(rsa_id_key) > PK_BYTES))
return -1;
if (BUG(!crosscert))
return -1;
ssize_t parsed_len = rsa_ed_crosscert_parse(&cc, crosscert, crosscert_len);
if (parsed_len < 0 || crosscert_len != (size_t)parsed_len) {
ERR(-2, "Unparseable or overlong crosscert");
}
if (tor_memneq(rsa_ed_crosscert_getarray_ed_key(cc),
master_key->pubkey,
ED25519_PUBKEY_LEN)) {
ERR(-3, "Crosscert did not match Ed25519 key");
}
const uint32_t expiration_date = rsa_ed_crosscert_get_expiration(cc);
const uint64_t expiration_time = expiration_date * 3600;
if (reject_if_expired_before < 0 ||
expiration_time < (uint64_t)reject_if_expired_before) {
ERR(-4, "Crosscert is expired");
}
const uint8_t *eos = rsa_ed_crosscert_get_end_of_signed(cc);
const uint8_t *sig = rsa_ed_crosscert_getarray_sig(cc);
const uint8_t siglen = rsa_ed_crosscert_get_sig_len(cc);
tor_assert(eos >= crosscert);
tor_assert((size_t)(eos - crosscert) <= crosscert_len);
tor_assert(siglen == rsa_ed_crosscert_getlen_sig(cc));
/* Compute the digest */
uint8_t digest[DIGEST256_LEN];
crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256);
crypto_digest_add_bytes(d, RSA_ED_CROSSCERT_PREFIX,
strlen(RSA_ED_CROSSCERT_PREFIX));
crypto_digest_add_bytes(d, (char*)crosscert, eos-crosscert);
crypto_digest_get_digest(d, (char*)digest, sizeof(digest));
crypto_digest_free(d);
/* Now check the signature */
uint8_t signed_[PK_BYTES];
int signed_len = crypto_pk_public_checksig(rsa_id_key,
(char*)signed_, sizeof(signed_),
(char*)sig, siglen);
if (signed_len < DIGEST256_LEN) {
ERR(-5, "Bad signature, or length of signed data not as expected");
}
if (tor_memneq(digest, signed_, DIGEST256_LEN)) {
ERR(-6, "The signature was good, but it didn't match the data");
}
rv = 0;
err:
rsa_ed_crosscert_free(cc);
return rv;
}
/** Construct and return a new empty or_handshake_certs object */
or_handshake_certs_t *
or_handshake_certs_new(void)
{
return tor_malloc_zero(sizeof(or_handshake_certs_t));
}
/** Release all storage held in <b>certs</b> */
void
or_handshake_certs_free(or_handshake_certs_t *certs)
{
if (!certs)
return;
tor_x509_cert_free(certs->auth_cert);
tor_x509_cert_free(certs->link_cert);
tor_x509_cert_free(certs->id_cert);
tor_cert_free(certs->ed_id_sign);
tor_cert_free(certs->ed_sign_link);
tor_cert_free(certs->ed_sign_auth);
tor_free(certs->ed_rsa_crosscert);
memwipe(certs, 0xBD, sizeof(*certs));
tor_free(certs);
}
#undef ERR
#define ERR(s) \
do { \
log_fn(severity, LD_PROTOCOL, \
"Received a bad CERTS cell: %s", \
(s)); \
return 0; \
} while (0)
int
or_handshake_certs_rsa_ok(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now)
{
tor_x509_cert_t *link_cert = certs->link_cert;
tor_x509_cert_t *auth_cert = certs->auth_cert;
tor_x509_cert_t *id_cert = certs->id_cert;
if (certs->started_here) {
if (! (id_cert && link_cert))
ERR("The certs we wanted (ID, Link) were missing");
if (! tor_tls_cert_matches_key(tls, link_cert))
ERR("The link certificate didn't match the TLS public key");
if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, now, 0))
ERR("The link certificate was not valid");
if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, now, 1))
ERR("The ID certificate was not valid");
} else {
if (! (id_cert && auth_cert))
ERR("The certs we wanted (ID, Auth) were missing");
if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, now, 1))
ERR("The authentication certificate was not valid");
if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, now, 1))
ERR("The ID certificate was not valid");
}
return 1;
}
/** Check all the ed25519 certificates in <b>certs</b> against each other, and
* against the peer certificate in <b>tls</b> if appropriate. On success,
* return 0; on failure, return a negative value and warn at level
* <b>severity</b> */
int
or_handshake_certs_ed25519_ok(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now)
{
ed25519_checkable_t check[10];
unsigned n_checkable = 0;
time_t expiration = TIME_MAX;
#define ADDCERT(cert, pk) \
do { \
tor_assert(n_checkable < ARRAY_LENGTH(check)); \
if (tor_cert_get_checkable_sig(&check[n_checkable++], cert, pk, \
&expiration) < 0) \
ERR("Could not get checkable cert."); \
} while (0)
if (! certs->ed_id_sign || !certs->ed_id_sign->signing_key_included) {
ERR("No Ed25519 signing key");
}
ADDCERT(certs->ed_id_sign, NULL);
if (certs->started_here) {
if (! certs->ed_sign_link)
ERR("No Ed25519 link key");
{
/* check for a match with the TLS cert. */
tor_x509_cert_t *peer_cert = tor_tls_get_peer_cert(tls);
if (BUG(!peer_cert)) {
/* This is a bug, because if we got to this point, we are a connection
* that was initiated here, and we completed a TLS handshake. The
* other side *must* have given us a certificate! */
ERR("No x509 peer cert"); // LCOV_EXCL_LINE
}
const common_digests_t *peer_cert_digests =
tor_x509_cert_get_cert_digests(peer_cert);
int okay = tor_memeq(peer_cert_digests->d[DIGEST_SHA256],
certs->ed_sign_link->signed_key.pubkey,
DIGEST256_LEN);
tor_x509_cert_free(peer_cert);
if (!okay)
ERR("Link certificate does not match TLS certificate");
}
ADDCERT(certs->ed_sign_link, &certs->ed_id_sign->signed_key);
} else {
if (! certs->ed_sign_auth)
ERR("No Ed25519 link authentication key");
ADDCERT(certs->ed_sign_auth, &certs->ed_id_sign->signed_key);
}
if (expiration < now) {
ERR("At least one certificate expired.");
}
/* Okay, we've gotten ready to check all the Ed25519 certificates.
* Now, we are going to check the RSA certificate's cross-certification
* with the ED certificates.
*
* FFFF In the future, we might want to make this optional.
*/
tor_x509_cert_t *rsa_id_cert = certs->id_cert;
if (!rsa_id_cert) {
ERR("Missing legacy RSA ID certificate");
}
if (! tor_tls_cert_is_valid(severity, rsa_id_cert, rsa_id_cert, now, 1)) {
ERR("The legacy RSA ID certificate was not valid");
}
if (! certs->ed_rsa_crosscert) {
ERR("Missing RSA->Ed25519 crosscert");
}
crypto_pk_t *rsa_id_key = tor_tls_cert_get_key(rsa_id_cert);
if (!rsa_id_key) {
ERR("RSA ID cert had no RSA key");
}
if (rsa_ed25519_crosscert_check(certs->ed_rsa_crosscert,
certs->ed_rsa_crosscert_len,
rsa_id_key,
&certs->ed_id_sign->signing_key,
now) < 0) {
crypto_pk_free(rsa_id_key);
ERR("Invalid RSA->Ed25519 crosscert");
}
crypto_pk_free(rsa_id_key);
rsa_id_key = NULL;
/* FFFF We could save a little time in the client case by queueing
* this batch to check it later, along with the signature from the
* AUTHENTICATE cell. That will change our data flow a bit, though,
* so I say "postpone". */
if (ed25519_checksig_batch(NULL, check, n_checkable) < 0) {
ERR("At least one Ed25519 certificate was badly signed");
}
return 1;
}
/**
* Check the Ed certificates and/or the RSA certificates, as appropriate. If
* we obtained an Ed25519 identity, set *ed_id_out. If we obtained an RSA
* identity, set *rs_id_out. Otherwise, set them both to NULL.
*/
void
or_handshake_certs_check_both(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now,
const ed25519_public_key_t **ed_id_out,
const common_digests_t **rsa_id_out)
{
tor_assert(ed_id_out);
tor_assert(rsa_id_out);
*ed_id_out = NULL;
*rsa_id_out = NULL;
if (certs->ed_id_sign) {
if (or_handshake_certs_ed25519_ok(severity, certs, tls, now)) {
tor_assert(certs->ed_id_sign);
tor_assert(certs->id_cert);
*ed_id_out = &certs->ed_id_sign->signing_key;
*rsa_id_out = tor_x509_cert_get_id_digests(certs->id_cert);
/* If we reached this point, we did not look at any of the
* subsidiary RSA certificates, so we'd better just remove them.
*/
tor_x509_cert_free(certs->link_cert);
tor_x509_cert_free(certs->auth_cert);
certs->link_cert = certs->auth_cert = NULL;
}
/* We do _not_ fall through here. If you provided us Ed25519
* certificates, we expect to verify them! */
} else {
/* No ed25519 keys given in the CERTS cell */
if (or_handshake_certs_rsa_ok(severity, certs, tls, now)) {
*rsa_id_out = tor_x509_cert_get_id_digests(certs->id_cert);
}
}
}

View File

@ -57,8 +57,9 @@ tor_cert_t *tor_cert_parse(const uint8_t *cert, size_t certlen);
void tor_cert_free(tor_cert_t *cert);
int tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
const tor_cert_t *out,
const ed25519_public_key_t *pubkey);
const tor_cert_t *out,
const ed25519_public_key_t *pubkey,
time_t *expiration_out);
int tor_cert_checksig(tor_cert_t *cert,
const ed25519_public_key_t *pubkey, time_t now);
@ -71,6 +72,28 @@ ssize_t tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key,
const crypto_pk_t *rsa_key,
time_t expires,
uint8_t **cert);
int rsa_ed25519_crosscert_check(const uint8_t *crosscert,
const size_t crosscert_len,
const crypto_pk_t *rsa_id_key,
const ed25519_public_key_t *master_key,
const time_t reject_if_expired_before);
or_handshake_certs_t *or_handshake_certs_new(void);
void or_handshake_certs_free(or_handshake_certs_t *certs);
int or_handshake_certs_rsa_ok(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now);
int or_handshake_certs_ed25519_ok(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now);
void or_handshake_certs_check_both(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
time_t now,
const ed25519_public_key_t **ed_id_out,
const common_digests_t **rsa_id_out);
#endif

View File

@ -130,6 +130,7 @@ src_test_test_SOURCES = \
src/test/test_helpers.c \
src/test/test_dns.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
src_test_test_slow_SOURCES = \
@ -137,6 +138,7 @@ src_test_test_slow_SOURCES = \
src/test/test_crypto_slow.c \
src/test/test_util_slow.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
src_test_test_memwipe_SOURCES = \

View File

@ -74,6 +74,8 @@
const char *get_fname(const char *name);
struct crypto_pk_t *pk_generate(int idx);
void init_pregenerated_keys(void);
void free_pregenerated_keys(void);
#define US2_CONCAT_2__(a, b) a ## __ ## b
#define US_CONCAT_2__(a, b) a ## _ ## b

View File

@ -32,6 +32,7 @@ static or_connection_t * tlschan_connection_or_connect_mock(
const tor_addr_t *addr,
uint16_t port,
const char *digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan);
static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
@ -70,7 +71,7 @@ test_channeltls_create(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
ch = channel_tls_connect(&test_addr, 567, test_digest);
ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
tt_assert(ch != NULL);
done:
@ -119,7 +120,7 @@ test_channeltls_num_bytes_queued(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
ch = channel_tls_connect(&test_addr, 567, test_digest);
ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
tt_assert(ch != NULL);
/*
@ -204,7 +205,7 @@ test_channeltls_overhead_estimate(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
ch = channel_tls_connect(&test_addr, 567, test_digest);
ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
tt_assert(ch != NULL);
/* First case: silly low ratios should get clamped to 1.0 */
@ -266,9 +267,11 @@ static or_connection_t *
tlschan_connection_or_connect_mock(const tor_addr_t *addr,
uint16_t port,
const char *digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan)
{
or_connection_t *result = NULL;
(void) ed_id; // XXXX Not yet used.
tt_assert(addr != NULL);
tt_assert(port != 0);

File diff suppressed because it is too large Load Diff

View File

@ -614,6 +614,67 @@ test_routerkeys_cross_certify_tap(void *args)
crypto_pk_free(onion_key);
}
static void
test_routerkeys_rsa_ed_crosscert(void *arg)
{
(void)arg;
ed25519_public_key_t ed;
crypto_pk_t *rsa = pk_generate(2);
uint8_t *cc = NULL;
ssize_t cc_len;
time_t expires_in = 1470846177;
tt_int_op(0, OP_EQ, ed25519_public_from_base64(&ed,
"ThisStringCanContainAnythingSoNoKeyHereNowX"));
cc_len = tor_make_rsa_ed25519_crosscert(&ed, rsa, expires_in, &cc);
tt_int_op(cc_len, OP_GT, 0);
tt_int_op(cc_len, OP_GT, 37); /* key, expires, siglen */
tt_mem_op(cc, OP_EQ, ed.pubkey, 32);
time_t expires_out = 3600 * ntohl(get_uint32(cc+32));
tt_int_op(expires_out, OP_GE, expires_in);
tt_int_op(expires_out, OP_LE, expires_in + 3600);
tt_int_op(cc_len, OP_EQ, 37 + get_uint8(cc+36));
tt_int_op(0, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
expires_in - 10));
/* Now try after it has expired */
tt_int_op(-4, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
expires_out + 1));
/* Truncated object */
tt_int_op(-2, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len - 2, rsa, &ed,
expires_in - 10));
/* Key not as expected */
cc[0] ^= 3;
tt_int_op(-3, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
expires_in - 10));
cc[0] ^= 3;
/* Bad signature */
cc[40] ^= 3;
tt_int_op(-5, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
expires_in - 10));
cc[40] ^= 3;
/* Signature of wrong data */
cc[0] ^= 3;
ed.pubkey[0] ^= 3;
tt_int_op(-6, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
expires_in - 10));
cc[0] ^= 3;
ed.pubkey[0] ^= 3;
done:
crypto_pk_free(rsa);
tor_free(cc);
}
#define TEST(name, flags) \
{ #name , test_routerkeys_ ## name, (flags), NULL, NULL }
@ -626,6 +687,7 @@ struct testcase_t routerkeys_tests[] = {
TEST(ed_keys_init_all, TT_FORK),
TEST(cross_certify_ntor, 0),
TEST(cross_certify_tap, 0),
TEST(rsa_ed_crosscert, 0),
END_OF_TESTCASES
};

View File

@ -1086,13 +1086,13 @@ test_tortls_check_lifetime(void *ignored)
time_t now = time(NULL);
tls = tor_malloc_zero(sizeof(tor_tls_t));
ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
tt_int_op(ret, OP_EQ, -1);
tls->ssl = tor_malloc_zero(sizeof(SSL));
tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
tls->ssl->session->peer = validCert;
ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
tt_int_op(ret, OP_EQ, 0);
ASN1_STRING_free(validCert->cert_info->validity->notBefore);
@ -1100,10 +1100,10 @@ test_tortls_check_lifetime(void *ignored)
ASN1_STRING_free(validCert->cert_info->validity->notAfter);
validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60);
ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, -1000);
ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, -1000);
tt_int_op(ret, OP_EQ, -1);
ret = tor_tls_check_lifetime(LOG_WARN, tls, -1000, 0);
ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), -1000, 0);
tt_int_op(ret, OP_EQ, -1);
done:
@ -2653,18 +2653,18 @@ test_tortls_cert_is_valid(void *ignored)
tor_x509_cert_t *cert = NULL, *scert = NULL;
scert = tor_malloc_zero(sizeof(tor_x509_cert_t));
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
tor_free(scert);
tor_free(cert);
cert = tor_x509_cert_new(read_cert_from(validCertString));
scert = tor_x509_cert_new(read_cert_from(caCertString));
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 1);
#ifndef OPENSSL_OPAQUE
@ -2675,7 +2675,7 @@ test_tortls_cert_is_valid(void *ignored)
ASN1_TIME_free(cert->cert->cert_info->validity->notAfter);
cert->cert->cert_info->validity->notAfter =
ASN1_TIME_set(NULL, time(NULL)-1000000);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@ -2684,7 +2684,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
X509_PUBKEY_free(cert->cert->cert_info->key);
cert->cert->cert_info->key = NULL;
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
#endif
@ -2695,7 +2695,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@ -2704,7 +2704,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@ -2713,7 +2713,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 1);
tor_x509_cert_free(cert);
@ -2723,7 +2723,7 @@ test_tortls_cert_is_valid(void *ignored)
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
X509_get_pubkey(cert->cert)->ameth = NULL;
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
#endif

View File

@ -155,65 +155,6 @@ remove_directory(void)
rm_rf(temp_dir);
}
/** Define this if unit tests spend too much time generating public keys*/
#define CACHE_GENERATED_KEYS
#define N_PREGEN_KEYS 11
static crypto_pk_t *pregen_keys[N_PREGEN_KEYS];
static int next_key_idx;
/** Generate and return a new keypair for use in unit tests. If we're using
* the key cache optimization, we might reuse keys. "idx" is ignored.
* Our only guarantee is that we won't reuse a key till this function has been
* called several times. The order in which keys are returned is slightly
* randomized, so that tests that depend on a particular order will not be
* reliable. */
crypto_pk_t *
pk_generate(int idx)
{
(void) idx;
#ifdef CACHE_GENERATED_KEYS
/* Either skip 1 or 2 keys. */
next_key_idx += crypto_rand_int_range(1,3);
next_key_idx %= N_PREGEN_KEYS;
return crypto_pk_dup_key(pregen_keys[next_key_idx]);
#else
crypto_pk_t *result;
int res;
result = crypto_pk_new();
res = crypto_pk_generate_key__real(result);
tor_assert(!res);
return result;
#endif
}
#ifdef CACHE_GENERATED_KEYS
static int
crypto_pk_generate_key_with_bits__get_cached(crypto_pk_t *env, int bits)
{
if (bits != 1024)
return crypto_pk_generate_key_with_bits__real(env, bits);
crypto_pk_t *newkey = pk_generate(0);
crypto_pk_assign_(env, newkey);
crypto_pk_free(newkey);
return 0;
}
#endif
/** Free all storage used for the cached key optimization. */
static void
free_pregenerated_keys(void)
{
unsigned idx;
for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
if (pregen_keys[idx]) {
crypto_pk_free(pregen_keys[idx]);
pregen_keys[idx] = NULL;
}
}
}
static void *
passthrough_test_setup(const struct testcase_t *testcase)
{
@ -339,15 +280,7 @@ main(int c, const char **v)
}
tor_set_failed_assertion_callback(an_assertion_failed);
#ifdef CACHE_GENERATED_KEYS
for (i = 0; i < N_PREGEN_KEYS; ++i) {
pregen_keys[i] = crypto_pk_new();
int r = crypto_pk_generate_key(pregen_keys[i]);
tor_assert(r == 0);
}
MOCK(crypto_pk_generate_key_with_bits,
crypto_pk_generate_key_with_bits__get_cached);
#endif
init_pregenerated_keys();
atexit(remove_directory);

545
src/test/testing_rsakeys.c Normal file
View File

@ -0,0 +1,545 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
#include "test.h"
/** Define this if unit tests spend too much time generating public keys.
* This module is meant to save time by using a bunch of pregenerated RSA
keys among */
#define USE_PREGENERATED_RSA_KEYS
#ifdef USE_PREGENERATED_RSA_KEYS
static const char *PREGEN_KEYS_1024[] = {
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgQCZa39BCgq7KWBWFSjGYHhqmTCHvQ7WNEFAb9Mujb6Xn/Zy01fu\n"
"WIpVvqmAKeLNEziItUm/gB8GwAN+/ZLwL9pufjIp2Ar+yqVXKySioZQxuCgTP2wm\n"
"Ku0OfmAra1Xbtrkc2OCJllxkyNPrJ/kxfwjWR96UP0+VMbOlkBoEH1FtvwIDAQAB\n"
"AoGAUXoygeMIYe+OdwkTt48CRHKIwH3aRE5KHSOGPyIOB05vvvmYqD8jcHgqYqNc\n"
"DNdZXdkRin9LevU8phObFq4DTXp08XggUx4Kk4AdsFKubQtJ8gHm3xlSKbZXX2m/\n"
"ZF0GRaZtVDQ3TRGh+OBLILt/2jT+BaFKGAyJ7al76F2nprECQQDJyLlteLDFBmrd\n"
"0kAjNBE50S5YskBCQeQACROfyTKW8lG1J57UBeYjXvbrDFBR4alIS9DEexGai9Gz\n"
"wxpgKg2nAkEAwqQmPstjHxvqGQRi41uXO026MLxY7dhEqs1aSw3tuT8v17pW3OEa\n"
"Qxv7JINePZ3+sNN+Ic+3RXBR0QuD7lSSKQJAZjVSF21GvMXfY7SX4D0DbLHUNAE2\n"
"I1mUz5/JXOpgwazETmpfPS4vwELd93kpRhBz2rbsbFmaNRoVgmSU+5jRiQJAZ1bV\n"
"g2NilgKxEGU2x3U6Xt8Oqo9lO6omEvUCKnUTsNWuZf/l3FGbKuQxO5qPr3Ex5tny\n"
"zqrEqBZRKgbOHfxCuQJAbJY5C3Nm5koemr031r00MY2YD1b6+hyKZyPdZ21HpyY8\n"
"z1kWShL0POjYPX/BnKE1FkpklWcKBb7wkK7dvAKkEQ==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQCyqMM2TfFGV5tVBTVabxLVln8146nDavIdR6q78DCUMh8Zfzkk\n"
"h9Lbl1NX4RU+AmrCZMPq21/EjIRxRQyRdgPYJVLdp96eGeYnEzmMkqvXiswXvDg/\n"
"tXqsjyJeYsoHMQWDTpCLfjYo4K1ol1sg8VIs4wQeq5og6QSdmhBoz7MyqQIDAQAB\n"
"AoGBAIJekey7nZeV8Bxva4ptSRIg+v0I/2VBUiG5nUX9NIW/uV/yrXERx/VDjKaw\n"
"8b5JJzxpKWnk4RJc83xwRYaT1qMYHiQfybxEI0K9SjhtaThAjtXkQGtZgLJILl3t\n"
"yh3LPTh1ocwafsKjU6eGYAe/DYn9/QwYHbtyaimcigu4etp9AkEA2DgC+HndoP1i\n"
"np26Lx+4TG0vAfrVYGSLT9FXwf2iBV3oJvdKqu6wr8ipb1SbshRPcOQd31/mCh6+\n"
"2BR+d4ddcwJBANOHrlBbGZdHnoEu6kKbPwwkc31IZYqyfSpkqm0Lb2oWZ9SInKfc\n"
"cz0qpH91p610XUpYmycaJr4K+N8jgrz86HMCQQCoqGBg1Ca2OpCf66bctWB8dTqS\n"
"z8d7rlIhC8npr1+f0hWRt5pN5Wx7YgoQpq3gZgllpPtMT7DQOhVh1fKkaDnTAkA4\n"
"XuskPPLX7t0dvhvtviOSH9CrLXTp/mD+wC7uumJpmij3aaSd01DelxOZaAhUYDNQ\n"
"UcafKAf1E0V5aaQ4qwljAkA9NVN6CtpzzcLrstTKxrx5P1Ylt/0UYQDo1lIaqwrT\n"
"aOFbXmOungiC9+p/4U7RbX0MEzjFDHCWlaHASviGVgta\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgQDDt2V63APj3JSqaRgofUzhtB+prm0wII4uHyxfOxnpYIELOW5z\n"
"3UHmkr+B4D+Nif5jIp0i6W4OS4S+YHewKsDsXvXKRIW78KzOt6Le4JI9rSarNjy5\n"
"aJKksWQRALLCmxP/BdolaBFqF3fIPD5+Zxu8ESgxhkEQI4p7awUp3E730QIDAQAB\n"
"AoGAZktfAR4p8lkCYydW9yK2ommQ+xEuBK+fYL/uYz/yxSYpjIJSFsEYhrlA21Mo\n"
"JIRxr8MRuoOjgFk8YnztUeimuHpslDlZDaCBzjRjBRFCMepZNG9xqSEL0u7C+SH6\n"
"KU5f2x2P6PneBj6WaHZM+6Lf2xHlOoeuaVSUfq2Pk2VBF9kCQQDtawWWNwP0+xea\n"
"oCAQpanaLzYPjlqZfHJQ1AAI5eSkdf1qmlypIHwOtjAEa6XuEO/Or8RNkNy4nQdw\n"
"qhcQ7PXDAkEA0wjT6Z+Lrt67FnwPgoSvl4Nukcqw4OWHbBKhaQPsO9+oc3PAXLdD\n"
"SclUUqDF6NX1yONTV1KrPdz4zElmEua+2wJABm4inZnp2oW+cuqpU6oY+pbSwQMb\n"
"AxMyyWukgJkxYx7q+SsrHU2K7p8Sl9wOh28f/5oVGAC3aayfGfcRXtz8HwJAIqeO\n"
"dQzYGU1GF7kjquEzHIRewd4xEZ1fkaW1j9MvFd3ygZL+gbsud41yJWd1WHjaNbTu\n"
"2KYgrLX+vT1IX844hQJAbg0V7iHlttQqXL7yN09jIjQLprqVhDZCUHS9s9Dxe7fz\n"
"Ac0ZZD0D6EVNmSmBB71q7kLUWX/W/10d447TLnnfew==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXgIBAAKBgQDhCAjPEockl4lqkvoIb5O3NJJG8NWD31c63e/cPWY6MX5nOM/q\n"
"avof2eWJxFOk0HQ2BRVwIgNex6kLxtsdw7XE0A5uZorTp9DbRCGMqUqHNhHH9ci2\n"
"mMPP9jptq3ieWg310bH4Tad8h3WE2npSCDBvxyV6EmuH2rlQW9ZlHNoiRQIDAQAB\n"
"AoGBAI4PgWggPTqng7PJF5mNvsYQpSutzE0VCL977nmuNUQVjMPjRLarVD4ZU+QW\n"
"EevhQQv9R5xjjJcgGqL5pchzjeKDm0/LA+AygnZoDMs2O68Neieqvr7cPqr5ALGs\n"
"WuZvSn+bRJTenvV9sUh2ii0/u3GQbL1v7GWDkIdD7itDbmRhAkEA8iijuEY+W67w\n"
"7JusjY2MQ2Cm6xxxR0YcnYPzT6UDm+Z7NNJwKscQ6AjayNmxmXGpbUdukzLzXf8y\n"
"fccI9t6iHQJBAO3kx9nZay0Ktl51QP5o2gwoqRIbnogGfR06KJOlzIPGR0aPn8cg\n"
"uKq2SiyjewEaSBM6S/4UlxYUmvc3VKnxCEkCQQDpTjg2YQ7RPGIIRA/iLV7Wx3bq\n"
"C/QjjCwjoi44LK6mdE9928WPoUzrkSRg4EQYpwZqL6kcDrmkdSuLPMipOGQNAkA3\n"
"KtzlujPOiDNuiEaAORSHyU4b8ue6p7aP9pK+Wq6oyGxzAo+NABuTCx78ZxT5Vnzs\n"
"aJKC44d+CV0+g0hQ+KJxAkEAqFYzNWIzTHX8DVDdK9BpUaBg1DFxIeP5Kk+/X3FF\n"
"5BafG08B6OiLf8qIGGsxLXNRjIE0GVp3Sy23FUKtUymP+A==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQDMDk01VwPxQq/BAwOBmfGUP/x5BQn+uxI0Aat6bdWuz/2CsjbS\n"
"CWD/YLCaPm+DpHp9RMwk4HONJaw4B2XOw3ELPx7y9DEgdC1wZ9wRkJmqr2IJZoZR\n"
"C7x43nNv+/IXTiRkkljCcMpoL1Tld+L2VbmWR29PdZwvspWRILkEZu1mNwIDAQAB\n"
"AoGANvFK3KfXSei4xfF3yjeXEmHAKx2uOUZJenNQpqBYPr+F9ODjXd5knZ59LqrM\n"
"/9cTnBMgHHXK5yBTpKppQSjikLeQ2BF04Ktff9oGqVcS9x/rKo0CREuxsEfawZOW\n"
"OzOWENp4YcDKGP1I/Ctr185QzStaWrXVQftxmYQ53T77ShECQQDnhabwtqW7rfe4\n"
"+MfkWEJ9Y2s6iMs3JWnwPOX9G9R39PiAD4vAghHJyHHttS9Ipxmvp0hThu0x7a4g\n"
"8BfUpqgjAkEA4aFAmzarWKigREAACVTYH2RHpXbuk05vF9WqfMPiEvQUd5a1q6vc\n"
"xkGZsE3v/TExLjPRZP4FeUNV5sD7THzA3QJBAJxPoRlNx3GCEAlDdfnWGPX9JI09\n"
"hC40RWUcSI7ttjJTI1+an1kWuBnLChhaRpU/tFjikTNLmmMmPHUihIRfDI8CQG7g\n"
"3WzpKr8A7vFbOilbxnF2yDaqAYfmTXW7DHMPl/OUetJh/5kDdhT/e9VGF5+nIvH/\n"
"iPFGW85Bpt8lCtmFnQkCQQDjpp9iy2qesE7KKX4Kv3++QfCJ2w3g7lwg4iyncoDd\n"
"JrM53p29HROM21R6eekvqeWIe9tEX754b+E/N60ZjpGm\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXgIBAAKBgQDdDn3H+Eu0AW5GKohqDBntw6ubnd3VaJwZGzZyga4J2kLg8peP\n"
"RAW6GDD6pcHzW+KZbFWHtRk70FSwvmyGcf+DY0r5tfyCHyDGmbJyPR0o6OVCgSFl\n"
"ccf4eDvbyszzMdlx3uL05ABIpCShoKtEUqvyIQla3Jon+QBwuVkizMzyVwIDAQAB\n"
"AoGACoKh4Fwh3VEkGRn0mnYw1Wk0Q5Xh8j+jDF6K3C7mQ3mpLGDca+dkDlEQIxq2\n"
"egeoYnsQJf+qT3m8TRsAtfO9nj7+7IX4BfCtdIi4RNcorbs5YMWtFyaywnM6SQjS\n"
"+1qf74aL4On9WRO2FtvnTMjFAAkiWNbQp7mWwTmB59i620ECQQDwde6/PwhUzvZh\n"
"dyslKJdna5RjkDQyDIuh0zD/tFZ0Iko7Luec8q6n52ev/n0OiTLGetUh8goePsPP\n"
"HVZHidNJAkEA61eMCmmu+GCAg2vJRtL5sDakAXsbP5M9Bf/QVHXtc4EVXHC6T2ld\n"
"bldOJriNbBThBuPNmlQbssn9FApkyWT4nwJBAIuHIv3+CUuMvBJaH8L0BsaP+g67\n"
"wk24Ud2Yujnl3rSMoR4uXV8IwqfS8quAs/gXTEs3QyzrUUuzh9NKZqIkK2ECQQCz\n"
"vivBEDKIlPvSZBJYO25kfXcJgoKvLb9fw5/TwjXXD/HGpnpFiI3JZnjT7gRlVhT/\n"
"9CDmC/MTvF3EXqPXhXy1AkEAo3a2me23Ljmub21jycSKaCk09dK85QTRRMe9c/hs\n"
"i+pcGi9ZZW0Mm7cyQo47oXjNurkkv0fEvXIobVTEXAGU7w==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQCv8R1IbfYnE3R3kNeezJ7m02XnyCBDDy0YfrQldQ+urdg1CFye\n"
"bO0iPniJb8fmV8NW7x6nUZTDznCg+igroKXtK/w0WYmJJiH4A7Oi5xNjAfRIPvJ/\n"
"J5GI8szS8rH8tp8pW1h8k/kNg2pnBjwQ2U9omhp95RGaHDQSRYzzH/fEFQIDAQAB\n"
"AoGAcy7+BcH/iZuB/xjzIIJDcUhqibCJ9n0D/+pLU85sYuZrCmUcBZe4M1gEn61v\n"
"iExilRJc1hthskL/l1POYql8lk+aqeeDuh38fWJj60TCV/sENiuXOsTmoFVA5pNn\n"
"lwlG8JlpBMsgr1fGqg1C/WLFfMmvXdKVGvpRqI06j7AYUa0CQQDfZ5rI+FhXBlxo\n"
"PR5CM1LB90DuHUMW+Kqoj0c9d2esXEQM7UqQ/9BiBQbL6Py7Z3VwCxibOqyz7+V7\n"
"2aGUMAKnAkEAyZy5Mu2tHs6YBBxPYam7huzMUYjddN7ixAZUyGwxQp9kTIF2NbSQ\n"
"yVDjKrco3s2lO4qj4pSumwVe3GGlsi6G4wJAOOS3pIqqZK84BUvbUtyjLMZ9AKbv\n"
"GQCG5ZpneB3ahyiQJAKiRL8BIJVLH87b3hYA8GHDCHUu2jwz4xCPd5+qbQJAV0TP\n"
"pYvb9AnZI25drhiaY7z8dA6aTYxs/A0Bhf/PEteLwtIHKRgP1BR/QG4n8slxTGSm\n"
"q91P9ypL9XkPECGzoQJBAIMvGEM7ZGevQHBjJ8HhU8IsgT4cYH/XEYb8jRy4F+Ui\n"
"jKxHPxLuFK4urAZunNUNrqhT0PxbB7hRjtHZrmFkrcc=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQDSpmV8ncLwc8gXzdFsZGPDtMO7C/IN9jKCIK13WIseMg1APlMt\n"
"PB5lMQ9fa3m9ZRU0L8HzRo+u/Xdos3yIBI38X2Avy0laGKnQxiOKaDT/5ZHeiBBh\n"
"nMZjP2WY5V1sgqNP9RD8enE6WaSvq1j0BM++mn9KEe//5+dWD8tboBKF4QIDAQAB\n"
"AoGBALgVoerdE1Z+WAY1XyaSNHz6o3H6ZnW9CTaex/jb7/dbVikmThnhx842qXCB\n"
"w8m3ZGhOs/edWkNaTde5wsI6+LhVGco/PWxN4v61jokxUU+5KvUvGacXhXIjzKwG\n"
"DrNCYmle62QCI1z4+TLQW/Lq+jw2Wzk70NWEvoP58gt5SJoBAkEA9wubRKRs49LW\n"
"5JNQZ9hjc+mAfP9YK/sMe4jkdloMMWXjSMlF3Z4mI9XQSpfbBqwWIBXsjU/15LIS\n"
"ftmujZsMKQJBANpJEZI7UFoRdSP7AlM0YJuXWnVGyn/K+VIeEso5AlZdKXCTpxqp\n"
"9blWq0UVC6jLesZ5UNPuBiAnrBaVwDA8YvkCQF+FQVfdK607TJO80g4VAP9EfcXX\n"
"BUScIUtytsN8NdKzzpnKGRWDnMOmXI87ABkoWLW3RGuvSyhOIhCiInfmR2ECQASc\n"
"FmroJcJBLCAeZOYs7P1cLOTdIdmhB7LcP7lVit8YCJAADj9Z536KfgNvdleSNH2M\n"
"glB3blmvfMrdTrm2DMECQQDj6GJ/Tc2rCsq534xknasVjrgtJMQFxmQCTVgBx9pc\n"
"gTflJAHAmNDvstacVqeObLCF2ZIvya8fSXGbDOJYeGDv\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQDGgUJAm7vf/3focNGwzv4TkzYF2XwpAirnb61dyxvfug1zKv2k\n"
"AUg3qACiurR7JrI+kAbmxEnNaKV7ts7uO763wP9KE8YAuFZsp7NFA295rEZhw38T\n"
"rUlWHMCeaZ3mqW2q8gA14C/ZJCG4gS91SIHLjNGsbHwr2Jvri2ItwIP8FQIDAQAB\n"
"AoGAONceb32oiHWQkkBr6uL6ogRPPdGO2fdC7c5uqCLWsnOGEmpHAsVTNoym0fIA\n"
"aBsmgv+e2klukKDccdZg3prA+z7lHcc2a4bIFguF6ei80hLIis/dds66fFXofCzy\n"
"DMlkncSbJwIvQHG9gblxp9qSKElZF7XjABZEImarfUlakGkCQQD//msGy5N0ZhMI\n"
"yGMXkwXRJXfmRrIrOqHx6u1eUp4OuqDW+hBz4KCHnWfuRJkNGQIammSf18jPasP5\n"
"YHyr/LifAkEAxoJ8R8Vusexo9ZjuU44qXCSvJQ26UBV7mn6TGEAn2DRK1RWKDaHv\n"
"j2vnRjt3CO9WPDQL7SB/1HNAy+dIMPyqywJBAIB6tESIz8zPniX+TJ18UKMTZwXP\n"
"3YQMvVKpUdDRLjq+OBMtFizSRD9MJOlUzGvibUfkzTPcHRDcyNbUMj4vbIkCQBx4\n"
"6sqAjvgGKKfRX52sbnb47AYsieSisC/gp8h6qzxfg7w8cqix6WJw36M7ND+b1Iqe\n"
"DHfeiXc3cLvOWJRuKTECQCEYkujtSjXWb26xaESFWGtUI/nEvCyqYPQAFBpaGzQ3\n"
"tiTDeKHzypesWYoTxOiNQWCQMLrFGuUbDpYOuDOVNjw=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQCcwSAfytnspSSDX/sKmCPOMnpuCYeWA4wbz1wLyb63a8/KXhhG\n"
"6o2W0kt3x1vnGZkeWwZOeBFUqwoc+xHhoNcZFsMOyqbqA3UMZW5cx27MsexRTQHs\n"
"Go1newu/E+8NNCohY51G7z1Hdo0L6mi/Tldh7puuGsMwKqNG/Vvo/GQDgwIDAQAB\n"
"AoGBAIUdpBAbjXDe1OET0vYuOMnUKA/l29RS8tpy/zGrg1/0GCM8QNWIPfEEaL4w\n"
"+CSKonMazYI5iE4kaZQuygKXOdFqKxX8nrGK2hR0DIEUHhhiqyGMUKrf4ELkAJzK\n"
"tHtcO64OFEU2EGa72wCmyk2MhqhLxWxA7E00x24uvW6pen6xAkEAzHhbzlRgLZ+K\n"
"QuXmQHEqkGaS2Ccf6c9TA5Bf5S2/5zBl+OqVyJJQH0yrbPYR6Nn1NeSv3R4IDJYg\n"
"fSZLaVzWHQJBAMRCU6QtTnZoQ97pLvXCSKRYKJF+CnE3zDFTyoJrpK0W1FSnb1EE\n"
"DWjjdSdMLynf/InX+VOaLk3Gxwjme4NKjh8CQQCg2b4/HplayrsVzY3I/D2jw02Z\n"
"xY2RfYusrhMCU284DBbsLn8OfiuRs9rXqOyF5ZDFiNXgeROT8zYzvcBtbp7xAkBU\n"
"ZET9IvJLXjhZISItUXbVHIeNUIqC9sBaMbKx9EGioF97a2gliT2O7cgRtuPM+ODq\n"
"ETHILlNc5G3vuNRBt4x3AkBV98Y1SZA3TQlUVTsjGraxkFTfU1IlomiOdOwTQ+xZ\n"
"x+JxhhgZwZ+kgI3PidEufFCTZJ3WO6Wk9gk18Bx7CLjm\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXgIBAAKBgQDq/K7wNW3fcTbaRTjNZlM4W0G7tKeO+X0bca4+9uin3ML3ogNJ\n"
"6qT/B0QAZB6Vyi9kKa3E8plQkjmPuX8Q27zj2QjEuDZ12RGFnikeOosUhOYiDh3Z\n"
"T9CHnr6stozzgk79Xd6VI7bqRcgRwbY0uc9QVr6vwddyIfSploSpVcgspQIDAQAB\n"
"AoGBAJfUpo/sZc6uzxtfCKGmkPTj+ef3hSBbUZuu60AhtxfnC06HrwpOg0eJAUYj\n"
"aqOsHMziJTYQ7kDiCjE0UMaqxDNS5hueumznq2xM2mSN0nYoktU00kpANVkW4VPA\n"
"33TB16DyqlKq2/21Rs1g8/8+IKkKDbRLTC//1WqNHASQVoGNAkEA/+z4hxTVXZkr\n"
"9hz29tAHKURlqzxUEKLnS0eL+XGJRNfGJ+65eXL+gFiIbTnpVeidL1+lKWkZyYzl\n"
"75cNRdUHhwJBAOsOJ9mUOqTbLW5tzh18ewZGOa1JcxhOvf2E1d56N8tDK6lvoqkF\n"
"oUUb8kIweDxPLCVLCl8qFrbjn619fxDInXMCQAfEZGKNIlCd5nSoumIRPDZnagKB\n"
"aTe8CfMB7+CZLoZVWiE6IIzsDYdNqI5QFKHT1nlqmLOiCfNRAGV+GxwEdB8CQQDE\n"
"sHu4HclU2fMSTOAE3H01qt3om2WsGXfyBI3SNQMrG3IVvkymkwd4BQKbUGPMU5Pl\n"
"QP3U1CtdruuXCUSijrzxAkEAoqYub6+0zM8fakSQZcZ01TG9Fuo2xVFDCQsvqR3m\n"
"ZhRT/oinIvOxSh4fQs40bmt1RBmc2L1Is6YB2NTVQEBZDQ==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgQCrf0rPvHYaGYQrc1ciRwaONs8TUvSVmUU98HMYXoFEkBL4CAGH\n"
"4oNHFk8kXHEOsBED0eccSYegWhqKHSz7PbjmJaXloExWrtx5ea3Twf8VTgcfDWQP\n"
"0TzD3G1TYjAFPQ1/LAZCpQFmwpMmTGGxegUhOzkpEWXdLVEVc9Uw4C4L2QIDAQAB\n"
"AoGAZXAJZA5pHM7y6nBynYe9TOkGWru6h7H8zsImkcd0VoWRcrvpi+JjG+0KKsuy\n"
"46kop0XEmWq0mhgxknfnX0QG1MKTqGMIUGN4qCaezOabIpCOdA4d/pr/mWoNgOWw\n"
"9Kc/tNCrKxPKsQMAlWP6ktHN30XRSlHgAjSeUVUiNHztvTECQQDUNin2nyIvj8ZA\n"
"QAsFW9qW+TiTkeUK6yiZ9Gvgf20gwZRWOe5/xnMxVvtN6v7Av1ew/l4VhBoj/w5g\n"
"ydIZk+2LAkEAzuJwdt+ccllG19qmEcbo9XFafgi2PvlEjPJmT1rHV2ns/7HIMu27\n"
"PJY36GgExSfFco6VmicaoOt+RKg+5acgqwJBAKQxAEjcGWQ5VsgRhTVxO3DChX7Q\n"
"TColhrWPwwPhM/s7K92HVzwvvKL5TNmdr9xMb7n3Ja56FouxZVuH6/J0XT8CQAat\n"
"Mhnz/3WFQg8HRGLAe5YoMVZt64u+uaKe1ARtlo9QoNBjqWVTXL6IzocWjEjcjrey\n"
"uEtARdC5qNqIX3dD3H8CP3pVCPvpHOTxkUaktmLYowSA1HSfO9wkE6bMCHhkLwXF\n"
"yTIJ+N7c5u5YN1B6hhVqpKbdnSv+K0MQ0xbfwOWNMw==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQDGQmrKfO3WovoXkOTSh/shO9qjbX4izhg4pccVU3Tp45v/dgAE\n"
"uDUuaa/clToyH5AhOtuazO/asC3ZNajg1ia5VPzmQU3gtqiIZIEXFaOovPlOrXru\n"
"wyQnxaGORndJwfDXicG6bUwI+PDpNq8c4VOTujReeF0r74qMSc7TQLVlUQIDAQAB\n"
"AoGAakR/aTm9YibJVohbnl00xoOGlcLCsXU2lmaFZ3DsYdGWdD+TkvQJzW7ozJtQ\n"
"Lj2sy6L4wujGR7nXWW3hr2IaLpoc1UoyJpieAZM5os6bMN+N4MCqdcZMlazMtSWV\n"
"UDO7O7xQGFpcvvZmnfKCyluFaJ5K/tWxP+2TnS1/m0BDRIECQQD5DYvToA0eKBt+\n"
"7K4eEI8pzDot9NlcL21D86kNgpmuY4pifALU7GvXr299JpFFiYa2A1JVRfpQaoI3\n"
"hZzz0ze1AkEAy8opWJP+T2q4reD5Qq5UjjrHUXFID23KeJEjh5YF40/bHqyVpWVR\n"
"UMntNgAzs+13vRij48Zn6I8GRhStaQ3ArQJASPyFS8GN1paeaDXoWPs1WWR2cF1f\n"
"DbsAZHeVxVXOv+J//ZimI8wdVpodLCoPTLee+NxEVqUpVEPCYY8QjgwKOQJAATmj\n"
"6f5pxvxzQ8hYd0gpBfngfOLbdgxI7VSiDAyg2G8AeDy9YZMsW/n6zRpPNUO2NpLR\n"
"WWs18LX7aaxyJnGIuQJBAPPfy9pd4XEFsRBIIe3N23Gua1XkS/407RJtAGm73Vrt\n"
"QhtWh3i6D5gfpEApMoaE8aaQQ7H0z+0Uh1t8SWesy10=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgQCc/M/X8etUqrxnmH3PyuAYLIPZhwNySch8qz9NB47izYjxzuBG\n"
"GSls6H7WeKIrB8UJY1gW8TLkdOLcrI/0hTANNHEPaueOE0xdABFj7tAaiiGPIM25\n"
"N0wc76me0ZAMYJrZTHk8JZK153y9wInYBwVZreXCVSVf11RuVwe+iFQa5QIDAQAB\n"
"AoGAQC4XJtivdhDLL6snHFF7pkZkrQTGgu3pOhakrXA+mTigGQOTqvTUe8LdP/9X\n"
"hTIK+tiTheWcAcxLhx5BSB0/VDKjYhS0ROpTc33Iq9KalOQaTJbBYGA4eagpQjwU\n"
"jGwr9u2sUsM9WI/Jg0VvLSKhfnNwYIUzLpK3BbWb2qAdh+0CQQDQ2s/8DlibFSBK\n"
"UsFK7lLpV8UgMk9CkaNM2BPzI8Hsjpp6s3pULVRd36m4YTSg15EEHv7bZ1N/+krX\n"
"mXb9xUULAkEAwGy5wHsUSjTK+kntkNXjlCU/+9R+HFpzg9Bwm/PqXTBwEWeU24hV\n"
"iRjPvqPtWFZrWi/nfcviuMaqtdliw1I1zwJAZ2mQxhtMYC2LuYFUWAe9YfClmJWQ\n"
"jUOTef8bka5I3RqW/t5TWc7AEWMnpDXtWx6hnUrDolt9Cschu7MvKeQ9lQJAL18U\n"
"46PpPNN+XNuyVoOxgRkihVasrUI/SeYYsuv7eHGiRUagyOLpW9T139LvbV3pE8zT\n"
"So7VA/Q0towL2lX01QJAGcoBNNouSpum9+5NvGQK1XXsZweawE+pFR2BE5XcjG+n\n"
"FnaLEUBX7nTxhTU2cSQET1PKRNp568a281NEna0nxw==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQDFOqqGG/VtIScxayZYZ+BT+hcs5W1bD5qRxunbG9O36UVT18UE\n"
"CWw9HUf0Q5sDMGvVmBxwZ4GjbR5FDPfhIXaRCzobnejJXq/0k+O5NAVkcSPtJvhK\n"
"AaUqBrWA41vnjKOtJudTsZLfufKafzYwVonze7fXGyVsBRjVwHNS4iqq2QIDAQAB\n"
"AoGAJCoStI6R3RXUKvKb0GATuTJFZ50WBTmCPTK9FMkwdCuY47vPy2Ky7y3cUMTI\n"
"urf5PewrYs0H72CFyWGMXkKVi8aOYshsATEXMfGSqOcqXn+UDssRzvabZFlpnAUa\n"
"WDVt/iN092AdakXNna7/DxrLisDpq8HHJfjtlWGPfkXRg4ECQQDpHeKimTvwJcPc\n"
"iDa6Qb/n9gwLeRckfzhYtfX1luJYLIOHh+J9vjQN75thenBLQB/B6qlKtOn9ejxg\n"
"5z+3zIOpAkEA2JbxXVTCOA802p9khvHxDtLHdKi3w/BjjJiC7Mgqo69ZI+s3PB9E\n"
"F2HJA69kZqpGqvybWHDapjWsq7rcMlxrsQJBAME2yvR3y00VEAyGPc4M1vF8ZqlP\n"
"uRW/+ETWtEDUyU/JvU6lGt2bu2tdkEyv/cjxIiFIzP4litdT7B1pLc+6S9kCQBwE\n"
"usiWFGHoJbA6emiyl7qRLdg7kzo3uMkRWa6D3nA6WM+6t/SBHu/faH+fit91G5s2\n"
"/mmcf8yMmP/GNoIVTqECQFl4Pt6yGiz/YVoYSp35ljY5n3JB6T8o2pOmIrRLuPmT\n"
"6kgyygtJBAmx5nnQoeG8n08tl9QakWznKzkNJ0DIFKI=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQDCaOqJ0lsSAEBcnNB6X7BvVcEcol+evi/nJsPe0uT1SbtW50Ch\n"
"vYOHwK6aQR2C5x9VSs47cLynTL7tNt5d8oeryF3NpI8VTPLImDJCcvUZhS7p4bxn\n"
"JO+Wm+D/e3TWfyjreuWtdL+Mfimw2gzwWuBEtmj51GzQ89eYm7fh11SB6QIDAQAB\n"
"AoGAWaakMbZNxPlUtOCjyysBY/Y5vYira7rswD3CKak7aFn+CE9QIMYSN7IFUqEg\n"
"iNMoQd7jR8nvVX8wtJeO5+gF48W13C3n8FZSrW7c5N3bmfMIgo0xa/TGfeXHP98o\n"
"7vhH0I58j3ZZt0Q+3wTm7t7WPE/nJzgrCk30TqmoaEmstTkCQQDtV6YZ6juEK2Lp\n"
"LGUiqohcS/WJxvFrF5+LNpk86Xdgomf6FphZlkq42KYkvl7qibKDcfDqLKTbHHle\n"
"vQQeCgZ7AkEA0bFHi7F8o4iHtKleBvt4QCj1neA0q3CRDypCI5EqFSrNpxY4Krhh\n"
"WYSVX+xT00QYaCpKKWfYQztCw7Anylv96wJACl86Mwe5ch0zRV1bThiFvQLUyCCZ\n"
"jESMBFlueOr6/I4cXSF/puqaeVl+aTyoiTdbRcNE8/bffXPRGgLIm0d04QJBAJSY\n"
"lmTN789Lby99Xh6AkaSV4ghw26Ip8QHYJmph8npxjK69Niw/4Oy44cnKBVUPSmR2\n"
"o3tYFY7/Lb7S1D+4lOUCQQDbMQUGVsZT+ZjuOG1bAjIuXoAOfOd3mgH5VgQHjSgJ\n"
"ourZtlJ4OUpNrq9IfWqPkM+zSE8+0Dk8/9MS5ngBA/SJ\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXQIBAAKBgQDNbHjwg+7tVNr9erMLowXRnIcttp4pUJbr3B7Jo/u+kD/Yo3F3\n"
"4rIKhHpJl1uEHP1QmvAD+4ApFFI2hNG54xYI8dGflxL5HOs5xxyOPpkrwzQ8Qvnv\n"
"LPg7Gf6PAW9zF4McG4wK0TkrV28G6NhqcPs5VFY6UyvfZ0fEdWAeoWTIfQIDAQAB\n"
"AoGBAKOmkMp7MLLd8QAS6eSRYSdWHdLrMyES1MjduaFGBF4SKOr7en/Zl6ENXSaX\n"
"cA7V0XCPnjpt9/HCAKTyNupx4LCeFWiqdu8VGXhlzX8bdb896OSR2brKbxgRY5tF\n"
"36uL8akrZdrYgocykQCxmRARMB7/rHwDusiamjL6RUZ3+c45AkEA6UPTVmKZQRMr\n"
"A7Qgg5nXrXo9117Lpqf3FdZ1wdni9V59Ptf5xrx9oGZNZzctJPXSAH4M4cumSJrV\n"
"sZ1V8qE7AwJBAOFx+5luLrVKrdlG7MyOhTAdhKYUvKIvL4wvVSY6y+L2nNEx/cTx\n"
"KYbxGC+H1RJbkCS09rYir3VfDRWQ3W1c1n8CQH+X4hn2hO3blkPIW6CgniD+JKWR\n"
"7MOUTMtdK7yFemfM76VYbgAPSohabSxwOfllnSE30cQQqTw9tXYaIdE98BECQG+M\n"
"QWxSS0QillB6unIgVqBPCrJOcmNhK4qWZPBMiVNcqI0Nyj2nAeAl7MyfzfqOWY0A\n"
"CU5nbR+LD2NLUXRqSisCQQCN3IGv1WOWInmA5xhU6vCFDX5u48Dcji7VLJO/Nv/i\n"
"b/zHKAgjHk5Js7bi5ZWEGaUgA4Jt6cKmGdERheqTMKxx\n"
"-----END RSA PRIVATE KEY-----\n"
};
static const char *PREGEN_KEYS_2048[] = {
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpAIBAAKCAQEAoksI1qIuIaFCqT4QbgDvOQCmr9Z9F0E7ku+U5Ep/5dWNANqB\n"
"bSzAOq0+cxiisfF+H4desoqiWDUwlOwXH74qD3ZsbChhvFUD78cQBWQkF+whLVHb\n"
"296QmF0LZqosqz9HMS9CdoMUc1brZb78Hb25QIOOjrg25KYHLZHaqcet1wfhHow6\n"
"Uehc6QTuWgOWFhJnfiXzYgen2o8lnLixxZozhk7Lm7Aix9ur2ckXdQ2Wgny4xw70\n"
"JW84Hapnd8oFUD98XXrExk4VFuIcA8qo7r7y18II6wx4Cw1suKru6bhW65cM/y51\n"
"KC4lB7VkvuoJCelRFdM1PfKZLv2tJP63oAqJrQIDAQABAoIBAQCWc38PEqw3avqU\n"
"UMAEaoNa0bq1Gd8/Nq8WqVnbRSFKHO2pk+cWIb1W6BITuwvgcGKesezdEV4s7apK\n"
"9I7/U1hEm2Ep50mrwRh0KZM1nD9Fmharn851Bt//D4qpMytT2caS1yADI8NKpZJ1\n"
"8VZh7+cT4qG+txHUaAIRgbw3VrBWvTIMu6SOSOZm+e3eOr5UU3du1KvjdJHJ2c2k\n"
"TceHvUdKxV7OYt+BBSN1oBOhs3ajUSRge1v3twRDg3cmbwG0DeXvwHNhGUTcF8IH\n"
"JO1RF5njbkFvyqdAi3ltjU41zYd4OMuPtrwzFOtxUjKT62Soz109HUXXE2CGKFPZ\n"
"PVi5/BIhAoGBANN1xqS5BgHszIB0nXbw5ImYpTRmyhO0KsTblBT9+8Q/B7BCK7bM\n"
"zl+dOPeyvEadSwE7RSMMt6CAlTakWIf3Quw/VZajvXy9C9/LHf52pEKXjxMFMPKE\n"
"aGLHpQnwMtDi8/H8AEAXxI3hpxB2KVR7sAYHWihSGjRJ6oPGvEmKEkb5AoGBAMR6\n"
"G2PKz0xk1vFrjfjSY+y13gH/t7xHaXUggjggUSGKaknQh2BDUllXjadeI0fi1eLW\n"
"r98ZImZZgntAgjaIZ4bAlooTDk4gRHaz9jI+z8lsRwOKnWdiigM7txiXZTMVwMqj\n"
"o5mMNGMA+A+ACkTViRHmkDI7S/9FqAvnbOqVwgFVAoGBALUcY6WDvwx5B3Jh7tgH\n"
"XIYpEh3+h8c2gYcX1g3gtvkPTwN8uToY0gz8eOVV1YHZiHsmi4GIi+HRH3usaRMT\n"
"COOVHzYlSc8Dj57+tdLTRL6wVl9hC9o647ju64DGlI9qQquYPZKniLZIdbFYsu9j\n"
"/JA9Tc/I+h6czFpPJccKlbrpAoGAAPWXrKUQ3g6f/g3IY66jTkSVEO1uuDyhBzFh\n"
"cWS3ALLsUe/yuUWa4VTMHEUZZwB0iucBdNVqlZVaTb/C4wFHgCDwmzv8leUScIHw\n"
"cc5ctV8R+bJzkk2o3tsrybLzi4xPpK2n3tgQaWtXyruVUUC5qpy1l4kylcyBRY2b\n"
"uomAqQECgYAiCNWtuWIDlRBcvtIB+kHguzcoFT3vTCCNhalTEn0zi/tbi+voQgVJ\n"
"SDJNptZv+6vRwQ/HfcQtljKIPO6hUZPYaFWRNhgbh7Ay85lRXYXQOottE8ayReBk\n"
"zZb0fl853Qah4DPsaOugAvhjjKeBmKg6bFWO1z6hj18I3UpDf2YnVQ==\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEpQIBAAKCAQEAssO0r37mSJNAkc/ISwXBsu9JjyLeWlsHPAhylQGkSAdp2rjz\n"
"E6AT0Eh3wrocNO31I4pvHReAuh1QedGY6T1cQwO/WAAhQtRCBQDK12qWRgfbC11y\n"
"Xu7zNYPd1Z7YIRy+FxhbL5f+lv3rEUv0HUG5c3CWhLtbANKg+jOieIDzA4Yp1s55\n"
"ynodQBUkTZrwQiT0P8yDSjiasf+clgJRfA1k2XK12KSAMRgyDuPTE4OtBxBvUM3L\n"
"Zvxs81PsmcOuAG4DLaFTg2a/QkCjt2VC1SYYuh/LVxpL41FFh3eMoK5g5deHkgRe\n"
"tlywKjAHIDJu/qgNzNgNW7ymwn2CfBvry9h0/wIDAQABAoIBAEMZ4wDdCWPEokAZ\n"
"Vn2Ss5qO53WrCPuxn42RPjFgZGIFJl7LfbKoK8fK6+lUIrJbf+DPXdX1tIQn7MVN\n"
"P7CNL8yX44MMyW9kbUOjgIBLqgyvdjFV6lBoMTKtRN+iuE31lATnR5Md4pqaxVnA\n"
"wOkaepoycM1x5j7w0SwZparF/HIdkYv0y/MysqT9ByupPA4Fqp/iRSrosHXahNtI\n"
"KZYj1TyERYtuDXq91P4dr/pWq3FmDNI8O3upblkL0YouvG/ZlFLdiNy77XbAyWcX\n"
"ps3YDddM+vECnXO3+sa3ZxgBYvXJdWrrIzM5A+jCkDRZQGsFAzK5I5/S7C2ljt6i\n"
"SmzqvMECgYEA16bGy2XTi6KBPb8aev/OBgK9XuGLwUqK1m15mS9Y2qPHmuc22qaZ\n"
"hw6zginPFrxAEtQWKanhZy4aVqlLkDPLwRnyeuMo1EZAc5B1gZ5ViSAKxBq99hA9\n"
"eqyakdb+IUQsEnRDxSc2gqUQ0EagksUyw5wGG5Q/CVEALmS/r1SU3KUCgYEA1DYf\n"
"6JYdzuRtule3vYeWXKf8sOJpdplgWV7tvLrKkQhdE564uwMCYB23HvYfwWqEdDYG\n"
"fsYg/ur/stk9MDZ3wZKffTEM8V3sX1t1JXnC3ogSAgMGhLZ3ILOLqkoO4BEZJnsS\n"
"dMdiNijlAtQkqs/BO/UVUAKysCtKP3v/+1775dMCgYEAvLjGFjApfnSbV/cK7IM6\n"
"wEXbhdIqZOCgOeEaXjVyM/zKbMRVW+oaR3hVHd8KzSG3jQKv1oxFpu9Qu3ByoWLC\n"
"uF3Ft0debs6ADuJoAyQWROeWpGGmxlUWCGpO5rxYL7KiQxAeUsXrTU+5NBvq4CbV\n"
"MxwyuCX3OGb7mp4upfiGQcUCgYEAuhVsDYv1P4LXJVvd5viKRV2ZG5KuYC1Ga5fu\n"
"aFxzXJI07At2eaa94oKsHR494mEBHNZzA5/BN0fiSHZuTWS1xqxH5oOokc6Gg2ez\n"
"ZdVLp88x20nD4YQPGkHW6tBeEuVrZG7vVC+yU0Ow7bYRISdkjqrusWZsQkbzqI+X\n"
"fFliEbkCgYEAu8x+47M1ordbI7NmbBGyiyP0r7nMRCZ+KEvGeCNYracWmsnCNnfV\n"
"zR2UzmwtSainw3Ho8Jv/rWDC8RIDauyBRYEi2VqOnUzT2ca0iymQyLeBCudAQuio\n"
"drOu4JU8RzZ3Ad6V3DNFnaqmX/7GA9Pa2GI8NJMyb8p1GAGv7Gi8nxc=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEAt01S8JuEwWy/Hzb90yO2O7oGWq3GfvfDpFOF4OQnwG3kQ/BP\n"
"4MoPDCYHdqb3iI9aD3vykZA6Q8zpdfGwjm4+bHrgRdiSmZWv8NvRwuQ5Ji9xbiGn\n"
"hA1XwqH9hvgFTiy6tRvirWSJ7kzH3Q/bEGpCbHUQkwMog4v6yCNKNrjlwjN++eCi\n"
"gFK/0RMOJMLOs8BD3zY+lKjd/pd8LBRujkMyUF5SryeRueAFjD2sq4OXq8DPABGt\n"
"zdR6vbTcsi4JwP1Q6y4x0/LIWEprzzewNU63I5E2zj0WnoRGAIM4aF+VuqcHjWUx\n"
"VWnyLZldSen6lScZ4xj4seitiDbSFvtFkDF6VwIDAQABAoIBAGTP9im2ntDyyjqU\n"
"uA0DuxomOZBtupniEouyFBOX5/UBe2WSKZxsBNKdp8UuFz3X+aRCeyprtF/NtyjT\n"
"AFOVdmebPPWtIxOtK9LAUyFo+7VwqmXzxHnwDLBS/2jXx7MzDozFBWpvvRx+xf1i\n"
"1wy0JEwaJj90oTeYKRkhr5NhJZwkX8zCNYaemBd3kHB3aGWGJasI1Y81UezeRKCn\n"
"hSbn2CrWalI7pyJ4lsavM11nIq1Eu2ZthJiNCMghbYrHoBHd+iVWiCYchP2rNEWV\n"
"sdHtaVHtQ9zdZ43bao3OzPu7lAjd6UAbxsuhUe+a2YdDz/+Up+6+BvQf1FCfYIjW\n"
"KFUdCoECgYEA4t5O+u0V9gkMUhKsevYb0zgc7O/mo8ivN+V++EpAtL0mhiwxeO8p\n"
"oef0szLyhdULQeLN9pJQDCeAbkGdwIe3L+AKU8o8BFGEWLFysZjMg9In/UTrp5MN\n"
"mMDy2SRKKu5BqsvdYH302xpZfHq1T2cMNDWE8lrZffduH06Cgq/XEtECgYEAztbj\n"
"bhFneADnrvk609VnOQvoQEjySeCQKFQFRRI6k/FguqMisL2IRXnMaWammosdeCAg\n"
"m7eZchnszHIst9cwZUKXUFqmAqeDuWSNdTI7uKZH6nT/A6IDlgdjaHsqhvpK0Ac9\n"
"ngycdHONitOZh0ZG74pdWjf828Dwzf+CuYjl9KcCgYEAmIvI6ZqvkJ8m5Kzfw1Jn\n"
"BVCOypbJK8oOX3R2Orea6KzjEYb3wQx3nwFcHX6danYFOskpmqlpH7MT/Y8rZsEa\n"
"4RsxdoPedTzm08iFiXtn0R9nejp0hlov402iPXXUVSedih3IflBTa1w9XaEY9wog\n"
"P57ZBSknYzcTmgNtaDiaUnECgYA5sWauhNw/dMEq5QmrnJK2LsQRakdqo+CR3x25\n"
"LmR4b5Nze51pfvRLrLV/kMpXwQXvQ8bUqFl8og6S2CXxAWzWUcSy/RXhF6h+RbXP\n"
"Qru1vWvB0fBvqvklF9p6giBSle3YKKzfMNVTBggs+OiR+uA+YHG5gHRfN2nzi5mC\n"
"9tRtcQKBgBnDSi4lRCjRe9pPnyAYaa4iyBUGhjPysScSLY9orel89+qmTBQ/Py6J\n"
"0+sefL4ZJaOsuaR2mSSPP/lbSkF9DMFs4tHbBqY+WkVNYLshAkauHwqv26HTVCSd\n"
"QKzeb7uZw9lNaRIzDvy/3wfCLvXfdDozPFrOUgkyaBN5pJSA/4sv\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEogIBAAKCAQEA9qtiDoJWqU/eSlpj381eG6UcDzfMguFh/q4e4s7QVdRYj5J0\n"
"Msv0PCkti8JHuvQUyncRpOPccBkhNbVjNbjIgw1pHaIZNdVotUDhP0kseRyJ6z3M\n"
"qbZ5qKn+0mHjVjPNItVDDe6tebYMT1BZpVyRrCOqY2v5z1ecLC+ReygmHgDpzg+L\n"
"0rWfIxGT10IPZ8pAlcdEn6xt5aEhi7mPCX/xwqfQChPIJz6zVLEC8UaPtvDBohPR\n"
"6NQTBTeZZAAtzrQ7+oNxfz1v6Fz6RwMei7Q+qOBnMiwpQmbcDBKABM2RnXSpD0LA\n"
"1GR7/+CiV1HQoShWVvEwrSIlM6jVAJo6iqF6WQIDAQABAoIBAHqwcdxPnfUm4aTP\n"
"4r9NcZKEhDlZgqJSoiA/0OL1BRC7xrTanmspoLhPrvTF1FG715+Aq8j9AQbMqQUC\n"
"zG7LEwiEIhV4K9vn4uXMeHy206UFud/E5EhBl695pmJUB/Q3XcAGnQyP+77++o50\n"
"o7IpIdeiAbzj1uP3aplbq5u7M4JV7fUZWA/368G4HolqFTxcAfBJ05GXlp97BBwY\n"
"AnY3/pNrKMz0NiPf3nsJHYWK18up0JCLPL3tomc94wuNZ66spIazHIL9aaKY0q3V\n"
"LkBrelndfYM1m4xRTnSOy6STu0qKTPOpX0C8XBLYs6uiXjRsChqSYwndCCeASaH3\n"
"LGNIcbUCgYEA/m4qvt8tdT4wEvnE+QUxEELmBtT4UFa3NnQISrzNlhNeI0Zd2xlp\n"
"SG0/pcw83mG2uX+V5xSaWL5LYfLBkvy83Y0yIWgYbbIkyyCOUZnTpwaDGU/FjWip\n"
"3TfXf5qpAgiez94sV+MsFpKfG05yxJh5u+3sIyGTVUAxp0HPx4LVgbMCgYEA+DD1\n"
"fu6ttpuV1UMrsFdjuk6gBvSbyJ9OilY2jT+yE7hSRc/yP3O9ikuR74tNlVrWTnO2\n"
"0kcYbyLJXE2cGUC2q5e4r8TDGiozNfQ7/OC2M3XaJ+xJk4zMf/8PuDDpWr+18ZXA\n"
"Pf+ibXWTFvZ6ZeUmpbrrfCrXdvmIZnwVuOI0FcMCgYAZn26emksxq3mb75tumJ9A\n"
"S/xuY7Q+Iv2Adl7/Z9QscPbiBowdLIn1yUrHn7Hhk2WbeMXX57NDjKZ6zr+/1cQP\n"
"a9DInHsZUP9zlWu/vAYcpAM/4VC71PaGWMFTEHhExCl6NZ2xnCcsfseXMGdOdSyN\n"
"SICnaRI1W6mkdnQ+W2a1EQKBgGEKA3KVr6XuPy8bDEHuaTe29irCCQbwAq1j+ABS\n"
"HzZGoyRYocbdYgZoda7LMJJs6c3SwHCHC66oU0KbtaTKAKImuDdBH2djiJJX4/yD\n"
"f7mvIpTpdfsS2gJRn7vMo/CvdFv4ySl0gfV6OwCHbmPYrLuv0dLCjWwfNI2dhoC7\n"
"MNIxAoGAIPSIG4BrShzbeX4c2L18iwIg+NlOcUbtl0Ccr1t6uLGI+ge/6I6T/5XH\n"
"DPKqYIf0IRYV8suxpfQNKiz/C0NPffA1d1M2hvuAg2v09o2cSwvdcQwdmakKZ5bl\n"
"sdCuYKdCIwomEUOz/4XgQrJl4XDUqxftJT6/egAjWvcIYvfNCsY=\n"
"-----END RSA PRIVATE KEY-----\n",
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEA1yHZMsgRLckL+v6rgpGq9qmxVBNDxeuul1V/QlFyOlcAk5n/\n"
"uduTalSqGQhc4NEePMxq6nFui4ucpkZOozmcEnhV0N9jld9IB9rLGt4erdg7RKl9\n"
"+gQ+zTn69j69U36E2I47H4dM69uxeSOyWP2Odxpw+biisa3o8mMz1zCmuj4GMDtG\n"
"DlnSpthFzgQR6N1pbvxLXrWg5F16GqFiJOD7kXDfy4/l6kB/mDs1T/3r8kav6DqR\n"
"c/t3aQZxgWGIpI7hc9Qgvp7coZRMey5dNOZEna3tqS8dn2tZlhkpYV5uyFUjmxjG\n"
"TERSULQ7hvUqW+eshGGsnxFtL7ANnTSc4xECowIDAQABAoIBAFhJJMhpQFuIySjd\n"
"AGeZ/g4x/3rgWQzNNp4WUR5XLEhy0eLA7ShJywp06kVRoEQGraEHxsyldldAGS5H\n"
"ZhgoGTufNKB+PHER646FpJpHE1IGjfQUloVW3qr8I1iQ0MOGBWCVpf+/V7rnMsLi\n"
"+lr421FXgYuJ0QKXuyRVv72M0q9U6i+ml3aVAhgW/19oFg+dW7YccX+9iVyD05Q5\n"
"KR64tX8xd4wrAqfAgYA3erbbE6GTyHYD5K54kIgfRr/+pIU4qc1L7XOCblnqc/rI\n"
"BilFysEC634r2MNe66uQvNui4oQTfBcFFlXg0zAmp7d5QE0ApOL6HpCsmbImm2uJ\n"
"sdFNYyECgYEA716kfEv7HfnF0P3pAP2AOuEsW6t8q0UtWvnHrwRQXQw8Yv90g7kD\n"
"pUV3/BjD9VQgsQZosbdSn5wbT4j7dypRdrzYk+8m/hBk4Q8M/tWoRGVOn46NudvK\n"
"/KX0A4ODLuulj8yAZVc7CM5Cdy4GCGJBVO+oVvBUAnHxfZziOyqBw9MCgYEA5hQg\n"
"HEORzdxvbbfAx1ggvH1Eg1lqRhmpI43PpRkaoqb8jLwXb2CyBeuv3RBft/X2Tr6F\n"
"mHpe0U1kN/5YEjii/Q/jUX8azIHaUNNSAjrriEeMQZOqFxmhCdiyeXuqg2fbFbhe\n"
"K3Q6/fsB1xj9OOSwyPMqm/M5U0LsoGjmg8TFE/ECgYAlImKUIdlwOgp1NJ7MF4eo\n"
"Gryd8AmkLFQv8+YFgb7R4I8RsJ2rva0SG6fUhScJTSbRL7RYNZ9swXP/L7oLL5Z5\n"
"vCxBLu22pmZv/7y9X/n9ulWrLRtRhQaFkV08mk9knQwPNeOJVTIEWLM49/vZmxyV\n"
"h6Ru8FOoGXMkUI1MLnj5HwKBgGJLkNhiacVYeuaWDa9c0EeXARFYvxWJ2wAMkvzG\n"
"9+ErlFQP+7ciyYvMAItidnJii8NilDLrfNzQwpNFf5zxQ3j4M7bapblfdMT5M10u\n"
"jPfhEWPm0VEjKvDI+p76HYQcd7YU2W6ZLqbZeRTLYUvQMFL5yGduBzyyJ+P0TR9Y\n"
"jpYRAoGBAM7vYGTprw4w2tTZPFICXVk1bQ0LO06oNRtwkiQTUT6UqPjWMFyvHnmN\n"
"11SVVBmRZ0RAk6e5eZLFX8WelJ4J4nSOGRcJheCtoEFlO7D1ewAUSbqWJ0pBqp2T\n"
"gV4oCS8LYe8zReVoYZJjuLwoHvxZzs/hUjc3SI2HRW2W/HQRPC25\n"
"-----END RSA PRIVATE KEY-----\n"
};
#define N_PREGEN_KEYS_1024 ARRAY_LENGTH(PREGEN_KEYS_1024)
static crypto_pk_t *pregen_keys_1024[N_PREGEN_KEYS_1024];
static int next_key_idx_1024;
#define N_PREGEN_KEYS_2048 ARRAY_LENGTH(PREGEN_KEYS_2048)
static crypto_pk_t *pregen_keys_2048[N_PREGEN_KEYS_2048];
static int next_key_idx_2048;
#endif
/** Generate and return a new keypair for use in unit tests. If we're using
* the key cache optimization, we might reuse keys. "idx" is ignored.
* Our only guarantee is that we won't reuse a key till this function has been
* called several times. The order in which keys are returned is slightly
* randomized, so that tests that depend on a particular order will not be
* reliable. */
static crypto_pk_t *
pk_generate_internal(int bits)
{
tor_assert(bits == 2048 || bits == 1024);
#ifdef USE_PREGENERATED_RSA_KEYS
int *idxp;
int n_pregen;
crypto_pk_t **pregen_array;
if (bits == 2048) {
idxp = &next_key_idx_2048;
n_pregen = N_PREGEN_KEYS_2048;
pregen_array = pregen_keys_2048;
} else {
idxp = &next_key_idx_1024;
n_pregen = N_PREGEN_KEYS_1024;
pregen_array = pregen_keys_1024;
}
/* Either skip 1 or 2 keys. */
*idxp += crypto_rand_int_range(1,3);
*idxp %= n_pregen;
return crypto_pk_dup_key(pregen_array[*idxp]);
#else
crypto_pk_t *result;
int res;
result = crypto_pk_new();
res = crypto_pk_generate_key_with_bits__real(result, bits);
tor_assert(!res);
return result;
#endif
}
crypto_pk_t *
pk_generate(int idx)
{
(void) idx;
return pk_generate_internal(1024);
}
#ifdef USE_PREGENERATED_RSA_KEYS
static int
crypto_pk_generate_key_with_bits__get_cached(crypto_pk_t *env, int bits)
{
if (bits == 1024 || bits == 2048) {
crypto_pk_t *newkey = pk_generate_internal(bits);
crypto_pk_assign_(env, newkey);
crypto_pk_free(newkey);
} else {
return crypto_pk_generate_key_with_bits__real(env, bits);
}
return 0;
}
#endif
/** Free all storage used for the cached key optimization. */
void
free_pregenerated_keys(void)
{
#ifdef USE_PREGENERATED_RSA_KEYS
unsigned idx;
for (idx = 0; idx < N_PREGEN_KEYS_1024; ++idx) {
if (pregen_keys_1024[idx]) {
crypto_pk_free(pregen_keys_1024[idx]);
pregen_keys_1024[idx] = NULL;
}
}
for (idx = 0; idx < N_PREGEN_KEYS_2048; ++idx) {
if (pregen_keys_2048[idx]) {
crypto_pk_free(pregen_keys_2048[idx]);
pregen_keys_2048[idx] = NULL;
}
}
#endif
}
void
init_pregenerated_keys(void)
{
#ifdef USE_PREGENERATED_RSA_KEYS
const char *s;
crypto_pk_t *pk;
unsigned i;
for (i = 0; i < N_PREGEN_KEYS_1024; ++i) {
pk = pregen_keys_1024[i] = crypto_pk_new();
s = PREGEN_KEYS_1024[i];
int r = crypto_pk_read_private_key_from_string(pk, s, strlen(s));
tor_assert(r == 0);
}
for (i = 0; i < N_PREGEN_KEYS_2048; ++i) {
pk = pregen_keys_2048[i] = crypto_pk_new();
s = PREGEN_KEYS_2048[i];
int r = crypto_pk_read_private_key_from_string(pk, s, strlen(s));
tor_assert(r == 0);
}
MOCK(crypto_pk_generate_key_with_bits,
crypto_pk_generate_key_with_bits__get_cached);
#endif
}