diff --git a/include/libtorrent/instantiate_connection.hpp b/include/libtorrent/instantiate_connection.hpp index e9ca5fcf5..19f0a5460 100644 --- a/include/libtorrent/instantiate_connection.hpp +++ b/include/libtorrent/instantiate_connection.hpp @@ -40,7 +40,11 @@ namespace libtorrent { struct proxy_settings; struct utp_socket_manager; + struct socket_type; + // if from is specified, a new socket will be created + // using the same underlying socket object as 'from'. + // this can be used to "upgrade" a socket into an SSL socket TORRENT_EXPORT bool instantiate_connection(io_service& ios , proxy_settings const& ps, socket_type& s , void* ssl_context = 0 diff --git a/include/libtorrent/max.hpp b/include/libtorrent/max.hpp index 2a7753aa0..a1b801a4b 100644 --- a/include/libtorrent/max.hpp +++ b/include/libtorrent/max.hpp @@ -105,6 +105,18 @@ namespace libtorrent value = max3::value }; }; + + template + struct max9 + { + enum + { + temp1 = max3::value, + temp2 = max3::value, + temp3 = max3::value, + value = max3::value + }; + }; } #endif diff --git a/include/libtorrent/proxy_base.hpp b/include/libtorrent/proxy_base.hpp index 89e379bda..692bed0e3 100644 --- a/include/libtorrent/proxy_base.hpp +++ b/include/libtorrent/proxy_base.hpp @@ -46,6 +46,7 @@ class proxy_base : boost::noncopyable { public: + typedef stream_socket next_layer_type; typedef stream_socket::lowest_layer_type lowest_layer_type; typedef stream_socket::endpoint_type endpoint_type; typedef stream_socket::protocol_type protocol_type; @@ -217,6 +218,11 @@ public: return m_sock.lowest_layer(); } + next_layer_type& next_layer() + { + return m_sock; + } + bool is_open() const { return m_sock.is_open(); } protected: diff --git a/include/libtorrent/socket_type.hpp b/include/libtorrent/socket_type.hpp index c6244e9be..47c98daf6 100644 --- a/include/libtorrent/socket_type.hpp +++ b/include/libtorrent/socket_type.hpp @@ -72,7 +72,9 @@ POSSIBILITY OF SUCH DAMAGE. case socket_type_int_impl >::value: \ get >()->x; break; \ case socket_type_int_impl >::value: \ - get >()->x; break; + get >()->x; break; \ + case socket_type_int_impl >::value: \ + get >()->x; break; #define TORRENT_SOCKTYPE_SSL_FORWARD_RET(x, def) \ case socket_type_int_impl >::value: \ @@ -80,7 +82,9 @@ POSSIBILITY OF SUCH DAMAGE. case socket_type_int_impl >::value: \ return get >()->x; \ case socket_type_int_impl >::value: \ - return get >()->x; + return get >()->x; \ + case socket_type_int_impl >::value: \ + return get >()->x; #else @@ -160,6 +164,10 @@ namespace libtorrent template <> struct socket_type_int_impl > { enum { value = 8 }; }; + + template <> + struct socket_type_int_impl > + { enum { value = 9 }; }; #endif struct TORRENT_EXPORT socket_type @@ -260,7 +268,7 @@ namespace libtorrent io_service& m_io_service; int m_type; - enum { storage_size = max8< + enum { storage_size = max9< sizeof(stream_socket) , sizeof(socks5_stream) , sizeof(http_stream) @@ -274,8 +282,9 @@ namespace libtorrent , sizeof(ssl_stream) , sizeof(ssl_stream) , sizeof(ssl_stream) + , sizeof(ssl_stream) #else - , 0, 0, 0 + , 0, 0, 0, 0 #endif >::value }; diff --git a/include/libtorrent/ssl_stream.hpp b/include/libtorrent/ssl_stream.hpp index 8a8a07e95..e0c2597e5 100644 --- a/include/libtorrent/ssl_stream.hpp +++ b/include/libtorrent/ssl_stream.hpp @@ -56,11 +56,11 @@ public: { } - typedef asio::ssl::stream next_layer_type; + typedef typename asio::ssl::stream sock_type; + typedef typename sock_type::next_layer_type next_layer_type; typedef typename Stream::lowest_layer_type lowest_layer_type; typedef typename Stream::endpoint_type endpoint_type; typedef typename Stream::protocol_type protocol_type; - typedef typename asio::ssl::stream sock_type; typedef boost::function handler_type; @@ -79,6 +79,33 @@ public: , boost::bind(&ssl_stream::connected, this, _1, h)); } + template + void async_accept_handshake(Handler const& handler) + { + // this is used for accepting SSL connections + boost::shared_ptr h(new handler_type(handler)); + m_sock.async_handshake(asio::ssl::stream_base::server + , boost::bind(&ssl_stream::handshake, this, _1, h)); + } + + void accept_handshake(error_code& ec) + { + // this is used for accepting SSL connections + m_sock.handshake(asio::ssl::stream_base::server, ec); + } + + template + void async_shutdown(Handler const& handler) + { + boost::shared_ptr h(new handler_type(handler)); + m_sock.async_shutdown( boost::bind(&ssl_stream::on_shutdown, this, _1, h)); + } + + void shutdown(error_code& ec) + { + m_sock.shutdown(ec); + } + template void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) { @@ -222,7 +249,7 @@ public: next_layer_type& next_layer() { - return m_sock; + return m_sock.next_layer(); } private: diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 5ec785aff..e193227f7 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -838,6 +838,12 @@ namespace libtorrent void queue_torrent_check(); void dequeue_torrent_check(); +#ifdef TORRENT_USE_OPENSSL + void set_ssl_cert(std::string const& certificate, error_code& ec); + bool is_ssl_torrent() const { return m_ssl_ctx; } + boost::asio::ssl::context* ssl_ctx() const { return m_ssl_ctx.get(); } +#endif + private: void on_files_deleted(int ret, disk_io_job const& j); diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 1a1bd613d..f02446408 100644 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -252,6 +252,9 @@ namespace libtorrent bool resolve_countries() const; #endif + void set_ssl_certificates(std::string const& certificate + , error_code& ec); + storage_interface* get_storage_impl() const; // all these are deprecated, use piece diff --git a/include/libtorrent/utp_stream.hpp b/include/libtorrent/utp_stream.hpp index 87d88dedf..0717b34a4 100644 --- a/include/libtorrent/utp_stream.hpp +++ b/include/libtorrent/utp_stream.hpp @@ -166,12 +166,15 @@ class TORRENT_EXPORT utp_stream { public: + typedef utp_stream lowest_layer_type; typedef stream_socket::endpoint_type endpoint_type; typedef stream_socket::protocol_type protocol_type; explicit utp_stream(asio::io_service& io_service); ~utp_stream(); + lowest_layer_type& lowest_layer() { return *this; } + // used for incoming connections void set_impl(utp_socket_impl* s); utp_socket_impl* get_impl(); @@ -239,8 +242,7 @@ public: std::size_t available() const; std::size_t available(error_code& ec) const { return available(); } - asio::io_service& io_service() - { return m_io_service; } + asio::io_service& get_io_service() { return m_io_service; } template void async_connect(endpoint_type const& endpoint, Handler const& handler) @@ -338,10 +340,33 @@ public: template std::size_t write_some(Const_Buffers const& buffers, error_code& ec) { + TORRENT_ASSERT(false && "not implemented!"); // TODO: implement return 0; } +#ifndef BOOST_NO_EXCEPTIONS + template + std::size_t read_some(Mutable_Buffers const& buffers) + { + error_code ec; + std::size_t ret = read_some(buffers, ec); + if (ec) + boost::throw_exception(boost::system::system_error(ec)); + return ret; + } + + template + std::size_t write_some(Const_Buffers const& buffers) + { + error_code ec; + std::size_t ret = write_some(buffers, ec); + if (ec) + boost::throw_exception(boost::system::system_error(ec)); + return ret; + } +#endif + template void async_write_some(Const_Buffers const& buffers, Handler const& handler) { diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 1d829b243..f7e811d09 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -300,12 +300,14 @@ void http_connection::start(std::string const& hostname, std::string const& port { if (m_ssl_ctx == 0) { - m_ssl_ctx = new boost::asio::ssl::context(m_resolver.get_io_service(), asio::ssl::context::sslv23_client); + m_ssl_ctx = new (std::nothrow) boost::asio::ssl::context( + m_resolver.get_io_service(), asio::ssl::context::sslv23_client); if (m_ssl_ctx) { m_own_ssl_context = true; error_code ec; m_ssl_ctx->set_verify_mode(asio::ssl::context::verify_none, ec); + TORRENT_ASSERT(!ec); } } userdata = m_ssl_ctx; @@ -536,7 +538,7 @@ void http_connection::connect(int ticket, tcp::endpoint target_address) if (m_ssl) { TORRENT_ASSERT(m_sock.get >()); - m_sock.get >()->next_layer().next_layer().set_dst_name(m_hostname); + m_sock.get >()->next_layer().set_dst_name(m_hostname); } else #endif diff --git a/src/instantiate_connection.cpp b/src/instantiate_connection.cpp index 495af59d7..572c5aaf5 100644 --- a/src/instantiate_connection.cpp +++ b/src/instantiate_connection.cpp @@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - TORRENT_EXPORT bool instantiate_connection(io_service& ios , proxy_settings const& ps, socket_type& s , void* ssl_context @@ -50,12 +49,26 @@ namespace libtorrent { if (sm) { - s.instantiate(ios); - s.get()->set_impl(sm->new_utp_socket(s.get())); + utp_stream* str; +#ifdef TORRENT_USE_OPENSSL + if (ssl_context) + { + s.instantiate >(ios, ssl_context); + str = &s.get >()->next_layer(); + } + else +#endif + { + s.instantiate(ios); + str = s.get(); + } + str->set_impl(sm->new_utp_socket(str)); } #if TORRENT_USE_I2P else if (ps.type == proxy_settings::i2p_proxy) { + // it doesn't make any sense to try ssl over i2p + TORRENT_ASSERT(ssl_context == 0); s.instantiate(ios); s.get()->set_proxy(ps.hostname, ps.port); } @@ -63,12 +76,19 @@ namespace libtorrent else if (ps.type == proxy_settings::none || (peer_connection && !ps.proxy_peer_connections)) { + stream_socket* str; #ifdef TORRENT_USE_OPENSSL if (ssl_context) + { s.instantiate >(ios, ssl_context); + str = &s.get >()->next_layer(); + } else #endif + { s.instantiate(ios); + str = s.get(); + } } else if (ps.type == proxy_settings::http || ps.type == proxy_settings::http_pw) @@ -78,7 +98,7 @@ namespace libtorrent if (ssl_context) { s.instantiate >(ios, ssl_context); - str = &s.get >()->next_layer().next_layer(); + str = &s.get >()->next_layer(); } else #endif @@ -100,7 +120,7 @@ namespace libtorrent if (ssl_context) { s.instantiate >(ios, ssl_context); - str = &s.get >()->next_layer().next_layer(); + str = &s.get >()->next_layer(); } else #endif diff --git a/src/socket_type.cpp b/src/socket_type.cpp index e93b5e29c..59a0c93f1 100644 --- a/src/socket_type.cpp +++ b/src/socket_type.cpp @@ -71,6 +71,9 @@ namespace libtorrent case socket_type_int_impl >::value: get >()->~ssl_stream(); break; + case socket_type_int_impl >::value: + get >()->~ssl_stream(); + break; #endif default: TORRENT_ASSERT(false); } @@ -116,6 +119,11 @@ namespace libtorrent new ((ssl_stream*)m_data) ssl_stream(m_io_service , *((boost::asio::ssl::context*)userdata)); break; + case socket_type_int_impl >::value: + TORRENT_ASSERT(userdata); + new ((ssl_stream*)m_data) ssl_stream(m_io_service + , *((boost::asio::ssl::context*)userdata)); + break; #endif default: TORRENT_ASSERT(false); } diff --git a/src/torrent.cpp b/src/torrent.cpp index fd7901e13..342801014 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1292,7 +1292,7 @@ namespace libtorrent // inject the root certificate, and no other, to // verify other peers against boost::shared_ptr ctx( - new (std::nothrow) context(m_ses.m_io_service, context::tlsv1)); + new (std::nothrow) context(m_ses.m_io_service, context::sslv23)); if (!ctx) { @@ -3972,6 +3972,26 @@ namespace libtorrent } } +#ifdef TORRENT_USE_OPENSSL + // certificate is a filename to a .pem file which is our + // certificate. root_cert is a filename to a certificate + // on disk which is the trusted certificate authority (CA) + // for this torrent. 'certificate' must be signed by the + // 'root_cert', and any peer we connect to or that connect + // to use must present a valid certificate signed by 'root_cert' + void torrent::set_ssl_cert(std::string const& certificate, error_code& ec) + { + ec.clear(); + if (!m_ssl_ctx) + { + ec = asio::error::operation_not_supported; + return; + } + using boost::asio::ssl::context; + m_ssl_ctx->use_certificate_file(certificate, context::pem, ec); + } +#endif + void torrent::remove_peer(peer_connection* p) { // INVARIANT_CHECK; @@ -4313,7 +4333,11 @@ namespace libtorrent bool ssl = string_begins_no_case("https://", web->url.c_str()); void* userdata = 0; #ifdef TORRENT_USE_OPENSSL - if (ssl) userdata = &m_ses.m_ssl_ctx; + if (ssl) + { + userdata = m_ssl_ctx.get(); + if (!userdata) userdata = &m_ses.m_ssl_ctx; + } #endif bool ret = instantiate_connection(m_ses.m_io_service, m_ses.proxy(), *s, userdata, 0, true); (void)ret; @@ -4335,13 +4359,11 @@ namespace libtorrent { // we're using a socks proxy and we're resolving // hostnames through it + socks5_stream* str = #ifdef TORRENT_USE_OPENSSL - socks5_stream* str = ssl - ? &s->get >()->next_layer().next_layer() - : s->get(); -#else - socks5_stream* str = s->get(); + ssl ? &s->get >()->next_layer() : #endif + s->get(); TORRENT_ASSERT(str); using boost::tuples::ignore; diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 1e86d557e..6d7ee9201 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -375,6 +375,16 @@ namespace libtorrent TORRENT_ASYNC_CALL(flush_cache); } + void torrent_handle::set_ssl_certificates( + std::string const& certificate, error_code& ec) + { +#ifdef TORRENT_USE_OPENSSL + TORRENT_ASYNC_CALL2(set_ssl_cert, certificate, boost::ref(ec)); +#else + ec = boost::asio::error::operation_not_supported; +#endif + } + void torrent_handle::save_resume_data(int f) const { INVARIANT_CHECK;