Add SSLConfig object to IceServer.

This is a rollforward of https://webrtc-review.googlesource.com/c/src/+/96020,
with the addition of setting the old tlsCertPolicy, tlsAlpnProtocols and
tlsEllipticCurves in the RTCIceServer initializer, for backwards compatibility.

Bug: webrtc:9662
Change-Id: I28706ed4ff5abe3f7f913f105779f0e5412aeac5
Reviewed-on: https://webrtc-review.googlesource.com/98762
Commit-Queue: Diogo Real <diogor@google.com>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24696}
This commit is contained in:
Diogo Real
2018-09-11 16:00:22 -07:00
committed by Commit Bot
parent e0c8b230e7
commit 4f085434b9
31 changed files with 1093 additions and 183 deletions

View File

@ -209,7 +209,6 @@ OpenSSLAdapter::OpenSSLAdapter(AsyncSocket* socket,
ssl_(nullptr),
ssl_ctx_(nullptr),
ssl_mode_(SSL_MODE_TLS),
ignore_bad_cert_(false),
custom_cert_verifier_status_(false) {
// If a factory is used, take a reference on the factory's SSL_CTX.
// Otherwise, we'll create our own later.
@ -226,16 +225,8 @@ OpenSSLAdapter::~OpenSSLAdapter() {
Cleanup();
}
void OpenSSLAdapter::SetIgnoreBadCert(bool ignore) {
ignore_bad_cert_ = ignore;
}
void OpenSSLAdapter::SetAlpnProtocols(const std::vector<std::string>& protos) {
alpn_protocols_ = protos;
}
void OpenSSLAdapter::SetEllipticCurves(const std::vector<std::string>& curves) {
elliptic_curves_ = curves;
void OpenSSLAdapter::SetSSLConfig(const SSLConfig& ssl_config) {
ssl_config_ = ssl_config;
}
void OpenSSLAdapter::SetMode(SSLMode mode) {
@ -269,7 +260,7 @@ AsyncSocket* OpenSSLAdapter::Accept(SocketAddress* paddr) {
SSLAdapter* adapter = SSLAdapter::Create(socket);
adapter->SetIdentity(identity_->GetReference());
adapter->SetRole(rtc::SSL_SERVER);
adapter->SetIgnoreBadCert(ignore_bad_cert_);
adapter->SetSSLConfig(ssl_config_);
adapter->StartSSL("", false);
return adapter;
}
@ -367,13 +358,28 @@ int OpenSSLAdapter::BeginSSL() {
}
#ifdef OPENSSL_IS_BORINGSSL
// Set a couple common TLS extensions; even though we don't use them yet.
SSL_enable_ocsp_stapling(ssl_);
SSL_enable_signed_cert_timestamps(ssl_);
// Potentially set a couple common TLS extensions; even though we don't use
// them yet.
if (ssl_config_.enable_ocsp_stapling) {
SSL_enable_ocsp_stapling(ssl_);
}
if (ssl_config_.enable_signed_cert_timestamp) {
SSL_enable_signed_cert_timestamps(ssl_);
}
SSL_CTX_set_grease_enabled(ssl_ctx_, ssl_config_.enable_grease);
#endif
if (!alpn_protocols_.empty()) {
std::string tls_alpn_string = TransformAlpnProtocols(alpn_protocols_);
if (ssl_config_.max_ssl_version.has_value()) {
SSL_set_max_proto_version(ssl_, ssl_config_.max_ssl_version.value());
}
if (ssl_config_.enable_tls_channel_id) {
SSL_enable_tls_channel_id(ssl_);
}
if (ssl_config_.tls_alpn_protocols.has_value()) {
std::string tls_alpn_string =
TransformAlpnProtocols(ssl_config_.tls_alpn_protocols.value());
if (!tls_alpn_string.empty()) {
SSL_set_alpn_protos(
ssl_, reinterpret_cast<const unsigned char*>(tls_alpn_string.data()),
@ -381,8 +387,9 @@ int OpenSSLAdapter::BeginSSL() {
}
}
if (!elliptic_curves_.empty()) {
SSL_set1_curves_list(ssl_, rtc::join(elliptic_curves_, ':').c_str());
if (ssl_config_.tls_elliptic_curves.has_value()) {
SSL_set1_curves_list(
ssl_, rtc::join(ssl_config_.tls_elliptic_curves.value(), ':').c_str());
}
// Now that the initial config is done, transfer ownership of |bio| to the
@ -794,10 +801,10 @@ bool OpenSSLAdapter::SSLPostConnectionCheck(SSL* ssl, const std::string& host) {
openssl::VerifyPeerCertMatchesHost(ssl, host) &&
(SSL_get_verify_result(ssl) == X509_V_OK || custom_cert_verifier_status_);
if (!is_valid_cert_name && ignore_bad_cert_) {
if (!is_valid_cert_name && ShouldIgnoreBadCert()) {
RTC_DLOG(LS_WARNING) << "Other TLS post connection checks failed. "
"ignore_bad_cert_ set to true. Overriding name "
"verification failure!";
"TLS cert policy set to ignore bad certs. "
"Overriding name verification failure!";
is_valid_cert_name = true;
}
return is_valid_cert_name;
@ -870,7 +877,7 @@ int OpenSSLAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
}
// Should only be used for debugging and development.
if (!ok && stream->ignore_bad_cert_) {
if (!ok && stream->ShouldIgnoreBadCert()) {
RTC_DLOG(LS_WARNING) << "Ignoring cert error while verifying cert chain";
ok = 1;
}
@ -941,6 +948,11 @@ SSL_CTX* OpenSSLAdapter::CreateContext(SSLMode mode, bool enable_cache) {
return ctx;
}
bool OpenSSLAdapter::ShouldIgnoreBadCert() {
return ssl_config_.tls_cert_policy ==
TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK;
}
std::string TransformAlpnProtocols(
const std::vector<std::string>& alpn_protocols) {
// Transforms the alpn_protocols list to the format expected by

View File

@ -45,9 +45,7 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
SSLCertificateVerifier* ssl_cert_verifier = nullptr);
~OpenSSLAdapter() override;
void SetIgnoreBadCert(bool ignore) override;
void SetAlpnProtocols(const std::vector<std::string>& protos) override;
void SetEllipticCurves(const std::vector<std::string>& curves) override;
void SetSSLConfig(const SSLConfig& ssl_config) override;
void SetMode(SSLMode mode) override;
void SetCertVerifier(SSLCertificateVerifier* ssl_cert_verifier) override;
void SetIdentity(SSLIdentity* identity) override;
@ -95,6 +93,9 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
void Error(const char* context, int err, bool signal = true);
void Cleanup();
// If true, the server certificate need not match the configured hostname.
bool ShouldIgnoreBadCert();
// Return value and arguments have the same meanings as for Send; |error| is
// an output parameter filled with the result of SSL_get_error.
int DoSslWrite(const void* pv, size_t cb, int* error);
@ -138,12 +139,8 @@ class OpenSSLAdapter : public SSLAdapter, public MessageHandler {
std::string ssl_host_name_;
// Set the adapter to DTLS or TLS mode before creating the context.
SSLMode ssl_mode_;
// If true, the server certificate need not match the configured hostname.
bool ignore_bad_cert_;
// List of protocols to be used in the TLS ALPN extension.
std::vector<std::string> alpn_protocols_;
// List of elliptic curves to be used in the TLS elliptic curves extension.
std::vector<std::string> elliptic_curves_;
// SSL configuration for this session.
SSLConfig ssl_config_;
// Holds the result of the call to run of the ssl_cert_verify_->Verify()
bool custom_cert_verifier_status_;
};

View File

@ -16,6 +16,12 @@
namespace rtc {
SSLConfig::SSLConfig() = default;
SSLConfig::SSLConfig(const SSLConfig&) = default;
SSLConfig::~SSLConfig() = default;
///////////////////////////////////////////////////////////////////////////////
SSLAdapterFactory* SSLAdapterFactory::Create() {
return new OpenSSLAdapterFactory();
}

View File

@ -22,6 +22,57 @@ namespace rtc {
class SSLAdapter;
// TLS certificate policy.
enum class TlsCertPolicy {
// For TLS based protocols, ensure the connection is secure by not
// circumventing certificate validation.
TLS_CERT_POLICY_SECURE,
// For TLS based protocols, disregard security completely by skipping
// certificate validation. This is insecure and should never be used unless
// security is irrelevant in that particular context.
// Do not set to this value in production code.
// TODO(juberti): Remove the opportunistic encryption mechanism in
// BasicPacketSocketFactory that uses this value.
TLS_CERT_POLICY_INSECURE_NO_CHECK,
};
// SSL configuration options.
struct SSLConfig final {
SSLConfig();
SSLConfig(const SSLConfig&);
~SSLConfig();
bool operator==(const SSLConfig& o) const {
return enable_ocsp_stapling == o.enable_ocsp_stapling &&
enable_signed_cert_timestamp == o.enable_signed_cert_timestamp &&
enable_tls_channel_id == o.enable_tls_channel_id &&
enable_grease == o.enable_grease &&
max_ssl_version == o.max_ssl_version &&
tls_alpn_protocols == o.tls_alpn_protocols &&
tls_elliptic_curves == o.tls_elliptic_curves;
}
bool operator!=(const SSLConfig& o) const { return !(*this == o); }
// If true, enables the (unused) OCSP stapling TLS extension.
bool enable_ocsp_stapling = true;
// If true, enables the (unused) signed certificate timestamp TLS extension.
bool enable_signed_cert_timestamp = true;
// If true, enables the (unused) channel ID TLS extension.
bool enable_tls_channel_id = false;
// If true, enables the (unused) GREASE TLS extension.
bool enable_grease = false;
// Indicates how to process incoming certificates.
TlsCertPolicy tls_cert_policy = TlsCertPolicy::TLS_CERT_POLICY_SECURE;
// If set, indicates the highest supported SSL version.
absl::optional<int> max_ssl_version;
// If set, indicates the list of protocols to be used in the TLS ALPN
// extension.
absl::optional<std::vector<std::string>> tls_alpn_protocols;
// If set, indicates the list of curves to be used in the TLS elliptic curves
// extension.
absl::optional<std::vector<std::string>> tls_elliptic_curves;
};
// Class for creating SSL adapters with shared state, e.g., a session cache,
// which allows clients to resume SSL sessions to previously-contacted hosts.
// Clients should create the factory using Create(), set up the factory as
@ -52,14 +103,8 @@ class SSLAdapter : public AsyncSocketAdapter {
public:
explicit SSLAdapter(AsyncSocket* socket) : AsyncSocketAdapter(socket) {}
// Methods that control server certificate verification, used in unit tests.
// Do not call these methods in production code.
// TODO(juberti): Remove the opportunistic encryption mechanism in
// BasicPacketSocketFactory that uses this function.
virtual void SetIgnoreBadCert(bool ignore) = 0;
virtual void SetAlpnProtocols(const std::vector<std::string>& protos) = 0;
virtual void SetEllipticCurves(const std::vector<std::string>& curves) = 0;
// Sets the SSL configuration for this session.
virtual void SetSSLConfig(const SSLConfig& ssl_config) = 0;
// Do DTLS or TLS (default is TLS, if unspecified)
virtual void SetMode(SSLMode mode) = 0;

View File

@ -67,7 +67,9 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
// Ignore any certificate errors for the purpose of testing.
// Note: We do this only because we don't have a real certificate.
// NEVER USE THIS IN PRODUCTION CODE!
ssl_adapter_->SetIgnoreBadCert(true);
ssl_config_.tls_cert_policy =
rtc::TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK;
ssl_adapter_->SetSSLConfig(ssl_config_);
ssl_adapter_->SignalReadEvent.connect(
this, &SSLAdapterTestDummyClient::OnSSLAdapterReadEvent);
@ -75,22 +77,52 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
this, &SSLAdapterTestDummyClient::OnSSLAdapterCloseEvent);
}
void SetIgnoreBadCert(bool ignore_bad_cert) {
ssl_adapter_->SetIgnoreBadCert(ignore_bad_cert);
void SetTlsCertPolicy(rtc::TlsCertPolicy tls_cert_policy) {
ssl_config_.tls_cert_policy = tls_cert_policy;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetEnableOcspStapling(bool enable_ocsp_stapling) {
ssl_config_.enable_ocsp_stapling = enable_ocsp_stapling;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetEnableSignedCertTimestamp(bool enable_signed_cert_timestamp) {
ssl_config_.enable_signed_cert_timestamp = enable_signed_cert_timestamp;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetEnableTlsChannelId(bool enable_tls_channel_id) {
ssl_config_.enable_tls_channel_id = enable_tls_channel_id;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetEnableGrease(bool enable_grease) {
ssl_config_.enable_grease = enable_grease;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetMaxSslVersion(const absl::optional<int>& max_ssl_version) {
ssl_config_.max_ssl_version = max_ssl_version;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetAlpnProtocols(
const absl::optional<std::vector<std::string>>& tls_alpn_protocols) {
ssl_config_.tls_alpn_protocols = tls_alpn_protocols;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetEllipticCurves(
const absl::optional<std::vector<std::string>>& tls_elliptic_curves) {
ssl_config_.tls_elliptic_curves = tls_elliptic_curves;
ssl_adapter_->SetSSLConfig(ssl_config_);
}
void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) {
ssl_adapter_->SetCertVerifier(ssl_cert_verifier);
}
void SetAlpnProtocols(const std::vector<std::string>& protos) {
ssl_adapter_->SetAlpnProtocols(protos);
}
void SetEllipticCurves(const std::vector<std::string>& curves) {
ssl_adapter_->SetEllipticCurves(curves);
}
rtc::SocketAddress GetAddress() const {
return ssl_adapter_->GetLocalAddress();
}
@ -154,6 +186,8 @@ class SSLAdapterTestDummyClient : public sigslot::has_slots<> {
std::unique_ptr<rtc::SSLAdapter> ssl_adapter_;
rtc::SSLConfig ssl_config_;
std::string data_;
};
@ -305,29 +339,51 @@ class SSLAdapterTestBase : public testing::Test, public sigslot::has_slots<> {
void SetHandshakeWait(int wait) { handshake_wait_ = wait; }
void SetIgnoreBadCert(bool ignore_bad_cert) {
client_->SetIgnoreBadCert(ignore_bad_cert);
void SetTlsCertPolicy(rtc::TlsCertPolicy tls_cert_policy) {
client_->SetTlsCertPolicy(tls_cert_policy);
}
void SetEnableOcspStapling(bool enable_ocsp_stapling) {
client_->SetEnableOcspStapling(enable_ocsp_stapling);
}
void SetEnableSignedCertTimestamp(bool enable_signed_cert_timestamp) {
client_->SetEnableSignedCertTimestamp(enable_signed_cert_timestamp);
}
void SetEnableTlsChannelId(bool enable_tls_channel_id) {
client_->SetEnableTlsChannelId(enable_tls_channel_id);
}
void SetEnableGrease(bool enable_grease) {
client_->SetEnableGrease(enable_grease);
}
void SetMaxSslVersion(const absl::optional<int>& max_ssl_version) {
client_->SetMaxSslVersion(max_ssl_version);
}
void SetAlpnProtocols(
const absl::optional<std::vector<std::string>>& tls_alpn_protocols) {
client_->SetAlpnProtocols(tls_alpn_protocols);
}
void SetEllipticCurves(
const absl::optional<std::vector<std::string>>& tls_elliptic_curves) {
client_->SetEllipticCurves(tls_elliptic_curves);
}
void SetCertVerifier(rtc::SSLCertificateVerifier* ssl_cert_verifier) {
client_->SetCertVerifier(ssl_cert_verifier);
}
void SetAlpnProtocols(const std::vector<std::string>& protos) {
client_->SetAlpnProtocols(protos);
}
void SetEllipticCurves(const std::vector<std::string>& curves) {
client_->SetEllipticCurves(curves);
}
void SetMockCertVerifier(bool return_value) {
auto mock_verifier = absl::make_unique<MockCertVerifier>();
EXPECT_CALL(*mock_verifier, Verify(_)).WillRepeatedly(Return(return_value));
cert_verifier_ =
std::unique_ptr<rtc::SSLCertificateVerifier>(std::move(mock_verifier));
SetIgnoreBadCert(false);
SetTlsCertPolicy(rtc::TlsCertPolicy::TLS_CERT_POLICY_SECURE);
SetCertVerifier(cert_verifier_.get());
}
@ -525,6 +581,76 @@ TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransferCustomCertVerifier) {
TestTransfer("Hello, world!");
}
// Test transfer with OCSP stapling enabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestOcspStaplingEnabled) {
SetEnableOcspStapling(true);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with OCSP stapling disabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestOcspStaplingDisabled) {
SetEnableOcspStapling(false);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// test transfer with signed cert timestamp enabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestSignedCertTimestampEnabled) {
SetEnableSignedCertTimestamp(true);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with signed cert timestamp disabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestSignedCertTimestampDisabled) {
SetEnableSignedCertTimestamp(false);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with TLS channel ID enabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSChannelIdEnabled) {
SetEnableTlsChannelId(true);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with TLS channel ID disabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSChannelIdDisabled) {
SetEnableTlsChannelId(false);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with GREASE enabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestGreaseEnabled) {
SetEnableGrease(true);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with GREASE disabled
TEST_F(SSLAdapterTestTLS_ECDSA, TestGreaseDisabled) {
SetEnableGrease(false);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with TLS1_3.
TEST_F(SSLAdapterTestTLS_ECDSA, TestMaxSSLVersionTLS1_3) {
SetMaxSslVersion(0x0304 /* TLS1_3 */);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer with TLS1_2.
TEST_F(SSLAdapterTestTLS_ECDSA, TestMaxSSLVersionTLS1_2) {
SetMaxSslVersion(0x0303 /* TLS1_2 */);
TestHandshake(true);
TestTransfer("Hello, world!");
}
// Test transfer using ALPN with protos as h2 and http/1.1
TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSALPN) {
std::vector<std::string> alpn_protos{"h2", "http/1.1"};