merged ssl fix from RC_0_16

This commit is contained in:
Arvid Norberg 2013-07-28 15:06:28 +00:00
parent 2599acf451
commit beae6cece0
21 changed files with 565 additions and 58 deletions

View File

@ -523,8 +523,7 @@ namespace libtorrent
TORRENT_DEFINE_ALERT(peer_disconnected_alert);
const static int static_category = alert::debug_notification;
virtual std::string message() const
{ return peer_alert::message() + " disconnecting: " + error.message(); }
virtual std::string message() const;
error_code error;

View File

@ -600,6 +600,7 @@ namespace libtorrent
, const char* net_interface = 0
, int flags = 0);
unsigned short listen_port() const;
unsigned short ssl_listen_port() const;
bool is_listening() const;
// if the listen port failed in some way

View File

@ -931,6 +931,7 @@ namespace libtorrent
bool lock_files;
// open an ssl listen socket for ssl torrents on this port
// if this is 0, outgoing SSL connections are disabled
int ssl_listen;
// this is the factor X in the formula to calculate the

View File

@ -863,12 +863,13 @@ namespace libtorrent
TORRENT_ASSERT(m_num_connecting > 0);
--m_num_connecting;
}
bool is_ssl_torrent() const { return m_ssl_torrent; }
#ifdef TORRENT_USE_OPENSSL
void set_ssl_cert(std::string const& certificate
, std::string const& private_key
, std::string const& dh_params
, std::string const& passphrase);
bool is_ssl_torrent() const { return m_ssl_ctx; }
boost::asio::ssl::context* ssl_ctx() const { return m_ssl_ctx.get(); }
#endif
@ -1378,6 +1379,11 @@ namespace libtorrent
bool m_is_active_download:1;
bool m_is_active_finished:1;
// even if we're not built to support SSL torrents,
// remember that this is an SSL torrent, so that we don't
// accidentally start seeding it without any authentication.
bool m_ssl_torrent:1;
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
public:
// set to false until we've loaded resume data

View File

@ -474,6 +474,11 @@ namespace libtorrent
#ifdef TORRENT_USE_OPENSSL
std::string const& ssl_cert() const { return m_ssl_root_cert; }
#else
std::string ssl_cert() const
{
return m_info_dict.dict_find_string_value("ssl-cert");
}
#endif
bool is_valid() const { return m_files.is_valid(); }

View File

@ -508,5 +508,12 @@ namespace libtorrent {
return msg;
}
std::string peer_disconnected_alert::message() const
{
char msg[600];
snprintf(msg, sizeof(msg), "%s disconnecting: [%s] %s", peer_alert::message().c_str()
, error.category().name(), error.message().c_str());
return msg;
}
} // namespace libtorrent

View File

