Add --min-tls-version option

The --min-tls-version option specifies minimum SSL/TLS version to
enable. Possible Values: SSLv3, TLSv1, TLSv1.1, TLSv1.2 Default: TLSv1
pull/311/head
Tatsuhiro Tsujikawa 2014-12-06 00:26:43 +09:00
parent 62fba76666
commit 73d752fb1c
19 changed files with 183 additions and 33 deletions

View File

@ -1321,6 +1321,12 @@ Advanced Options
given URIs do not support resume. See :option:`--always-resume` option.
Default: ``0``
.. option:: --min-tls-version=<VERSION>
Specify minimum SSL/TLS version to enable.
Possible Values: ``SSLv3``, ``TLSv1``, ``TLSv1.1``, ``TLSv1.2``
Default: ``TLSv1``
.. option:: --log-level=<LEVEL>
Set log level to output.

View File

@ -195,9 +195,9 @@ bool checkIdentity(const SecIdentityRef id,
namespace aria2 {
TLSContext* TLSContext::make(TLSSessionSide side)
TLSContext* TLSContext::make(TLSSessionSide side, TLSVersion ver)
{
return new AppleTLSContext(side);
return new AppleTLSContext(side, ver);
}
AppleTLSContext::~AppleTLSContext()

View File

@ -49,8 +49,8 @@ namespace aria2 {
class AppleTLSContext : public TLSContext
{
public:
AppleTLSContext(TLSSessionSide side)
: side_(side), verifyPeer_(true), credentials_(nullptr)
AppleTLSContext(TLSSessionSide side, TLSVersion ver)
: side_(side), minTLSVer_(ver), verifyPeer_(true), credentials_(nullptr)
{}
virtual ~AppleTLSContext();
@ -89,8 +89,14 @@ public:
SecIdentityRef getCredentials();
TLSVersion getMinTLSVersion() const
{
return minTLSVer_;
}
private:
TLSSessionSide side_;
TLSVersion minTLSVer_;
bool verifyPeer_;
SecIdentityRef credentials_;

View File

@ -362,14 +362,36 @@ AppleTLSSession::AppleTLSSession(AppleTLSContext* ctx)
return;
}
#if defined(__MAC_10_8)
switch (ctx->getMinTLSVersion()) {
case TLS_PROTO_SSL3:
(void)SSLSetProtocolVersionMin(sslCtx_, kSSLProtocol3);
break;
case TLS_PROTO_TLS10:
(void)SSLSetProtocolVersionMin(sslCtx_, kSSLProtocol1);
break;
case TLS_PROTO_TLS11:
(void)SSLSetProtocolVersionMin(sslCtx_, kSSLProtocol11);
break;
case TLS_PROTO_TLS12:
(void)SSLSetProtocolVersionMin(sslCtx_, kSSLProtocol12);
break;
}
(void)SSLSetProtocolVersionMax(sslCtx_, kTLSProtocol12);
#else
(void)SSLSetProtocolVersionEnabled(sslCtx_, kSSLProtocolAll, false);
switch (ctx->getMinTLSVersion()) {
case TLS_PROTO_SSL3:
(void)SSLSetProtocolVersionEnabled(sslCtx_, kSSLProtocol3, true);
// fall through
case TLS_PROTO_TLS10:
(void)SSLSetProtocolVersionEnabled(sslCtx_, kTLSProtocol1, true);
// fall through
case TLS_PROTO_TLS11:
(void)SSLSetProtocolVersionEnabled(sslCtx_, kTLSProtocol11, true);
// fall through
case TLS_PROTO_TLS12:
(void)SSLSetProtocolVersionEnabled(sslCtx_, kTLSProtocol12, true);
}
#endif
// BEAST

View File

@ -49,14 +49,15 @@
namespace aria2 {
TLSContext* TLSContext::make(TLSSessionSide side)
TLSContext* TLSContext::make(TLSSessionSide side, TLSVersion ver)
{
return new GnuTLSContext(side);
return new GnuTLSContext(side, ver);
}
GnuTLSContext::GnuTLSContext(TLSSessionSide side)
GnuTLSContext::GnuTLSContext(TLSSessionSide side, TLSVersion ver)
: certCred_(0),
side_(side),
minTLSVer_(ver),
verifyPeer_(true)
{
int r = gnutls_certificate_allocate_credentials(&certCred_);

View File

@ -46,7 +46,7 @@ namespace aria2 {
class GnuTLSContext : public TLSContext {
public:
GnuTLSContext(TLSSessionSide side);
GnuTLSContext(TLSSessionSide side, TLSVersion ver);
virtual ~GnuTLSContext();
@ -79,9 +79,15 @@ public:
gnutls_certificate_credentials_t getCertCred() const;
TLSVersion getMinTLSVersion() const
{
return minTLSVer_;
}
private:
gnutls_certificate_credentials_t certCred_;
TLSSessionSide side_;
TLSVersion minTLSVer_;
bool good_;
bool verifyPeer_;
};

View File

@ -107,7 +107,20 @@ int GnuTLSSession::init(sock_t sockfd)
// It seems err is not error message, but the argument string
// which causes syntax error.
const char* err;
rv_ = gnutls_priority_set_direct(sslSession_, "SECURE128:-VERS-SSL3.0", &err);
std::string pri = "SECURE128";
switch(tlsContext_->getMinTLSVersion()) {
case TLS_PROTO_TLS12:
pri += ":-VERS-TLS1.1";
// fall through
case TLS_PROTO_TLS11:
pri += ":-VERS-TLS1.0";
// fall through
case TLS_PROTO_TLS10:
pri += ":-VERS-SSL3.0";
default:
break;
};
rv_ = gnutls_priority_set_direct(sslSession_, pri.c_str(), &err);
if(rv_ != GNUTLS_E_SUCCESS) {
return TLS_ERR_ERROR;
}

View File

@ -81,12 +81,12 @@ namespace {
namespace aria2 {
TLSContext* TLSContext::make(TLSSessionSide side)
TLSContext* TLSContext::make(TLSSessionSide side, TLSVersion minVer)
{
return new OpenSSLTLSContext(side);
return new OpenSSLTLSContext(side, minVer);
}
OpenSSLTLSContext::OpenSSLTLSContext(TLSSessionSide side)
OpenSSLTLSContext::OpenSSLTLSContext(TLSSessionSide side, TLSVersion minVer)
: sslCtx_(nullptr),
side_(side),
verifyPeer_(true)
@ -100,8 +100,23 @@ OpenSSLTLSContext::OpenSSLTLSContext(TLSSessionSide side)
ERR_error_string(ERR_get_error(), nullptr)));
return;
}
// Disable SSLv2/3 and enable all workarounds for buggy servers
SSL_CTX_set_options(sslCtx_, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3
long ver_opts = 0;
switch(minVer) {
case TLS_PROTO_TLS12:
ver_opts |= SSL_OP_NO_TLSv1_1;
// fall through
case TLS_PROTO_TLS11:
ver_opts |= SSL_OP_NO_TLSv1;
// fall through
case TLS_PROTO_TLS10:
ver_opts |= SSL_OP_NO_SSLv3;
default:
break;
};
// Disable SSLv2 and enable all workarounds for buggy servers
SSL_CTX_set_options(sslCtx_, SSL_OP_ALL | SSL_OP_NO_SSLv2 | ver_opts
#ifdef SSL_OP_SINGLE_ECDH_USE
| SSL_OP_SINGLE_ECDH_USE
#endif // SSL_OP_SINGLE_ECDH_USE

View File

@ -48,7 +48,7 @@ namespace aria2 {
class OpenSSLTLSContext : public TLSContext {
public:
OpenSSLTLSContext(TLSSessionSide side);
OpenSSLTLSContext(TLSSessionSide side, TLSVersion minVer);
~OpenSSLTLSContext();

View File

@ -188,7 +188,9 @@ int MultiUrlRequestInfo::prepare()
}
// We set server TLS context to the SocketCore before creating
// DownloadEngine instance.
std::shared_ptr<TLSContext> svTlsContext(TLSContext::make(TLS_SERVER));
auto minTLSVer = util::toTLSVersion(option_->get(PREF_MIN_TLS_VERSION));
std::shared_ptr<TLSContext> svTlsContext
(TLSContext::make(TLS_SERVER, minTLSVer));
if(!svTlsContext->addCredentialFile
(option_->get(PREF_RPC_CERTIFICATE),
option_->get(PREF_RPC_PRIVATE_KEY))) {
@ -245,7 +247,9 @@ int MultiUrlRequestInfo::prepare()
e_->setAuthConfigFactory(std::move(authConfigFactory));
#ifdef ENABLE_SSL
std::shared_ptr<TLSContext> clTlsContext(TLSContext::make(TLS_CLIENT));
auto minTLSVer = util::toTLSVersion(option_->get(PREF_MIN_TLS_VERSION));
std::shared_ptr<TLSContext> clTlsContext
(TLSContext::make(TLS_CLIENT, minTLSVer));
if(!option_->blank(PREF_CERTIFICATE)) {
clTlsContext->addCredentialFile(option_->get(PREF_CERTIFICATE),
option_->get(PREF_PRIVATE_KEY));

View File

@ -584,6 +584,17 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
op->setChangeOptionForReserved(true);
handlers.push_back(op);
}
#ifdef ENABLE_SSL
{
OptionHandler* op(new ParameterOptionHandler
(PREF_MIN_TLS_VERSION,
TEXT_MIN_TLS_VERSION,
A2_V_TLS10,
{ A2_V_SSL3, A2_V_TLS10, A2_V_TLS11, A2_V_TLS12 }));
op->addTag(TAG_ADVANCED);
handlers.push_back(op);
}
#endif // ENABLE_SSL
{
OptionHandler* op(new BooleanOptionHandler
(PREF_NO_CONF,

View File

@ -46,9 +46,16 @@ enum TLSSessionSide {
TLS_SERVER
};
enum TLSVersion {
TLS_PROTO_SSL3,
TLS_PROTO_TLS10,
TLS_PROTO_TLS11,
TLS_PROTO_TLS12,
};
class TLSContext {
public:
static TLSContext* make(TLSSessionSide side);
static TLSContext* make(TLSSessionSide side, TLSVersion minVer);
virtual ~TLSContext() {}
// private key `keyfile' must be decrypted.

View File

@ -63,28 +63,50 @@
namespace aria2 {
WinTLSContext::WinTLSContext(TLSSessionSide side) : side_(side), store_(0)
WinTLSContext::WinTLSContext(TLSSessionSide side, TLSVersion ver)
: side_(side), store_(0)
{
memset(&credentials_, 0, sizeof(credentials_));
credentials_.dwVersion = SCHANNEL_CRED_VERSION;
credentials_.grbitEnabledProtocols = 0;
if (side_ == TLS_CLIENT) {
credentials_.grbitEnabledProtocols =
SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT |
SP_PROT_TLS1_2_CLIENT;
switch (ver) {
case TLS_PROTO_SSL3:
credentials_.grbitEnabledProtocols |= SP_PROT_SSL3_CLIENT;
// fall through
case TLS_PROTO_TLS10:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_CLIENT;
// fall through
case TLS_PROTO_TLS11:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
// fall through
case TLS_PROTO_TLS12:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
}
}
else {
credentials_.grbitEnabledProtocols =
SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER | SP_PROT_TLS1_1_SERVER |
SP_PROT_TLS1_2_SERVER;
switch (ver) {
case TLS_PROTO_SSL3:
credentials_.grbitEnabledProtocols |= SP_PROT_SSL3_SERVER;
// fall through
case TLS_PROTO_TLS10:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_SERVER;
// fall through
case TLS_PROTO_TLS11:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_1_SERVER;
// fall through
case TLS_PROTO_TLS12:
credentials_.grbitEnabledProtocols |= SP_PROT_TLS1_2_SERVER;
}
}
credentials_.dwMinimumCipherStrength = 128; // bit
setVerifyPeer(side_ == TLS_CLIENT);
}
TLSContext* TLSContext::make(TLSSessionSide side)
TLSContext* TLSContext::make(TLSSessionSide side, TLSVersion ver)
{
return new WinTLSContext(side);
return new WinTLSContext(side, ver);
}
WinTLSContext::~WinTLSContext()

View File

@ -67,7 +67,7 @@ typedef std::unique_ptr<CredHandle, cred_deleter> CredPtr;
class WinTLSContext : public TLSContext
{
public:
WinTLSContext(TLSSessionSide side);
WinTLSContext(TLSSessionSide side, TLSVersion ver);
virtual ~WinTLSContext();

View File

@ -169,6 +169,10 @@ const std::string V_ARC4("arc4");
const std::string V_HTTP("http");
const std::string V_HTTPS("https");
const std::string V_FTP("ftp");
const std::string A2_V_SSL3("SSLv3");
const std::string A2_V_TLS10("TLSv1");
const std::string A2_V_TLS11("TLSv1.1");
const std::string A2_V_TLS12("TLSv1.2");
PrefPtr PREF_VERSION = makePref("version");
PrefPtr PREF_HELP = makePref("help");
@ -367,6 +371,8 @@ PrefPtr PREF_DSCP = makePref("dscp");
PrefPtr PREF_PAUSE_METADATA = makePref("pause-metadata");
// values: 1*digit
PrefPtr PREF_RLIMIT_NOFILE = makePref("rlimit-nofile");
// vlaues: SSLv3 | TLSv1 | TLSv1.1 | TLSv1.2
PrefPtr PREF_MIN_TLS_VERSION = makePref("min-tls-version");
/**
* FTP related preferences

View File

@ -105,6 +105,10 @@ extern const std::string V_ARC4;
extern const std::string V_HTTP;
extern const std::string V_HTTPS;
extern const std::string V_FTP;
extern const std::string A2_V_SSL3;
extern const std::string A2_V_TLS10;
extern const std::string A2_V_TLS11;
extern const std::string A2_V_TLS12;
extern PrefPtr PREF_VERSION;
extern PrefPtr PREF_HELP;
@ -304,6 +308,8 @@ extern PrefPtr PREF_DSCP;
extern PrefPtr PREF_PAUSE_METADATA;
// values: 1*digit
extern PrefPtr PREF_RLIMIT_NOFILE;
// vlaues: SSLv3 | TLSv1 | TLSv1.1 | TLSv1.2
extern PrefPtr PREF_MIN_TLS_VERSION;
/**
* FTP related preferences

View File

@ -1011,3 +1011,5 @@
" and the next download waiting in queue gets\n" \
" started. But be aware that seeding item is still\n" \
" recognized as active download in RPC method.")
#define TEXT_MIN_TLS_VERSION \
_(" --min-tls-version=VERSION Specify minimum SSL/TLS version to enable.")

View File

@ -2009,6 +2009,23 @@ bool strless(const char* a, const char* b)
return strcmp(a, b) < 0;
}
TLSVersion toTLSVersion(const std::string& ver)
{
if(ver == A2_V_SSL3) {
return TLS_PROTO_SSL3;
}
if(ver == A2_V_TLS10) {
return TLS_PROTO_TLS10;
}
if(ver == A2_V_TLS11) {
return TLS_PROTO_TLS11;
}
if(ver == A2_V_TLS12) {
return TLS_PROTO_TLS12;
}
return TLS_PROTO_TLS10;
}
} // namespace util
} // namespace aria2

View File

@ -64,6 +64,10 @@
#include "fmt.h"
#include "prefs.h"
#ifdef ENABLE_SSL
#include "TLSContext.h"
#endif // ENABLE_SSL
#ifndef HAVE_SIGACTION
# define sigset_t int
#endif // HAVE_SIGACTION
@ -880,6 +884,8 @@ bool noProxyDomainMatch(const std::string& hostname, const std::string& domain);
// Checks hostname matches pattern as described in RFC 6125.
bool tlsHostnameMatch(const std::string& pattern, const std::string& hostname);
TLSVersion toTLSVersion(const std::string& ver);
} // namespace util
} // namespace aria2