diff options
author | Nick Mathewson <nickm@torproject.org> | 2017-06-05 15:44:12 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2017-06-05 15:44:12 -0400 |
commit | d1c1dc229e189cbf4e463b82751af007801a02eb (patch) | |
tree | f4600f4663e62b0466c01da56dd3df6edccb2bb8 | |
parent | 7c54d2f3f0bcf483fd14dedb1a5dcbece6976411 (diff) | |
parent | 9fea00928cb680f550a5ea9c64227efc025ea69b (diff) | |
download | tor-d1c1dc229e189cbf4e463b82751af007801a02eb.tar.gz tor-d1c1dc229e189cbf4e463b82751af007801a02eb.zip |
Merge branch 'maint-0.2.9' into maint-0.3.0
-rw-r--r-- | changes/bug22460_case2 | 8 | ||||
-rw-r--r-- | src/common/tortls.c | 27 | ||||
-rw-r--r-- | src/common/tortls.h | 1 | ||||
-rw-r--r-- | src/or/connection_or.c | 32 | ||||
-rw-r--r-- | src/test/test_link_handshake.c | 30 |
5 files changed, 80 insertions, 18 deletions
diff --git a/changes/bug22460_case2 b/changes/bug22460_case2 new file mode 100644 index 0000000000..0a11759832 --- /dev/null +++ b/changes/bug22460_case2 @@ -0,0 +1,8 @@ + o Major bugfixes (relay, link handshake): + + - When performing the v3 link handshake on a TLS connection, report that + we have the x509 certificate that we actually used on that connection, + even if we have changed certificates since that connection was first + opened. Previously, we would claim to have used our most recent x509 + link certificate, which would sometimes make the link handshake fail. + Fixes one case of bug 22460; bugfix on 0.2.3.6-alpha. diff --git a/src/common/tortls.c b/src/common/tortls.c index 1594f3be00..e3e8830b3e 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -704,11 +704,13 @@ MOCK_IMPL(STATIC tor_x509_cert_t *, return cert; } -/** Return a copy of <b>cert</b> */ +/** Return a new 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)); + tor_assert(cert); + X509 *x509 = cert->cert; + return tor_x509_cert_new(X509_dup(x509)); } /** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>, @@ -2046,7 +2048,8 @@ tor_tls_peer_has_cert(tor_tls_t *tls) return 1; } -/** Return the peer certificate, or NULL if there isn't one. */ +/** Return a newly allocated copy of the peer certificate, or NULL if there + * isn't one. */ MOCK_IMPL(tor_x509_cert_t *, tor_tls_get_peer_cert,(tor_tls_t *tls)) { @@ -2058,6 +2061,24 @@ tor_tls_get_peer_cert,(tor_tls_t *tls)) return tor_x509_cert_new(cert); } +/** Return a newly allocated copy of the cerficate we used on the connection, + * or NULL if somehow we didn't use one. */ +MOCK_IMPL(tor_x509_cert_t *, +tor_tls_get_own_cert,(tor_tls_t *tls)) +{ + X509 *cert = SSL_get_certificate(tls->ssl); + tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, + "getting own-connection certificate"); + if (!cert) + return NULL; + /* Fun inconsistency: SSL_get_peer_certificate increments the reference + * count, but SSL_get_certificate does not. */ + X509 *duplicate = X509_dup(cert); + if (BUG(duplicate == NULL)) + return NULL; + return tor_x509_cert_new(duplicate); +} + /** Warn that a certificate lifetime extends through a certain range. */ static void log_cert_lifetime(int severity, const X509 *cert, const char *problem, diff --git a/src/common/tortls.h b/src/common/tortls.h index 6510fdbe64..bb7701cc4b 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -199,6 +199,7 @@ int tor_tls_is_server(tor_tls_t *tls); void tor_tls_free(tor_tls_t *tls); int tor_tls_peer_has_cert(tor_tls_t *tls); MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls)); +MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_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, time_t now, diff --git a/src/or/connection_or.c b/src/or/connection_or.c index cefe42c4db..b9ac9b2c5d 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -2270,7 +2270,8 @@ add_ed25519_cert(certs_cell_t *certs_cell, int connection_or_send_certs_cell(or_connection_t *conn) { - const tor_x509_cert_t *link_cert = NULL, *id_cert = NULL; + const tor_x509_cert_t *global_link_cert = NULL, *id_cert = NULL; + tor_x509_cert_t *own_link_cert = NULL; var_cell_t *cell; certs_cell_t *certs_cell = NULL; @@ -2283,21 +2284,26 @@ connection_or_send_certs_cell(or_connection_t *conn) 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) + if (tor_tls_get_my_certs(conn_in_server_mode, + &global_link_cert, &id_cert) < 0) return -1; - tor_assert(link_cert); + if (conn_in_server_mode) { + own_link_cert = tor_tls_get_own_cert(conn->tls); + } tor_assert(id_cert); certs_cell = certs_cell_new(); /* Start adding certs. First the link cert or auth1024 cert. */ if (conn_in_server_mode) { + tor_assert_nonfatal(own_link_cert); add_x509_cert(certs_cell, - OR_CERT_TYPE_TLS_LINK, link_cert); + OR_CERT_TYPE_TLS_LINK, own_link_cert); } else { + tor_assert(global_link_cert); add_x509_cert(certs_cell, - OR_CERT_TYPE_AUTH_1024, link_cert); + OR_CERT_TYPE_AUTH_1024, global_link_cert); } /* Next the RSA->RSA ID cert */ @@ -2344,6 +2350,7 @@ connection_or_send_certs_cell(or_connection_t *conn) connection_or_write_var_cell_to_buf(cell, conn); var_cell_free(cell); certs_cell_free(certs_cell); + tor_x509_cert_free(own_link_cert); return 0; } @@ -2484,10 +2491,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn, memcpy(auth1_getarray_type(auth), authtype_str, 8); { - const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL; + const tor_x509_cert_t *id_cert=NULL; const common_digests_t *my_digests, *their_digests; const uint8_t *my_id, *their_id, *client_id, *server_id; - if (tor_tls_get_my_certs(server, &link_cert, &id_cert)) + if (tor_tls_get_my_certs(server, NULL, &id_cert)) goto err; my_digests = tor_x509_cert_get_id_digests(id_cert); their_digests = @@ -2542,13 +2549,11 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn, { /* Digest of cert used on TLS link : 32 octets. */ - const tor_x509_cert_t *cert = NULL; - tor_x509_cert_t *freecert = NULL; + tor_x509_cert_t *cert = NULL; if (server) { - tor_tls_get_my_certs(1, &cert, NULL); + cert = tor_tls_get_own_cert(conn->tls); } else { - freecert = tor_tls_get_peer_cert(conn->tls); - cert = freecert; + cert = tor_tls_get_peer_cert(conn->tls); } if (!cert) { log_warn(LD_OR, "Unable to find cert when making %s data.", @@ -2559,8 +2564,7 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn, memcpy(auth->scert, tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32); - if (freecert) - tor_x509_cert_free(freecert); + tor_x509_cert_free(cert); } /* HMAC of clientrandom and serverrandom using master key : 32 octets */ diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 421f3aaedf..b3e854ef76 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -59,7 +59,7 @@ mock_get_peer_cert(tor_tls_t *tls) if (mock_peer_cert_expect_tortls && mock_peer_cert_expect_tortls != tls) return NULL; - return mock_peer_cert; + return tor_x509_cert_dup(mock_peer_cert); } static int mock_send_netinfo_called = 0; @@ -105,6 +105,14 @@ mock_export_key_material(tor_tls_t *tls, uint8_t *secrets_out, return 0; } +static tor_x509_cert_t *mock_own_cert = NULL; +static tor_x509_cert_t * +mock_get_own_cert(tor_tls_t *tls) +{ + (void)tls; + return tor_x509_cert_dup(mock_own_cert); +} + /* Test good certs cells */ static void test_link_handshake_certs_ok(void *arg) @@ -126,6 +134,7 @@ test_link_handshake_certs_ok(void *arg) MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell); MOCK(connection_or_send_netinfo, mock_send_netinfo); MOCK(tor_tls_get_peer_cert, mock_get_peer_cert); + MOCK(tor_tls_get_own_cert, mock_get_own_cert); key1 = pk_generate(2); key2 = pk_generate(3); @@ -143,6 +152,12 @@ test_link_handshake_certs_ok(void *arg) } /* c1 has started_here == 1 */ + { + const tor_x509_cert_t *link = NULL; + tt_assert(!tor_tls_get_my_certs(1, &link, NULL)); + mock_own_cert = tor_x509_cert_dup(link); + } + c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3; c1->link_proto = 3; tt_int_op(connection_init_or_handshake_state(c1, 1), ==, 0); @@ -285,6 +300,9 @@ test_link_handshake_certs_ok(void *arg) UNMOCK(connection_or_write_var_cell_to_buf); UNMOCK(connection_or_send_netinfo); UNMOCK(tor_tls_get_peer_cert); + UNMOCK(tor_tls_get_own_cert); + tor_x509_cert_free(mock_own_cert); + mock_own_cert = NULL; memset(c1->identity_digest, 0, sizeof(c1->identity_digest)); memset(c2->identity_digest, 0, sizeof(c2->identity_digest)); connection_free_(TO_CONN(c1)); @@ -322,6 +340,7 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj) UNMOCK(connection_or_send_netinfo); UNMOCK(connection_or_close_for_error); UNMOCK(tor_tls_get_peer_cert); + UNMOCK(tor_tls_get_own_cert); if (d) { tor_free(d->cell); @@ -1130,6 +1149,7 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg) (void) test; UNMOCK(connection_or_write_var_cell_to_buf); UNMOCK(tor_tls_get_peer_cert); + UNMOCK(tor_tls_get_own_cert); UNMOCK(tor_tls_get_tlssecrets); UNMOCK(connection_or_close_for_error); UNMOCK(channel_set_circid_type); @@ -1147,7 +1167,11 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg) crypto_pk_free(d->key2); tor_free(d); } + tor_x509_cert_free(mock_peer_cert); + tor_x509_cert_free(mock_own_cert); mock_peer_cert = NULL; + mock_own_cert = NULL; + return 1; } @@ -1161,6 +1185,7 @@ authenticate_data_setup(const struct testcase_t *test) MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell); MOCK(tor_tls_get_peer_cert, mock_get_peer_cert); + MOCK(tor_tls_get_own_cert, mock_get_own_cert); MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets); MOCK(connection_or_close_for_error, mock_close_for_err); MOCK(channel_set_circid_type, mock_set_circid_type); @@ -1227,6 +1252,9 @@ authenticate_data_setup(const struct testcase_t *test) mock_peer_cert = tor_x509_cert_decode(der, sz); tt_assert(mock_peer_cert); + mock_own_cert = tor_x509_cert_decode(der, sz); + tt_assert(mock_own_cert); + /* Make an authenticate cell ... */ int authtype; if (is_ed) |