aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/or/channeltls.c90
-rw-r--r--src/or/connection_or.c10
-rw-r--r--src/or/or.h27
-rw-r--r--src/or/torcert.c150
-rw-r--r--src/or/torcert.h10
5 files changed, 240 insertions, 47 deletions
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index d1fae926d5..6de3bd4732 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -1788,8 +1788,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
* 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;
- rsa_ed_crosscert_t *rsa_crosscert = NULL;
int n_certs, i;
certs_cell_t *cc = NULL;
@@ -1879,38 +1880,45 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
}
break;
}
+
case CERT_ENCODING_RSA_CROSSCERT: {
- rsa_ed_crosscert_t *cc_cert = NULL;
- ssize_t n = rsa_ed_crosscert_parse(&cc_cert, cert_body, cert_len);
- if (n != cert_len) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Received unparseable RS1024-Ed25519 crosscert "
- " in CERTS cell from %s:%d",
- safe_str(chan->conn->base_.address),
- chan->conn->base_.port);
+ if (rsa_ed_cc_cert) {
+ ERR("Duplicate RSA->Ed25519 crosscert");
} else {
- if (rsa_crosscert) {
- rsa_ed_crosscert_free(cc_cert);
- ERR("Duplicate RSA->Ed25519 crosscert");
- } else {
- rsa_crosscert = cc_cert;
- }
+ rsa_ed_cc_cert = tor_memdup(cert_body, cert_len);
+ rsa_ed_cc_cert_len = cert_len;
}
break;
}
}
}
- tor_x509_cert_t *id_cert = x509_certs[OR_CERT_TYPE_ID_1024];
- tor_x509_cert_t *auth_cert = x509_certs[OR_CERT_TYPE_AUTH_1024];
- tor_x509_cert_t *link_cert = x509_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[OR_CERT_TYPE_ID_1024] =
- x509_certs[OR_CERT_TYPE_AUTH_1024] =
- x509_certs[OR_CERT_TYPE_TLS_LINK] = NULL;
+ 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
@@ -1922,11 +1930,17 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
else
severity = LOG_PROTOCOL_WARN;
- if (! or_handshake_certs_rsa_ok(severity,
- chan->conn->handshake_state->certs,
- chan->conn->tls,
- time(NULL)))
- ERR("Invalid RSA certificates!");
+ 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) {
/* No more information is needed. */
@@ -1934,8 +1948,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
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");
@@ -1950,14 +1963,22 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
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_rsa_peer_id,
- NULL) < 0)
+ 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);
+ "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
@@ -1968,8 +1989,9 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
} else {
/* 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? */
@@ -1992,7 +2014,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
for (unsigned u = 0; u < ARRAY_LENGTH(ed_certs); ++u) {
tor_cert_free(ed_certs[u]);
}
- rsa_ed_crosscert_free(rsa_crosscert);
+ tor_free(rsa_ed_cc_cert);
certs_cell_free(cc);
#undef ERR
}
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 9048fde743..b922e97567 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -2391,10 +2391,12 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
if (is_ed) {
const ed25519_public_key_t *my_ed_id, *their_ed_id;
- if (!conn->handshake_state->certs->ed_id_sign_cert)
+ 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_cert->signing_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;
@@ -2500,8 +2502,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
if (ed_signing_key && is_ed) {
ed25519_signature_t sig;
- if (ed25519_sign(&sig, out, len, ed_signing_key) < 0)
+ if (ed25519_sign(&sig, out, len, ed_signing_key) < 0) {
+ log_warn(LD_OR, "Unable to sign ed25519 cert");
goto err;
+ }
auth1_setlen_sig(auth, ED25519_SIG_LEN);
memcpy(auth1_getarray_sig(auth), sig.sig, ED25519_SIG_LEN);
diff --git a/src/or/or.h b/src/or/or.h
index 65d40579cb..e6162c5f32 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1386,17 +1386,32 @@ 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 {
- /** DOCDOC */
+ /** True iff we originated this connection. */
int started_here;
- /** The cert for the key that's supposed to sign the AUTHENTICATE cell */
+ /** 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;
- /** DOCDOC */
+ /** 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 */
+ /** A self-signed identity certificate: the RSA identity key signed
+ * with itself. */
tor_x509_cert_t *id_cert;
- /** DOCDOC */
- struct tor_cert_st *ed_id_sign_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
diff --git a/src/or/torcert.c b/src/or/torcert.c
index ef7775eb9e..cff1ed10c5 100644
--- a/src/or/torcert.c
+++ b/src/or/torcert.c
@@ -420,7 +420,7 @@ or_handshake_certs_new(void)
return tor_malloc_zero(sizeof(or_handshake_certs_t));
}
-/** DODCDOC */
+/** Release all storage held in <b>certs</b> */
void
or_handshake_certs_free(or_handshake_certs_t *certs)
{
@@ -428,8 +428,14 @@ or_handshake_certs_free(or_handshake_certs_t *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);
}
@@ -477,9 +483,145 @@ or_handshake_certs_rsa_ok(int severity,
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(or_handshake_certs_t *certs)
+or_handshake_certs_ed25519_ok(int severity,
+ or_handshake_certs_t *certs,
+ tor_tls_t *tls,
+ time_t now)
{
- (void) certs;
- return 0;
+ 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 signing key");
+ ADDCERT(certs->ed_id_sign, NULL);
+
+ if (certs->started_here) {
+ if (! certs->ed_sign_link)
+ ERR("No link key");
+ {
+ /* check for a match with the TLS cert. */
+ tor_x509_cert_t *peer_cert = tor_tls_get_peer_cert(tls);
+ /* XXXX Does 'cert' match spec in this case? I hope so; if not, fix
+ * spec */
+ if (!peer_cert)
+ ERR("No x509 peer cert");
+ 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 link authentiction 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");
+ }
+ crypto_pk_t *rsa_id_key = tor_tls_cert_get_key(rsa_id_cert);
+
+ 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/missing RSA 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);
+ }
+ }
+
}
diff --git a/src/or/torcert.h b/src/or/torcert.h
index 143a2aa3a0..f7ca0ff521 100644
--- a/src/or/torcert.h
+++ b/src/or/torcert.h
@@ -84,6 +84,16 @@ 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