diff options
-rw-r--r-- | src/or/channeltls.c | 90 | ||||
-rw-r--r-- | src/or/connection_or.c | 10 | ||||
-rw-r--r-- | src/or/or.h | 27 | ||||
-rw-r--r-- | src/or/torcert.c | 150 | ||||
-rw-r--r-- | src/or/torcert.h | 10 |
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 |