diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c index 0b83b2d0a5..d4116d47ab 100644 --- a/src/core/crypto/relay_crypto.c +++ b/src/core/crypto/relay_crypto.c @@ -142,6 +142,13 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, if (relay_digest_matches(thishop->crypto.b_digest, cell)) { *recognized = 1; *layer_hint = thishop; + /* Keep current digest of this cell for the possible SENDME. */ + if (thishop->crypto.sendme_digest) { + crypto_digest_free(thishop->crypto.sendme_digest); + } + thishop->crypto.sendme_digest = + crypto_digest_dup(thishop->crypto.b_digest); + return 0; } } @@ -212,6 +219,11 @@ relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ) { relay_set_digest(or_circ->crypto.b_digest, cell); + /* Keep a record of this cell, we might use it for validating the SENDME. */ + if (or_circ->crypto.sendme_digest) { + crypto_digest_free(or_circ->crypto.sendme_digest); + } + or_circ->crypto.sendme_digest = crypto_digest_dup(or_circ->crypto.b_digest); /* encrypt one layer */ relay_crypt_one_payload(or_circ->crypto.b_crypto, cell->payload); } @@ -229,6 +241,7 @@ relay_crypto_clear(relay_crypto_t *crypto) crypto_cipher_free(crypto->b_crypto); crypto_digest_free(crypto->f_digest); crypto_digest_free(crypto->b_digest); + crypto_digest_free(crypto->sendme_digest); } /** Initialize crypto from the key material in key_data. diff --git a/src/core/or/relay.c b/src/core/or/relay.c index b26360b245..47275a811e 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -1568,7 +1568,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } /* Consider sending a circuit-level SENDME cell. */ - sendme_circuit_consider_sending(circ, layer_hint, NULL); + sendme_circuit_consider_sending(circ, layer_hint); if (rh.stream_id == 0) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Relay data cell with zero " diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h index dafce257c7..dbdf1599dc 100644 --- a/src/core/or/relay_crypto_st.h +++ b/src/core/or/relay_crypto_st.h @@ -25,6 +25,8 @@ struct relay_crypto_t { /** Digest state for cells heading away from the OR at this step. */ struct crypto_digest_t *b_digest; + /** Digest used for the next SENDME cell if any. */ + struct crypto_digest_t *sendme_digest; }; #undef crypto_cipher_t diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c index afade43f74..76f551a929 100644 --- a/src/core/or/sendme.c +++ b/src/core/or/sendme.c @@ -14,6 +14,7 @@ #include "core/or/cell_st.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" +#include "core/or/or_circuit_st.h" #include "core/or/relay.h" #include "core/or/sendme.h" #include "feature/nodelist/networkstatus.h" @@ -342,18 +343,20 @@ sendme_connection_edge_consider_sending(edge_connection_t *conn) * more. */ void -sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint, - crypto_digest_t *digest) +sendme_circuit_consider_sending(circuit_t *circ, crypt_path_t *layer_hint) { - tor_assert(digest); + crypto_digest_t *digest; while ((layer_hint ? layer_hint->deliver_window : circ->deliver_window) <= CIRCWINDOW_START - CIRCWINDOW_INCREMENT) { log_debug(LD_CIRC,"Queuing circuit sendme."); - if (layer_hint) + if (layer_hint) { layer_hint->deliver_window += CIRCWINDOW_INCREMENT; - else + digest = layer_hint->crypto.sendme_digest; + } else { circ->deliver_window += CIRCWINDOW_INCREMENT; + digest = TO_OR_CIRCUIT(circ)->crypto.sendme_digest; + } if (send_circuit_level_sendme(circ, layer_hint, digest) < 0) { return; /* The circuit's closed, don't continue */ } @@ -557,9 +560,16 @@ sendme_note_cell_digest(circuit_t *circ) return; } - digest = tor_malloc_zero(4); - if (circ->sendme_last_digests == NULL) { - circ->sendme_last_digests = smartlist_new(); + /* Only note the digest if we actually have the digest of the previous cell + * recorded. It should never happen in theory as we always record the last + * digest for the v1 SENDME. */ + if (TO_OR_CIRCUIT(circ)->crypto.sendme_digest) { + digest = tor_malloc_zero(4); + crypto_digest_get_digest(TO_OR_CIRCUIT(circ)->crypto.sendme_digest, + (char *) digest, 4); + if (circ->sendme_last_digests == NULL) { + circ->sendme_last_digests = smartlist_new(); + } + smartlist_add(circ->sendme_last_digests, digest); } - smartlist_add(circ->sendme_last_digests, digest); } diff --git a/src/core/or/sendme.h b/src/core/or/sendme.h index 300fb25d96..e7cf718bb1 100644 --- a/src/core/or/sendme.h +++ b/src/core/or/sendme.h @@ -16,8 +16,7 @@ /* Sending SENDME cell. */ void sendme_connection_edge_consider_sending(edge_connection_t *edge_conn); void sendme_circuit_consider_sending(circuit_t *circ, - crypt_path_t *layer_hint, - crypto_digest_t *digest); + crypt_path_t *layer_hint); /* Processing SENDME cell. */ int sendme_process_circuit_level(crypt_path_t *layer_hint,