From d132dd45e3258d4142620e10f5d2d132e792d857 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 28 Jun 2008 10:10:05 +0000 Subject: [PATCH] removed exceptions from pe_crypto and improved error handling --- include/libtorrent/bt_peer_connection.hpp | 2 +- include/libtorrent/pe_crypto.hpp | 42 +++++------ src/bt_peer_connection.cpp | 47 ++++++++---- src/pe_crypto.cpp | 92 +++++++++++++---------- 4 files changed, 107 insertions(+), 76 deletions(-) diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index 09b665b4a..9376f303c 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -389,7 +389,7 @@ private: // initialized during write_pe1_2_dhkey, and destroyed on // creation of m_RC4_handler. Cannot reinitialize once // initialized. - boost::scoped_ptr m_DH_key_exchange; + boost::scoped_ptr m_dh_key_exchange; // if RC4 is negotiated, this is used for // encryption/decryption during the entire session. Destroyed diff --git a/include/libtorrent/pe_crypto.hpp b/include/libtorrent/pe_crypto.hpp index 5db77f6c7..dd1260497 100644 --- a/include/libtorrent/pe_crypto.hpp +++ b/include/libtorrent/pe_crypto.hpp @@ -44,31 +44,30 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - class DH_key_exchange + class dh_key_exchange { public: - DH_key_exchange (); - ~DH_key_exchange (); + dh_key_exchange(); + ~dh_key_exchange(); + bool good() const { return m_dh; } // Get local public key, always 96 bytes - char const* get_local_key (void) const; + char const* get_local_key() const; // read remote_pubkey, generate and store shared secret in - // m_dh_secret - void compute_secret (const char* remote_pubkey); + // m_dh_secret. + int compute_secret(const char* remote_pubkey); - const char* get_secret (void) const; + const char* get_secret() const; private: - int get_local_key_size () const + int get_local_key_size() const { - TORRENT_ASSERT(m_DH); - return BN_num_bytes (m_DH->pub_key); + TORRENT_ASSERT(m_dh); + return BN_num_bytes(m_dh->pub_key); } - DH* m_DH; - static const unsigned char m_dh_prime[96]; - static const unsigned char m_dh_generator[1]; + DH* m_dh; char m_dh_local_key[96]; char m_dh_secret[96]; @@ -78,24 +77,24 @@ namespace libtorrent { public: // Input longkeys must be 20 bytes - RC4_handler (const sha1_hash& rc4_local_longkey, + RC4_handler(const sha1_hash& rc4_local_longkey, const sha1_hash& rc4_remote_longkey) { - RC4_set_key (&m_local_key, 20, + RC4_set_key(&m_local_key, 20, reinterpret_cast(rc4_local_longkey.begin())); - RC4_set_key (&m_remote_key, 20, + RC4_set_key(&m_remote_key, 20, reinterpret_cast(rc4_remote_longkey.begin())); // Discard first 1024 bytes char buf[1024]; - encrypt (buf, 1024); - decrypt (buf, 1024); + encrypt(buf, 1024); + decrypt(buf, 1024); }; - ~RC4_handler () {}; + ~RC4_handler() {}; - void encrypt (char* pos, int len) + void encrypt(char* pos, int len) { TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(pos); @@ -104,7 +103,7 @@ namespace libtorrent reinterpret_cast(pos)); } - void decrypt (char* pos, int len) + void decrypt(char* pos, int len) { TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(pos); @@ -122,3 +121,4 @@ namespace libtorrent #endif // TORRENT_PE_CRYPTO_HPP_INCLUDED #endif // TORRENT_DISABLE_ENCRYPTION + diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 307bcd4d2..d83fdfa3b 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -192,6 +192,7 @@ namespace libtorrent if (out_enc_policy == pe_settings::forced) { write_pe1_2_dhkey(); + if (is_disconnecting()) return; m_state = read_pe_dhkey; reset_recv_buffer(dh_key_len); @@ -214,6 +215,7 @@ namespace libtorrent fast_reconnect(true); write_pe1_2_dhkey(); + if (is_disconnecting()) return; m_state = read_pe_dhkey; reset_recv_buffer(dh_key_len); setup_receive(); @@ -372,7 +374,7 @@ namespace libtorrent TORRENT_ASSERT(!m_encrypted); TORRENT_ASSERT(!m_rc4_encrypted); - TORRENT_ASSERT(!m_DH_key_exchange.get()); + TORRENT_ASSERT(!m_dh_key_exchange.get()); TORRENT_ASSERT(!m_sent_handshake); #ifdef TORRENT_VERBOSE_LOGGING @@ -380,7 +382,12 @@ namespace libtorrent (*m_logger) << " initiating encrypted handshake\n"; #endif - m_DH_key_exchange.reset(new DH_key_exchange); + m_dh_key_exchange.reset(new (std::nothrow) dh_key_exchange); + if (!m_dh_key_exchange || !m_dh_key_exchange->good()) + { + disconnect("out of memory"); + return; + } int pad_size = std::rand() % 512; @@ -389,11 +396,15 @@ namespace libtorrent #endif buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size); - if (send_buf.begin == 0) return; // out of memory + if (send_buf.begin == 0) + { + disconnect("out of memory"); + return; + } - std::copy(m_DH_key_exchange->get_local_key(), - m_DH_key_exchange->get_local_key() + dh_key_len, - send_buf.begin); + std::copy(m_dh_key_exchange->get_local_key(), + m_dh_key_exchange->get_local_key() + dh_key_len, + send_buf.begin); std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand); setup_send(); @@ -417,7 +428,7 @@ namespace libtorrent hasher h; sha1_hash const& info_hash = t->torrent_file().info_hash(); - char const* const secret = m_DH_key_exchange->get_secret(); + char const* const secret = m_dh_key_exchange->get_secret(); int pad_size = rand() % 512; @@ -452,7 +463,7 @@ namespace libtorrent // Discard DH key exchange data, setup RC4 keys init_pe_RC4_handler(secret, info_hash); - m_DH_key_exchange.reset(); // secret should be invalid at this point + m_dh_key_exchange.reset(); // secret should be invalid at this point // write the verification constant and crypto field TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2); @@ -1752,13 +1763,17 @@ namespace libtorrent if (!packet_finished()) return; - // write our dh public key. m_DH_key_exchange is + // write our dh public key. m_dh_key_exchange is // initialized in write_pe1_2_dhkey() - if (!is_local()) - write_pe1_2_dhkey(); + if (!is_local()) write_pe1_2_dhkey(); + if (is_disconnecting()) return; // read dh key, generate shared secret - m_DH_key_exchange->compute_secret (recv_buffer.begin); // TODO handle errors + if (m_dh_key_exchange->compute_secret(recv_buffer.begin) == -1) + { + disconnect("out of memory"); + return; + } #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " received DH key\n"; @@ -1822,7 +1837,7 @@ namespace libtorrent // compute synchash (hash('req1',S)) h.update("req1", 4); - h.update(m_DH_key_exchange->get_secret(), dh_key_len); + h.update(m_dh_key_exchange->get_secret(), dh_key_len); m_sync_hash.reset(new sha1_hash(h.final())); } @@ -1895,7 +1910,7 @@ namespace libtorrent h.reset(); h.update("req3", 4); - h.update(m_DH_key_exchange->get_secret(), dh_key_len); + h.update(m_dh_key_exchange->get_secret(), dh_key_len); obfs_hash = h.final(); obfs_hash ^= skey_hash; @@ -1912,7 +1927,7 @@ namespace libtorrent TORRENT_ASSERT(t); } - init_pe_RC4_handler(m_DH_key_exchange->get_secret(), info_hash); + init_pe_RC4_handler(m_dh_key_exchange->get_secret(), info_hash); #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " stream key found, torrent located.\n"; #endif @@ -2641,7 +2656,7 @@ namespace libtorrent void bt_peer_connection::check_invariant() const { #ifndef TORRENT_DISABLE_ENCRYPTION - TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get()) + TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get()) || !is_local()); TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get()); diff --git a/src/pe_crypto.cpp b/src/pe_crypto.cpp index d9298e989..f20535610 100644 --- a/src/pe_crypto.cpp +++ b/src/pe_crypto.cpp @@ -42,29 +42,46 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + namespace + { + const unsigned char dh_prime[96] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63 + }; + + const unsigned char dh_generator[1] = { 2 }; + } // Set the prime P and the generator, generate local public key - DH_key_exchange::DH_key_exchange() + dh_key_exchange::dh_key_exchange() { - m_DH = DH_new(); - if (m_DH == 0) throw std::bad_alloc(); + m_dh = DH_new(); + if (m_dh == 0) return; - m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL); - m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL); - if (m_DH->p == 0 || m_DH->g == 0) + m_dh->p = BN_bin2bn(dh_prime, sizeof(dh_prime), 0); + m_dh->g = BN_bin2bn(dh_generator, sizeof(dh_generator), 0); + if (m_dh->p == 0 || m_dh->g == 0) { - DH_free(m_DH); - throw std::bad_alloc(); + DH_free(m_dh); + m_dh = 0; + return; } - m_DH->length = 160l; + m_dh->length = 160l; - TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH)); + TORRENT_ASSERT(sizeof(dh_prime) == DH_size(m_dh)); - if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0) + if (DH_generate_key(m_dh) == 0 || m_dh->pub_key == 0) { - DH_free(m_DH); - throw std::bad_alloc(); + DH_free(m_dh); + m_dh = 0; + return; } // DH can generate key sizes that are smaller than the size of @@ -72,42 +89,53 @@ namespace libtorrent // the msb's of m_dh_local_key need to be zeroed // appropriately. int key_size = get_local_key_size(); - int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH) + int len_dh = sizeof(dh_prime); // must equal DH_size(m_DH) if (key_size != len_dh) { TORRENT_ASSERT(key_size > 0 && key_size < len_dh); int pad_zero_size = len_dh - key_size; std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0); - BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size); + if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size) == 0) + { + DH_free(m_dh); + m_dh = 0; + return; + } } else - BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value + { + if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key) == 0) + { + DH_free(m_dh); + m_dh = 0; + return; + } + } } - DH_key_exchange::~DH_key_exchange() + dh_key_exchange::~dh_key_exchange() { - TORRENT_ASSERT(m_DH); - DH_free(m_DH); + if (m_dh) DH_free(m_dh); } - char const* DH_key_exchange::get_local_key() const + char const* dh_key_exchange::get_local_key() const { return m_dh_local_key; } // compute shared secret given remote public key - void DH_key_exchange::compute_secret(char const* remote_pubkey) + int dh_key_exchange::compute_secret(char const* remote_pubkey) { TORRENT_ASSERT(remote_pubkey); BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL); - if (bn_remote_pubkey == 0) throw std::bad_alloc(); + if (bn_remote_pubkey == 0) return -1; char dh_secret[96]; int secret_size = DH_compute_key((unsigned char*)dh_secret - , bn_remote_pubkey, m_DH); - if (secret_size < 0 || secret_size > 96) throw std::bad_alloc(); + , bn_remote_pubkey, m_dh); + if (secret_size < 0 || secret_size > 96) return -1; if (secret_size != 96) { @@ -116,26 +144,14 @@ namespace libtorrent } std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size); BN_free(bn_remote_pubkey); + return 0; } - char const* DH_key_exchange::get_secret() const + char const* dh_key_exchange::get_secret() const { return m_dh_secret; } - const unsigned char DH_key_exchange::m_dh_prime[96] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, - 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, - 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, - 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, - 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63 - }; - - const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 }; - } // namespace libtorrent #endif // #ifndef TORRENT_DISABLE_ENCRYPTION