@ -757,6 +757,12 @@ namespace libtorrent
return r;
}
unsigned short session::ssl_listen_port() const
{
TORRENT_SYNC_CALL_RET(unsigned short, ssl_listen_port);
return r;
}
session_status session::status() const
{
TORRENT_SYNC_CALL_RET(session_status, status);

View File

@ -581,10 +581,12 @@ namespace aux {
if (!t) return SSL_TLSEXT_ERR_ALERT_FATAL;
// if the torrent we found isn't an SSL torrent, also fail.
// the torrent doesn't have an SSL context and should not allow
// incoming SSL connections
if (!t->is_ssl_torrent()) return SSL_TLSEXT_ERR_ALERT_FATAL;
// if the torrent doesn't have an SSL context and should not allow
// incoming SSL connections
if (!t->ssl_ctx()) return SSL_TLSEXT_ERR_ALERT_FATAL;
// use this torrent's certificate
SSL_set_SSL_CTX(s, t->ssl_ctx()->native_handle());

View File

@ -427,6 +427,7 @@ namespace libtorrent
, m_in_state_updates(false)
, m_is_active_download(false)
, m_is_active_finished(false)
, m_ssl_torrent(false)
{
// if there is resume data already, we don't need to trigger the initial save
// resume data
@ -1363,6 +1364,12 @@ namespace libtorrent
if (!preverified) return false;
// we're only interested in checking the certificate at the end of the chain.
// TODO: is verify_peer_cert called once per certificate in the chain, and
// this function just tells us which depth we're at right now? If so, the comment
// makes sense.
// any certificate that isn't the leaf (i.e. the one presented by the peer)
// should be accepted automatically, given preverified is true. The leaf certificate
// need to be verified to make sure its DN matches the info-hash
int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
if (depth > 0) return true;
@ -1585,10 +1592,14 @@ namespace libtorrent
if (m_file_priority.size() > m_torrent_file->num_files())
m_file_priority.resize(m_torrent_file->num_files());
#ifdef TORRENT_USE_OPENSSL
std::string cert = m_torrent_file->ssl_cert();
if (!cert.empty()) init_ssl(cert);
if (!cert.empty())
{
m_ssl_torrent = true;
#ifdef TORRENT_USE_OPENSSL
init_ssl(cert);
#endif
}
m_file_priority.resize(m_torrent_file->num_files(), 1);
m_file_progress.resize(m_torrent_file->num_files(), 0);
@ -5781,13 +5792,13 @@ namespace libtorrent
void* userdata = 0;
#ifdef TORRENT_USE_OPENSSL
if (is_ssl_torrent())
if (is_ssl_torrent() && m_ses.settings().ssl_listen != 0)
{
userdata = m_ssl_ctx.get();
// SSL handshakes are slow
timeout_extend = 10;
// we don't support SSL over uTP yet
// TODO: 3 support SSL over uTP
sm = 0;
}
#endif
@ -5979,6 +5990,13 @@ namespace libtorrent
return false;
}
if (!m_ssl_ctx)
{
// we don't have a valid cert, don't accept any connection!
p->disconnect(errors::invalid_ssl_cert);
return false;
}
if (SSL_get_SSL_CTX(ssl_conn) != m_ssl_ctx->native_handle())
{
// if the SSL_CTX associated with this connection is
@ -5997,6 +6015,14 @@ namespace libtorrent
return false;
}
#endif
#else // TORRENT_USE_OPENSSL
if (is_ssl_torrent())
{
// Don't accidentally allow seeding of SSL torrents, just
// because libtorrent wasn't built with SSL support
p->disconnect(errors::requires_ssl_connection);
return false;
}
#endif // TORRENT_USE_OPENSSL
TORRENT_ASSERT(p != 0);

View File

@ -59,6 +59,7 @@ test-suite libtorrent :
[ run test_session.cpp ]
[ run test_upnp.cpp ]
[ run test_ssl.cpp ]
[ run test_tracker.cpp ]
[ run test_checking.cpp ]
[ run test_web_seed.cpp ]

View File

@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket_io.hpp" // print_endpoint
#include "libtorrent/socket_type.hpp"
#include "libtorrent/instantiate_connection.hpp"
#include "setup_transfer.hpp"
#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/stream.hpp>
@ -172,14 +173,14 @@ bool print_alerts(libtorrent::session& ses, char const* name
if (predicate && predicate(*i)) ret = true;
if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(*i))
{
fprintf(stderr, " %s(%s): %s\n", name, print_endpoint(p->ip).c_str(), p->message().c_str());
fprintf(stderr, "%s: %s(%s): %s\n", time_now_string(), name, print_endpoint(p->ip).c_str(), p->message().c_str());
}
else if ((*i)->message() != "block downloading"
&& (*i)->message() != "block finished"
&& (*i)->message() != "piece finished"
&& !no_output)
{
fprintf(stderr, " %s: %s\n", name, (*i)->message().c_str());
fprintf(stderr, "%s: %s: %s\n", time_now_string(), name, (*i)->message().c_str());
}
TEST_CHECK(alert_cast<fastresume_rejected_alert>(*i) == 0 || allow_failed_fastresume);
@ -187,7 +188,7 @@ bool print_alerts(libtorrent::session& ses, char const* name
peer_error_alert* pea = alert_cast<peer_error_alert>(*i);
if (pea)
{
fprintf(stderr, " peer error: %s\n", pea->error.message().c_str());
fprintf(stderr, "%s: peer error: %s\n", time_now_string(), pea->error.message().c_str());
TEST_CHECK((!handles.empty() && h.status().is_seeding)
|| pea->error.message() == "connecting to peer"
|| pea->error.message() == "closing connection to ourself"
@ -359,7 +360,7 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu
}
boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size
, int num_pieces, bool add_tracker, bool encrypted_torrent)
, int num_pieces, bool add_tracker, std::string ssl_certificate)
{
char const* tracker_url = "http://non-existent-name.com/announce";
// excercise the path when encountering invalid urls
@ -377,6 +378,23 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_
t.add_tracker(invalid_tracker_protocol);
}
if (!ssl_certificate.empty())
{
std::vector<char> file_buf;
error_code ec;
int res = load_file(ssl_certificate, file_buf, ec);
if (ec || res < 0)
{
fprintf(stderr, "failed to load SSL certificate: %s\n", ec.message().c_str());
}
else
{
std::string pem;
std::copy(file_buf.begin(), file_buf.end(), std::back_inserter(pem));
t.set_root_cert(pem);
}
}
std::vector<char> piece(piece_size);
for (int i = 0; i < int(piece.size()); ++i)
piece[i] = (i % 26) + 'A';
@ -401,14 +419,6 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_
entry tor = t.generate();
if (encrypted_torrent)
{
std::string key;
key.resize(32);
std::generate(key.begin(), key.end(), &std::rand);
tor["info"]["encryption-key"] = key;
}
bencode(out, tor);
error_code ec;
return boost::intrusive_ptr<torrent_info>(new torrent_info(
@ -420,7 +430,7 @@ setup_transfer(session* ses1, session* ses2, session* ses3
, bool clear_files, bool use_metadata_transfer, bool connect_peers
, std::string suffix, int piece_size
, boost::intrusive_ptr<torrent_info>* torrent, bool super_seeding
, add_torrent_params const* p, bool stop_lsd, bool encrypted_torrent)
, add_torrent_params const* p, bool stop_lsd, bool use_ssl_ports)
{
assert(ses1);
assert(ses2);
@ -464,7 +474,7 @@ setup_transfer(session* ses1, session* ses2, session* ses3
error_code ec;
create_directory("tmp1" + suffix, ec);
std::ofstream file(combine_path("tmp1" + suffix, "temporary").c_str());
t = ::create_torrent(&file, piece_size, 19, true, encrypted_torrent);
t = ::create_torrent(&file, piece_size, 19, true);
file.close();
if (clear_files)
{
@ -530,21 +540,47 @@ setup_transfer(session* ses1, session* ses2, session* ses3
if (connect_peers)
{
fprintf(stderr, "connecting peer\n");
error_code ec;
tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec)
, ses2->listen_port()));
if (use_ssl_ports)
{
fprintf(stderr, "ses1: connecting peer port: %d\n", int(ses2->ssl_listen_port()));
tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec)
, ses2->ssl_listen_port()));
}
else
{
fprintf(stderr, "ses1: connecting peer port: %d\n", int(ses2->listen_port()));
tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1", ec)
, ses2->listen_port()));
}
if (ses3)
{
// give the other peers some time to get an initial
// set of pieces before they start sharing with each-other
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses2->listen_port()));
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses1->listen_port()));
if (use_ssl_ports)
{
fprintf(stderr, "ses3: connecting peer port: %d\n", int(ses2->ssl_listen_port()));
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses2->ssl_listen_port()));
fprintf(stderr, "ses3: connecting peer port: %d\n", int(ses1->ssl_listen_port()));
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses1->ssl_listen_port()));
}
else
{
fprintf(stderr, "ses3: connecting peer port: %d\n", int(ses2->listen_port()));
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses2->listen_port()));
fprintf(stderr, "ses3: connecting peer port: %d\n", int(ses1->listen_port()));
tor3.connect_peer(tcp::endpoint(
address::from_string("127.0.0.1", ec)
, ses1->listen_port()));
}
}
}
@ -753,19 +789,6 @@ int start_web_server(bool ssl, bool chunked_encoding)
web_initialized.clear(l);
}
if (ssl)
{
system("echo . > tmp");
system("echo test province >>tmp");
system("echo test city >> tmp");
system("echo test company >> tmp");
system("echo test department >> tmp");
system("echo 127.0.0.1 >> tmp");
system("echo test@test.com >> tmp");
system("openssl req -new -x509 -keyout server.pem -out server.pem "
"-days 365 -nodes <tmp");
}
int port = 0;
web_server.reset(new libtorrent::thread(boost::bind(
@ -915,8 +938,8 @@ void web_server_thread(int* port, bool ssl, bool chunked)
boost::asio::ssl::context ssl_ctx(ios, boost::asio::ssl::context::sslv23_server);
if (ssl)
{
ssl_ctx.use_certificate_chain_file("server.pem");
ssl_ctx.use_private_key_file("server.pem", asio::ssl::context::pem);
ssl_ctx.use_certificate_chain_file("ssl/server.pem");
ssl_ctx.use_private_key_file("ssl/server.pem", asio::ssl::context::pem);
ssl_ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
ctx = &ssl_ctx;

View File

@ -73,7 +73,8 @@ extern EXPORT boost::detail::atomic_count g_http_tracker_requests;
void EXPORT create_random_files(std::string const& path, const int file_sizes[], int num_files);
boost::intrusive_ptr<libtorrent::torrent_info> EXPORT create_torrent(std::ostream* file = 0
, int piece_size = 16 * 1024, int num_pieces = 13, bool add_tracker = true, bool encrypted = false);
, int piece_size = 16 * 1024, int num_pieces = 13, bool add_tracker = true
, std::string ssl_certificate = "");
boost::tuple<libtorrent::torrent_handle
, libtorrent::torrent_handle
@ -82,7 +83,7 @@ EXPORT setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2
, libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true
, bool connect = true, std::string suffix = "", int piece_size = 16 * 1024
, boost::intrusive_ptr<libtorrent::torrent_info>* torrent = 0, bool super_seeding = false
, libtorrent::add_torrent_params const* p = 0, bool stop_lsd = true, bool encrypted_torrent = false);
, libtorrent::add_torrent_params const* p = 0, bool stop_lsd = true, bool use_ssl_ports = false);
int EXPORT start_web_server(bool ssl = false, bool chunked = false);
void EXPORT stop_web_server();

12
test/ssl/cert_request.pem Normal file
View File

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBsTCCARoCAQAwXDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEVMBMGA1UEAwwMdGVz
dCB0b3JyZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClM6eDsvQiXVj7
ZCrWko+PmlJUMBzPjTbDvSfLfw8zGH3OjPJev1lf3JCPRAGu8CRVFLPZg2RZUfLi
9dITBThnTD2T9/5sHeNpxAU0JW7FPETHay+Q4B1abuYJ+nPmdLbdaiegQjJgoAcH
GlYi6YPNM5n5B8y9vA+k3DOFTAXnLwIDAQABoBUwEwYJKoZIhvcNAQkHMQYMBHRl
c3QwDQYJKoZIhvcNAQEFBQADgYEAJuhp3OEKPqYfF2pz/BooTU5cu/bcgy21M6IM
rEzQSIBO5bNxetK3VlVaclC+QlKMDN5efHw1PiAZPXGGD3BfZyNtf1xEH7urCDqy
McGog59bL/wOwUqGwq5iq18e05XPyrc6JgZUwjKLFu3lSP6FkW0z8c1dbLrMduL+
M9dvHdk=
-----END CERTIFICATE REQUEST-----

4
test/ssl/dhparams.pem Normal file
View File

@ -0,0 +1,4 @@
-----BEGIN DH PARAMETERS-----
MEYCQQCyiMyueIbvCXyd04Z8CCAB44IKMgYTcBcWUEb8Ka3c5kwrlJOw+zi7MYD3
yLthYad9KAEOAA7DysJs7G+f3KBjAgEC
-----END DH PARAMETERS-----

View File

@ -0,0 +1,60 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 17335853646391593947 (0xf095530ac754cbdb)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=test root cert
Validity
Not Before: Jul 27 23:50:37 2013 GMT
Not After : Jul 27 23:50:37 2014 GMT
Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=*
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:e4:4d:f9:0f:d2:c4:d2:f0:e7:e7:ab:10:ea:75:
88:be:21:13:29:bd:bf:8a:7a:dc:07:1b:0c:cf:e1:
c8:09:81:04:f9:ce:85:12:92:62:38:23:28:03:27:
c8:0f:b5:5b:63:51:8a:2d:8c:dd:83:a8:ef:90:4c:
3b:ec:de:91:5c:e6:bd:74:9e:86:10:b0:f0:c0:bf:
de:27:f2:2e:2e:d7:b0:77:35:c0:80:41:b3:20:9b:
06:62:20:6a:b4:52:8c:b6:44:46:b5:9e:fb:d2:fe:
53:fe:10:8a:5a:f9:df:14:ad:00:66:29:fb:74:8b:
8d:29:4c:41:87:d0:d5:a5:35
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
2A:EE:9B:AF:32:D9:B2:A9:E5:46:42:53:A9:6E:B7:87:7A:EA:E9:63
X509v3 Authority Key Identifier:
keyid:B7:EA:25:4E:F3:13:05:CB:7F:6E:14:BD:13:BC:84:68:ED:35:8E:74
Signature Algorithm: sha1WithRSAEncryption
a8:dd:09:73:90:9e:48:95:8f:cc:fc:d7:0a:53:a8:07:5f:c5:
6b:1f:f6:e5:52:92:91:de:5d:7f:e5:a5:b4:d0:0c:23:4c:5c:
1a:7a:96:fc:e5:76:62:e7:ce:c3:2f:4d:54:e1:06:57:af:71:
10:48:a5:49:95:cf:ab:8c:12:e9:de:93:1f:6c:bd:24:3b:e3:
1b:ce:a5:19:aa:82:49:9d:44:1e:fb:57:cb:b9:ca:06:9d:44:
d6:5f:72:28:8a:a9:45:26:e8:9f:f5:a5:e3:12:05:5e:5e:d8:
96:90:4c:78:bc:16:45:fe:49:8e:34:78:e1:16:46:3d:26:90:
e3:5d
-----BEGIN CERTIFICATE-----
MIICqDCCAhGgAwIBAgIJAPCVUwrHVMvbMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMMDnRlc3Qgcm9vdCBjZXJ0MB4XDTEzMDcy
NzIzNTAzN1oXDTE0MDcyNzIzNTAzN1owUTELMAkGA1UEBhMCQVUxEzARBgNVBAgM
ClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEK
MAgGA1UEAwwBKjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5E35D9LE0vDn
56sQ6nWIviETKb2/inrcBxsMz+HICYEE+c6FEpJiOCMoAyfID7VbY1GKLYzdg6jv
kEw77N6RXOa9dJ6GELDwwL/eJ/IuLtewdzXAgEGzIJsGYiBqtFKMtkRGtZ770v5T
/hCKWvnfFK0AZin7dIuNKUxBh9DVpTUCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg
hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O
BBYEFCrum68y2bKp5UZCU6lut4d66uljMB8GA1UdIwQYMBaAFLfqJU7zEwXLf24U
vRO8hGjtNY50MA0GCSqGSIb3DQEBBQUAA4GBAKjdCXOQnkiVj8z81wpTqAdfxWsf
9uVSkpHeXX/lpbTQDCNMXBp6lvzldmLnzsMvTVThBlevcRBIpUmVz6uMEunekx9s
vSQ74xvOpRmqgkmdRB77V8u5ygadRNZfciiKqUUm6J/1peMSBV5e2JaQTHi8FkX+
SY40eOEWRj0mkONd
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISENU51R9xoQCAggA
MBQGCCqGSIb3DQMHBAgrubUiGwLYbgSCAoBFbrx1Dhn5drmbUJZIlcBQF7v1mMVZ
Cve/G6tr9Vk7iukKJDe7x90f+CP1GtL96yzWhTEa8DVVq62D0gGDDjcANlkrP8P2
Zgn1J69DdJZ0boNT1mhYkCnTMYeBGgOdnqgV2IQxNXFntu9PYDnUUYi+5XTMM9SV
P2txFzhm8ZpTKW78VekYki6l83eCEr/dzpqQoSML33OZlwlK2P0ef/SmHf+mvIga
fswG7mpOo0IAuHb7R5W+QGv10XGdSzF+rKV1jtl9KvOlK2GSsika+4FjaAAD78Q0
37FUakE6tQT27yeGG8/z3a4WTCbMQZPLCcjgmZBcM0Cn8dZsQDCiaM9WfXl1j9PH
FEuc2KDetG0FhTWTCZ9j64Or3UMA1zEtLIG4eVJMrLxcW8OuGuYLcwMc79lvHzzg
/EEfdMW+iQr7FQFltH507245ve7+1aKceCfKB3lcWjQClkSGzrbrSPJaaeweLWlw
XPqqF/xdRtGxTays8ED/HQML+6nsgpoOtFCPeSvxniIVpSVnUhFt7v0G05J1fk1H
Ppm4DF8VbnB6yYPGyGG/LUBJL8aB/0ffhMHLiPKGm/SQeahYeAJgQUEDmIRLnZtv
CSfH/0HsxjuqjZT3kFnZu5x907QBry1kTHi6uVQo2kPtGhQAuAbUyuF/3TQBFNHQ
ah2jxBb5u2SZaFOjpY/wQk76egupfLny/ZOJD3NSjiAm+opOO6zhPQjJ9Hdp1y5H
UxBAAI53b/YfzQDG1Cm9HnYQdGkzwaUMllM0JntXr8T1c7ZNvGiW+DLqxLRxEskP
8itWHr1KxPGXBnAPpVuF7f/P9GzyEVRLuddAWUilFbrYPkZj02Lf/bJ8
-----END ENCRYPTED PRIVATE KEY-----

57
test/ssl/root_ca_cert.pem Normal file
View File

@ -0,0 +1,57 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 17335853646391593945 (0xf095530ac754cbd9)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=test root cert
Validity
Not Before: Jul 27 14:26:20 2013 GMT
Not After : Jul 26 14:26:20 2016 GMT
Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=test root cert
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:e2:3c:4a:44:9e:81:d3:9a:f4:f1:a8:f7:51:58:
b3:67:b0:58:ca:e3:d0:12:d7:0c:c4:36:cb:0d:f6:
f3:46:24:d2:87:31:6a:25:55:08:21:94:38:83:eb:
b1:b9:cf:90:81:d0:8f:77:fb:de:66:27:3a:6d:9a:
0d:cd:5d:36:bf:ac:81:9b:15:dd:7e:71:cc:6c:7c:
86:43:a7:47:24:f2:dc:6d:99:cb:0d:cb:85:11:6f:
8c:22:c1:63:dc:f3:65:3d:b5:35:51:5e:30:78:09:
80:27:7f:72:d3:ea:b6:64:d8:b7:93:91:f6:ba:a4:
8f:ae:69:53:94:95:b5:2f:3d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
B7:EA:25:4E:F3:13:05:CB:7F:6E:14:BD:13:BC:84:68:ED:35:8E:74
X509v3 Authority Key Identifier:
keyid:B7:EA:25:4E:F3:13:05:CB:7F:6E:14:BD:13:BC:84:68:ED:35:8E:74
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
56:1e:82:1d:9a:ac:b2:28:b0:36:a9:5a:3c:5c:bf:72:ad:f3:
4e:d1:a8:48:c0:59:4c:cf:2e:a1:9a:f4:ce:31:7e:53:44:13:
fb:ee:3e:bc:f4:dc:bd:9e:bf:35:3b:84:d8:3c:79:ea:04:66:
ae:0b:d2:84:13:03:0c:f6:d0:da:9a:f8:e1:d2:b3:73:14:c6:
71:e4:29:77:bf:24:f6:f2:57:c2:3f:30:8b:fa:e0:3f:84:29:
63:c9:df:54:73:5f:34:15:9c:ce:e6:d4:d8:64:86:20:50:67:
4d:d2:e1:ad:cf:65:b9:db:c4:22:e7:c9:35:53:fb:3b:e2:e4:
32:fe
-----BEGIN CERTIFICATE-----
MIICijCCAfOgAwIBAgIJAPCVUwrHVMvZMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMMDnRlc3Qgcm9vdCBjZXJ0MB4XDTEzMDcy
NzE0MjYyMFoXDTE2MDcyNjE0MjYyMFowXjELMAkGA1UEBhMCQVUxEzARBgNVBAgM
ClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEX
MBUGA1UEAwwOdGVzdCByb290IGNlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
AoGBAOI8SkSegdOa9PGo91FYs2ewWMrj0BLXDMQ2yw3280Yk0ocxaiVVCCGUOIPr
sbnPkIHQj3f73mYnOm2aDc1dNr+sgZsV3X5xzGx8hkOnRyTy3G2Zyw3LhRFvjCLB
Y9zzZT21NVFeMHgJgCd/ctPqtmTYt5OR9rqkj65pU5SVtS89AgMBAAGjUDBOMB0G
A1UdDgQWBBS36iVO8xMFy39uFL0TvIRo7TWOdDAfBgNVHSMEGDAWgBS36iVO8xMF
y39uFL0TvIRo7TWOdDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFYe
gh2arLIosDapWjxcv3Kt807RqEjAWUzPLqGa9M4xflNEE/vuPrz03L2evzU7hNg8
eeoEZq4L0oQTAwz20Nqa+OHSs3MUxnHkKXe/JPbyV8I/MIv64D+EKWPJ31RzXzQV
nM7m1NhkhiBQZ03S4a3PZbnbxCLnyTVT+zvi5DL+
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI287GvM3Vm/4CAggA
MBQGCCqGSIb3DQMHBAifwngs3IFCzQSCAoCAYvNd9XQqNeDmKIdFS7o5oYDOPt/c
Ctnwy9UAwqBtv+gsAE+LTYwZrJ8o3/0+pt/ZT05sgsUwyy2wDtuBuCI+7OZObiSr
u9xdWfUUiJCRnGWaZ9bC5NLvPRTRZB2pOuVJJV7/mjVuxSz73FResRzGGLyr/+yD
tGotyRHCdYQOU0o2xWsKSIpcbG31lNhVYf5HCq0Rn1rwmDqwNW1GIO0bvPb6ZagU
qcRbZcvkgYMdS2yr55f9rglDByAZU5S7DrkrK92dUE2sujdyC7Iz20fAQ1UbUuch
fIFtrruvEbbWdqLkByfKlok5ho7tRav8dzbC9sMxBR5o7lP+SCe0t5g29hlQpv6N
mRgWakyOytY3/m94MFuVBcz/P86aY8l8HXBuUBxycDFai/MwYo6o0K2IpSKYZqny
BxT3+yZrsFFi3AIPg4ta3aAYDZCLKdxx5YXiF/ZFLr4s4fyD3AJOeGvDhXrRQaXq
NCPlSnFaMqS4cPbj43McYo9NhUT8OV0h73Zf32/e7MpE412DxTTYdtfZD3vTMRfS
4ZGs1PibHiBA5oPkD9xCiuFEIvwuy28YOZF8wILOSE1iEFFGfTNTCE7fs36ApYus
3JzmB94cWDas4Er3LwZrhv+j3DCuR0Q6iPzN9oNZh8vjpSzMyg2Va5soMTbfvQkC
tDE8l8k8Xu38QLOKpGWXY83eXstNmACv5WGEi4Krgpng6ybFMjEPOZ1bdPbPmBJZ
JENpp6Os2O2XPj+U/iBoYMR/3qFKv1Pd2ZIEwscZBMzXUvj8Wui2UeAsjk1M4bkw
S64cN5CR2sA2waauByMFRfyUPWJIKArEFiW7qFCHRCTusAa5nkrJV/iY
-----END ENCRYPTED PRIVATE KEY-----

35
test/ssl/server.pem Normal file
View File

@ -0,0 +1,35 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOZn52tnufSaCjj
Y23E0Pe4oKhlUToSL4yAnPj1K4v+9nN/IKJz07XHUZD5+Ypx1QUsq1WlBiyY2+il
ODvrhPN7gORIFn4P1tAQO/FuSBgTwTdbFdELAvJ2GpSwwzid6qBtYl82sVaWoLdV
G+jHItRfHG9J9ELTlsC8pTrMB+/DAgMBAAECgYEAq6kya2nBw1HXvGwUaqXD3WPD
ujlPtyuvtW1Va0cCh/VUnIgiwofy1cKYcmPJRL5qUWNWsAlLw/xSUx9OSpYb6S1v
Ddpk3RLnq4axc4fCuZNQ5xepT1lFJQXyZVS7DsVkfjm7vEYl6sXQTFh/7Sv+vhkn
s0XocET0xY95zR7JnekCQQDyq4HcQg+vhkdStj4fh7fHdkMKA91QHLOVcjTeKeIS
mK1h2BXXaA50RAQdA0e9PFdXR+AHhNq79I1dhJPw4N8FAkEA3zk0BEjDt/zWYrJb
zuC6BVYeULsrxO5331sLNmrO4j6NMSLSTV5gclCr4JANfNhHYdVlNjw9y5l2t9GD
nLP+JwJBANq9IecqXP04qp2xzDmbmlrfDPrAFQObe3zgXytK0Y81tEOYBcgO8ch3
bsXAKTA4bfosvZHJfWkivTJoyPm9mQkCQChVq8KCa2sZcpuO4uv0y2gfcYbg6z3A
YUSorNP+ZLeY2eZhBmMYhJDjZstC/Ezsv6k75/fu1rOtXThF0WRFWc0CQDeCjzUO
PEnd60cvLNvU8v8fcFZkezNOOqhwDt7qKKpxWw8kuCGZAeiD7qNLDrZBlP00CQ3R
xbS/tkvxXibulgI=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDCDCCAnGgAwIBAgIJAJknelvWNnggMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
VQQGEwJBVTEWMBQGA1UECAwNdGVzdCBwcm92aW5jZTESMBAGA1UEBwwJdGVzdCBj
aXR5MREwDwYDVQQKDAh0ZXN0IG9yZzEYMBYGA1UECwwPdGVzdCBkZXBhcnRtZW50
MRIwEAYDVQQDDAkxMjcuMC4wLjExIDAeBgkqhkiG9w0BCQEWEXRlc3RAdGVzdC5j
b25/bX9tMB4XDTEzMDcyNzE0MTExMVoXDTIzMDcyNTE0MTExMVowgZwxCzAJBgNV
BAYTAkFVMRYwFAYDVQQIDA10ZXN0IHByb3ZpbmNlMRIwEAYDVQQHDAl0ZXN0IGNp
dHkxETAPBgNVBAoMCHRlc3Qgb3JnMRgwFgYDVQQLDA90ZXN0IGRlcGFydG1lbnQx
EjAQBgNVBAMMCTEyNy4wLjAuMTEgMB4GCSqGSIb3DQEJARYRdGVzdEB0ZXN0LmNv
bn9tf20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOZn52tnufSaCjjY23E
0Pe4oKhlUToSL4yAnPj1K4v+9nN/IKJz07XHUZD5+Ypx1QUsq1WlBiyY2+ilODvr
hPN7gORIFn4P1tAQO/FuSBgTwTdbFdELAvJ2GpSwwzid6qBtYl82sVaWoLdVG+jH
ItRfHG9J9ELTlsC8pTrMB+/DAgMBAAGjUDBOMB0GA1UdDgQWBBT3G2k/6L5UdDpQ
Rj4RR6nUVPVTDDAfBgNVHSMEGDAWgBT3G2k/6L5UdDpQRj4RR6nUVPVTDDAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABHQx77KIJlUnCwg3mwYob3NA+uN
njwlrJjC9ZVVwabJiZvbMPqQVc4CkzN3gvVYpMIMzW28idsy5lH/oduC06dLt06E
TyJvolwSVrLf//zbVwgI8RFBDlgGUNGEZXxBUyEiD/YcEIyC40JadUrwyvLdmezj
itBP2eZmwxC1q8GP
-----END CERTIFICATE-----

204
test/test_ssl.cpp Normal file
View File

@ -0,0 +1,204 @@
/*
Copyright (c) 2013, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>
using namespace libtorrent;
using boost::tuples::ignore;
int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;
struct test_config_t
{
char const* name;
bool use_ssl_ports;
bool seed_has_cert;
bool downloader_has_cert;
bool expected_to_complete;
};
test_config_t test_config[] =
{
{"nobody has a cert (connect to regular port)", false, false, false, false},
{"nobody has a cert (connect to ssl port)", true, false, false, false},
{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false},
{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false},
{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false},
{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false},
{"both downloader and seed has a cert (connect to regular port)", false, true, true, false},
#ifdef TORRENT_USE_OPENSSL
{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true},
#else
{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false},
#endif
};
int peer_disconnects = 0;
bool predicate(alert* a)
{
if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(a))
++peer_disconnects;
return false;
}
void test_ssl(int test_idx)
{
test_config_t const& test = test_config[test_idx];
fprintf(stderr, "\n%s TEST: %s\n\n", time_now_string(), test.name);
// in case the previous run was terminated
error_code ec;
remove_all("tmp1_ssl", ec);
remove_all("tmp2_ssl", ec);
session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);
session_settings sett;
// this disables outgoing SSL connections
sett.ssl_listen = 0;
if (!test.downloader_has_cert) ses2.set_settings(sett);
torrent_handle tor1;
torrent_handle tor2;
create_directory("tmp1_ssl", ec);
std::ofstream file("tmp1_ssl/temporary");
boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "ssl/root_ca_cert.pem");
file.close();
add_torrent_params addp;
addp.flags &= ~add_torrent_params::flag_paused;
addp.flags &= ~add_torrent_params::flag_auto_managed;
wait_for_listen(ses1, "ses1");
wait_for_listen(ses2, "ses1");
peer_disconnects = 0;
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);
if (test.seed_has_cert)
{
tor1.set_ssl_certificate(combine_path("ssl", "peer_certificate.pem")
, combine_path("ssl", "peer_private_key.pem")
, combine_path("ssl", "dhparams.pem")
, "test");
}
if (test.downloader_has_cert)
{
tor2.set_ssl_certificate(combine_path("ssl", "peer_certificate.pem")
, combine_path("ssl", "peer_private_key.pem")
, combine_path("ssl", "dhparams.pem")
, "test");
}
for (int i = 0; i < 15; ++i)
{
print_alerts(ses1, "ses1", true, true, true, &predicate);
print_alerts(ses2, "ses2", true, true, true, &predicate);
torrent_status st1 = tor1.status();
torrent_status st2 = tor2.status();
if (i % 10 == 0)
{
std::cerr << time_now_string() << " "
<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
<< "\033[0m" << int(st1.progress * 100) << "% "
<< st1.num_peers
<< ": "
<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
<< "\033[0m" << int(st2.progress * 100) << "% "
<< st2.num_peers
<< " cc: " << st2.connect_candidates
<< std::endl;
}
if (peer_disconnects == 2) break;
if (st2.is_finished) break;
if (st2.state != torrent_status::downloading)
{
static char const* state_str[] =
{"checking (q)", "checking", "dl metadata"
, "downloading", "finished", "seeding", "allocating", "checking (r)"};
std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
}
TEST_CHECK(st1.state == torrent_status::seeding
|| st1.state == torrent_status::checking_files);
TEST_CHECK(st2.state == torrent_status::downloading);
test_sleep(100);
}
TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);
}
int test_main()
{
using namespace libtorrent;
test_ssl(7);
// for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
// test_ssl(i);
error_code ec;
remove_all("tmp1_ssl", ec);
remove_all("tmp2_ssl", ec);
return 0;
}

View File

@ -53,6 +53,15 @@ int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;
int peer_disconnects = 0;
bool predicate(alert* a)
{
if (peer_disconnected_alert* p = alert_cast<peer_disconnected_alert>(a))
++peer_disconnects;
return false;
}
// test the maximum transfer rate
void test_rate()
{
@ -77,15 +86,17 @@ void test_rate()
wait_for_listen(ses1, "ses1");
wait_for_listen(ses2, "ses1");
peer_disconnects = 0;
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
, true, false, true, "_transfer", 0, &t);
ptime start = time_now();
for (int i = 0; i < 70; ++i)
for (int i = 0; i < 50; ++i)
{
print_alerts(ses1, "ses1");
print_alerts(ses2, "ses2");
print_alerts(ses1, "ses1", true, true, true, &predicate);
print_alerts(ses2, "ses2", true, true, true, &predicate);
torrent_status st1 = tor1.status();
torrent_status st2 = tor2.status();
@ -93,6 +104,7 @@ void test_rate()
if (i % 10 == 0)
print_ses_rate(i / 10.f, &st1, &st2);
if (peer_disconnects == 2) break;
if (st2.is_seeding) break;
test_sleep(100);
}
@ -221,6 +233,10 @@ bool on_alert(alert* a)
{
if (alert_cast<tracker_reply_alert>(a))
++tracker_responses;
if (alert_cast<peer_disconnected_alert>(a))
++peer_disconnects;
return false;
}
@ -326,6 +342,8 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
wait_for_listen(ses1, "ses1");
wait_for_listen(ses2, "ses1");
peer_disconnects = 0;
// test using piece sizes smaller than 16kB
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
, true, false, true, "_transfer", 8 * 1024, &t, false, test_disk_full?&addp:0);
@ -398,6 +416,8 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
TEST_CHECK(st2.state == torrent_status::downloading
|| (test_disk_full && !st2.error.empty()));
if (peer_disconnects == 2) break;
test_sleep(100);
}
@ -416,10 +436,13 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
std::cerr << "force recheck" << std::endl;
tor2.force_recheck();
peer_disconnects = 0;
for (int i = 0; i < 50; ++i)
{
test_sleep(100);
print_alerts(ses2, "ses2");
print_alerts(ses2, "ses2", true, true, true, on_alert);
torrent_status st2 = tor2.status();
if (i % 10 == 0)
{
@ -433,7 +456,7 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
for (int i = 0; i < 5; ++i)
{
print_alerts(ses2, "ses2");
print_alerts(ses2, "ses2", true, true, true, on_alert);
torrent_status st2 = tor2.status();
TEST_CHECK(st2.state == torrent_status::finished);
test_sleep(100);
@ -509,8 +532,8 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
for (int i = 0; i < 5; ++i)
{
print_alerts(ses1, "ses1");
print_alerts(ses2, "ses2");
print_alerts(ses1, "ses1", true, true, true, on_alert);
print_alerts(ses2, "ses2", true, true, true, on_alert);
torrent_status st1 = tor1.status();
torrent_status st2 = tor2.status();
@ -529,8 +552,8 @@ void test_transfer(int proxy_type, bool test_disk_full = false, bool test_allowe
for (int i = 0; i < 130; ++i)
{
print_alerts(ses1, "ses1");
print_alerts(ses2, "ses2");
print_alerts(ses1, "ses1", true, true, true, on_alert);
print_alerts(ses2, "ses2", true, true, true, on_alert);
torrent_status st1 = tor1.status();
torrent_status st2 = tor2.status();