summaryrefslogtreecommitdiffstats
path: root/net/socket
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-28 15:53:50 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-28 15:53:50 +0000
commit899c3e93acbd41bcd3c5ce5d09eddef8f45ab3ff (patch)
tree38b3e5caabeb273244b348e1bd101181aa6ce576 /net/socket
parent40251a21ba6eea816755b1bcb9edf305c782aeda (diff)
downloadchromium_src-899c3e93acbd41bcd3c5ce5d09eddef8f45ab3ff.zip
chromium_src-899c3e93acbd41bcd3c5ce5d09eddef8f45ab3ff.tar.gz
chromium_src-899c3e93acbd41bcd3c5ce5d09eddef8f45ab3ff.tar.bz2
https: add support for DNS exclusion and switch to TXT records.
(This code has no effect unless --enable-dnssec-certs is given.) The existing DNSSEC code will process embeded chains in certificates and validate CERT records there in. The format of the CERT record was just something made up as a proof of concept. This change switches that code to using TXT records which are at least used by some other code. Additionally, when --enable-dnssec-certs is given. TXT record lookups are triggered for each HTTPS connection. If DNSSEC secure, these lookups can validate a HTTPS certificate. Even without DNSSEC, they can by used for exclusion: if TLS fingerprints are given, but the certificate doesn't match any of them, then the certificate is rejected. The next step in this series will be to perform the TXT lookup for some percentage of dev channel users in order to measure the latency impact. For this experiment, all behavioural changes will be disabled. BUG=none TEST=net_unittests http://codereview.chromium.org/3148037/show git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57787 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket')
-rw-r--r--net/socket/ssl_client_socket.h17
-rw-r--r--net/socket/ssl_client_socket_nss.cc223
-rw-r--r--net/socket/ssl_client_socket_nss.h13
-rw-r--r--net/socket/ssl_client_socket_pool.cc68
-rw-r--r--net/socket/ssl_client_socket_pool.h18
5 files changed, 299 insertions, 40 deletions
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index c4a063a..064dd26 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -8,6 +8,7 @@
#include <string>
+#include "net/base/completion_callback.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/socket/client_socket.h"
@@ -16,6 +17,20 @@ namespace net {
class SSLCertRequestInfo;
class SSLInfo;
+struct RRResponse;
+
+// DNSSECProvider is an interface to an object that can return DNSSEC data.
+class DNSSECProvider {
+ public:
+ // GetDNSSECRecords will either:
+ // 1) set |*out| to NULL and return OK.
+ // 2) set |*out| to a pointer, which is owned by this object, and return OK.
+ // 3) return IO_PENDING and call |callback| on the current MessageLoop at
+ // some point in the future. Once the callback has been made, this
+ // function will return OK if called again.
+ virtual int GetDNSSECRecords(RRResponse** out,
+ CompletionCallback* callback) = 0;
+};
// A client socket that uses SSL as the transport layer.
//
@@ -102,6 +117,8 @@ class SSLClientSocket : public ClientSocket {
return was_npn_negotiated_ = negotiated;
}
+ virtual void UseDNSSEC(DNSSECProvider*) { }
+
virtual bool was_spdy_negotiated() const {
return was_spdy_negotiated_;
}
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 44b5e1f..8419928 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -66,14 +66,16 @@
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/singleton.h"
+#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "net/base/address_list.h"
#include "net/base/cert_verifier.h"
+#include "net/base/dnsrr_resolver.h"
#include "net/base/dnssec_chain_verifier.h"
#include "net/base/dns_util.h"
#include "net/base/io_buffer.h"
-#include "net/base/net_log.h"
#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/base/ssl_connection_status_flags.h"
#include "net/base/ssl_info.h"
@@ -348,6 +350,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
client_auth_cert_needed_(false),
handshake_callback_called_(false),
completed_handshake_(false),
+ dnssec_provider_(NULL),
next_handshake_state_(STATE_NONE),
nss_fd_(NULL),
nss_bufs_(NULL),
@@ -927,6 +930,10 @@ SSLClientSocketNSS::GetNextProto(std::string* proto) {
#endif
}
+void SSLClientSocketNSS::UseDNSSEC(DNSSECProvider* provider) {
+ dnssec_provider_ = provider;
+}
+
void SSLClientSocketNSS::DoReadCallback(int rv) {
EnterFunction(rv);
DCHECK(rv != ERR_IO_PENDING);
@@ -1196,6 +1203,12 @@ int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
case STATE_HANDSHAKE:
rv = DoHandshake();
break;
+ case STATE_VERIFY_DNSSEC:
+ rv = DoVerifyDNSSEC(rv);
+ break;
+ case STATE_VERIFY_DNSSEC_COMPLETE:
+ rv = DoVerifyDNSSECComplete(rv);
+ break;
case STATE_VERIFY_CERT:
DCHECK(rv == OK);
rv = DoVerifyCert(rv);
@@ -1490,7 +1503,7 @@ int SSLClientSocketNSS::DoHandshake() {
} else if (rv == SECSuccess) {
if (handshake_callback_called_) {
// SSL handshake is completed. Let's verify the certificate.
- GotoState(STATE_VERIFY_CERT);
+ GotoState(STATE_VERIFY_DNSSEC);
// Done!
} else {
// SSL_ForceHandshake returned SECSuccess prematurely.
@@ -1514,14 +1527,108 @@ int SSLClientSocketNSS::DoHandshake() {
return net_error;
}
+// DNSValidationResult enumerates the possible outcomes from processing a
+// set of DNS records.
+enum DNSValidationResult {
+ DNSVR_SUCCESS, // the cert is immediately acceptable.
+ DNSVR_FAILURE, // the cert is unconditionally rejected.
+ DNSVR_CONTINUE, // perform CA validation as usual.
+};
+
+// VerifyTXTRecords processes the RRDATA for a number of DNS TXT records and
+// checks them against the given certificate.
+// dnssec: if true then the TXT records are DNSSEC validated. In this case,
+// DNSVR_SUCCESS may be returned.
+// server_cert_nss: the certificate to validate
+// rrdatas: the TXT records for the current domain.
+static DNSValidationResult VerifyTXTRecords(
+ bool dnssec,
+ CERTCertificate* server_cert_nss,
+ const std::vector<base::StringPiece>& rrdatas) {
+ bool found_well_formed_record = false;
+ bool matched_record = false;
+
+ for (std::vector<base::StringPiece>::const_iterator
+ i = rrdatas.begin(); i != rrdatas.end(); ++i) {
+ std::map<std::string, std::string> m(
+ DNSSECChainVerifier::ParseTLSTXTRecord(*i));
+ if (m.empty())
+ continue;
+
+ std::map<std::string, std::string>::const_iterator j;
+ j = m.find("v");
+ if (j == m.end() || j->second != "tls1")
+ continue;
+
+ j = m.find("ha");
+
+ HASH_HashType hash_algorithm;
+ unsigned hash_length;
+ if (j == m.end() || j->second == "sha1") {
+ hash_algorithm = HASH_AlgSHA1;
+ hash_length = SHA1_LENGTH;
+ } else if (j->second == "sha256") {
+ hash_algorithm = HASH_AlgSHA256;
+ hash_length = SHA256_LENGTH;
+ } else {
+ continue;
+ }
+
+ j = m.find("h");
+ if (j == m.end())
+ continue;
+
+ std::vector<uint8> given_hash;
+ if (!base::HexStringToBytes(j->second, &given_hash))
+ continue;
+
+ if (given_hash.size() != hash_length)
+ continue;
+
+ uint8 calculated_hash[SHA256_LENGTH]; // SHA256 is the largest.
+ SECStatus rv;
+
+ j = m.find("hr");
+ if (j == m.end() || j->second == "cert") {
+ rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+ server_cert_nss->derCert.data,
+ server_cert_nss->derCert.len);
+ } else if (j->second == "pubkey") {
+ rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+ server_cert_nss->derPublicKey.data,
+ server_cert_nss->derPublicKey.len);
+ } else {
+ continue;
+ }
+
+ if (rv != SECSuccess)
+ NOTREACHED();
+
+ found_well_formed_record = true;
+
+ if (memcmp(calculated_hash, &given_hash[0], hash_length) == 0) {
+ matched_record = true;
+ if (dnssec)
+ return DNSVR_SUCCESS;
+ }
+ }
+
+ if (found_well_formed_record && !matched_record)
+ return DNSVR_FAILURE;
+
+ return DNSVR_CONTINUE;
+}
+
+
// CheckDNSSECChain tries to validate a DNSSEC chain embedded in
// |server_cert_nss_|. It returns true iff a chain is found that proves the
-// value of a CERT record that contains a valid public key fingerprint.
-bool SSLClientSocketNSS::CheckDNSSECChain() {
- if (!server_cert_nss_)
- return false;
+// value of a TXT record that contains a valid public key fingerprint.
+static DNSValidationResult CheckDNSSECChain(
+ const std::string& hostname,
+ CERTCertificate* server_cert_nss) {
+ if (!server_cert_nss)
+ return DNSVR_CONTINUE;
- bool good = false;
// CERT_FindCertExtensionByOID isn't exported so we have to install an OID,
// get a tag for it and find the extension by using that tag.
static SECOidTag dnssec_chain_tag;
@@ -1544,50 +1651,95 @@ bool SSLClientSocketNSS::CheckDNSSECChain() {
}
SECItem dnssec_embedded_chain;
- SECStatus rv = CERT_FindCertExtension(server_cert_nss_,
+ SECStatus rv = CERT_FindCertExtension(server_cert_nss,
dnssec_chain_tag, &dnssec_embedded_chain);
if (rv != SECSuccess)
- return false;
+ return DNSVR_CONTINUE;
base::StringPiece chain(
reinterpret_cast<char*>(dnssec_embedded_chain.data),
dnssec_embedded_chain.len);
std::string dns_hostname;
- if (!DNSDomainFromDot(hostname_, &dns_hostname))
- return false;
+ if (!DNSDomainFromDot(hostname, &dns_hostname))
+ return DNSVR_CONTINUE;
DNSSECChainVerifier verifier(dns_hostname, chain);
DNSSECChainVerifier::Error err = verifier.Verify();
if (err != DNSSECChainVerifier::OK) {
LOG(ERROR) << "DNSSEC chain verification failed: " << err;
- return false;
+ return DNSVR_CONTINUE;
}
- if (verifier.rrtype() != kDNS_CERT)
- return false;
+ if (verifier.rrtype() != kDNS_TXT)
+ return DNSVR_CONTINUE;
- uint8 hash[SHA1_LENGTH];
- rv = HASH_HashBuf(HASH_AlgSHA1, hash,
- server_cert_nss_->derPublicKey.data,
- server_cert_nss_->derPublicKey.len);
- if (rv != SECSuccess)
- return false;
-
- const std::vector<base::StringPiece>& rrdatas = verifier.rrdatas();
- for (unsigned i = 0; i < rrdatas.size(); i++) {
- const uint8* data =
- reinterpret_cast<const uint8*>(rrdatas[i].data());
- // See RFC 4398 section 2 for details of the CERT format.
- static const uint8 kCERTHeader[] = {0, 9, 0, 0, 1};
- if (rrdatas[i].size() == 5 + SHA1_LENGTH &&
- memcmp(data, kCERTHeader, sizeof(kCERTHeader)) == 0 &&
- memcmp(data + sizeof(kCERTHeader), hash, sizeof(hash)) == 0) {
- good = true;
- break;
+ DNSValidationResult r = VerifyTXTRecords(
+ true /* DNSSEC verified */, server_cert_nss, verifier.rrdatas());
+ SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE);
+ return r;
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
+ if (ssl_config_.dnssec_enabled) {
+ DNSValidationResult r = CheckDNSSECChain(hostname_, server_cert_nss_);
+ if (r == DNSVR_SUCCESS) {
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ return OK;
}
}
- SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE);
- return good;
+ if (dnssec_provider_ == NULL) {
+ GotoState(STATE_VERIFY_CERT);
+ return OK;
+ }
+
+ GotoState(STATE_VERIFY_DNSSEC_COMPLETE);
+ RRResponse* response;
+ dnssec_wait_start_time_ = base::Time::Now();
+ return dnssec_provider_->GetDNSSECRecords(&response, &handshake_io_callback_);
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
+ RRResponse* response;
+ int err = dnssec_provider_->GetDNSSECRecords(&response, NULL);
+ DCHECK_EQ(err, OK);
+
+ const base::TimeDelta elapsed = base::Time::Now() - dnssec_wait_start_time_;
+ HISTOGRAM_TIMES("Net.DNSSECWaitTime", elapsed);
+
+ GotoState(STATE_VERIFY_CERT);
+ if (!response || response->rrdatas.empty())
+ return OK;
+
+ std::vector<base::StringPiece> records;
+ records.resize(response->rrdatas.size());
+ for (unsigned i = 0; i < response->rrdatas.size(); i++)
+ records[i] = base::StringPiece(response->rrdatas[i]);
+ DNSValidationResult r =
+ VerifyTXTRecords(response->dnssec, server_cert_nss_, records);
+
+ if (!ssl_config_.dnssec_enabled) {
+ // If DNSSEC is not enabled we don't take any action based on the result,
+ // except to record the latency, above.
+ GotoState(STATE_VERIFY_CERT);
+ return OK;
+ }
+
+ switch (r) {
+ case DNSVR_FAILURE:
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ return ERR_CERT_NOT_IN_DNS;
+ case DNSVR_CONTINUE:
+ GotoState(STATE_VERIFY_CERT);
+ break;
+ case DNSVR_SUCCESS:
+ GotoState(STATE_VERIFY_CERT_COMPLETE);
+ break;
+ default:
+ NOTREACHED();
+ GotoState(STATE_VERIFY_CERT);
+ }
+
+ return OK;
}
int SSLClientSocketNSS::DoVerifyCert(int result) {
@@ -1595,9 +1747,6 @@ int SSLClientSocketNSS::DoVerifyCert(int result) {
GotoState(STATE_VERIFY_CERT_COMPLETE);
int flags = 0;
- if (ssl_config_.dnssec_enabled && CheckDNSSECChain())
- return OK;
-
if (ssl_config_.rev_checking_enabled)
flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
if (ssl_config_.verify_ev_cert)
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index 315e142..dabe5c4 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -15,6 +15,7 @@
#include <vector>
#include "base/scoped_ptr.h"
+#include "base/time.h"
#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
#include "net/base/net_log.h"
@@ -46,6 +47,7 @@ class SSLClientSocketNSS : public SSLClientSocket {
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
+ virtual void UseDNSSEC(DNSSECProvider*);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback);
@@ -88,7 +90,9 @@ class SSLClientSocketNSS : public SSLClientSocket {
int DoWriteLoop(int result);
int DoHandshake();
- bool CheckDNSSECChain();
+
+ int DoVerifyDNSSEC(int result);
+ int DoVerifyDNSSECComplete(int result);
int DoVerifyCert(int result);
int DoVerifyCertComplete(int result);
int DoPayloadRead();
@@ -158,9 +162,16 @@ class SSLClientSocketNSS : public SSLClientSocket {
// True if the SSL handshake has been completed.
bool completed_handshake_;
+ // This pointer is owned by the caller of UseDNSSEC.
+ DNSSECProvider* dnssec_provider_;
+ // The time when we started waiting for DNSSEC records.
+ base::Time dnssec_wait_start_time_;
+
enum State {
STATE_NONE,
STATE_HANDSHAKE,
+ STATE_VERIFY_DNSSEC,
+ STATE_VERIFY_DNSSEC_COMPLETE,
STATE_VERIFY_CERT,
STATE_VERIFY_CERT_COMPLETE,
};
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index cb321ab..15619ab 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -4,6 +4,8 @@
#include "net/socket/ssl_client_socket_pool.h"
+#include "net/base/dnsrr_resolver.h"
+#include "net/base/dns_util.h"
#include "net/base/net_errors.h"
#include "net/base/ssl_cert_request_info.h"
#include "net/http/http_proxy_client_socket.h"
@@ -34,7 +36,10 @@ SSLSocketParams::SSLSocketParams(
ssl_config_(ssl_config),
load_flags_(load_flags),
force_spdy_over_ssl_(force_spdy_over_ssl),
- want_spdy_over_npn_(want_spdy_over_npn) {
+ want_spdy_over_npn_(want_spdy_over_npn),
+ dnssec_resolution_attempted_(false),
+ dnssec_resolution_complete_(false),
+ dnssec_resolution_callback_(NULL) {
switch (proxy_) {
case ProxyServer::SCHEME_DIRECT:
DCHECK(tcp_params_.get() != NULL);
@@ -61,6 +66,61 @@ SSLSocketParams::SSLSocketParams(
SSLSocketParams::~SSLSocketParams() {}
+void SSLSocketParams::StartDNSSECResolution() {
+ dnssec_response_.reset(new RRResponse);
+ // We keep a reference to ourselves while the DNS resolution is underway.
+ // When it completes (in DNSSECResolutionComplete), we balance it out.
+ AddRef();
+
+ dnssec_resolution_attempted_ = true;
+ bool r = DnsRRResolver::Resolve(
+ hostname(), kDNS_TXT, DnsRRResolver::FLAG_WANT_DNSSEC,
+ NewCallback(this, &SSLSocketParams::DNSSECResolutionComplete),
+ dnssec_response_.get());
+ if (!r) {
+ dnssec_response_.reset();
+ dnssec_resolution_attempted_ = false;
+ }
+}
+
+void SSLSocketParams::DNSSECResolutionComplete(int rv) {
+ CompletionCallback* callback = NULL;
+ {
+ DCHECK(dnssec_resolution_attempted_);
+ DCHECK(!dnssec_resolution_complete_);
+
+ if (rv != OK)
+ dnssec_response_.reset();
+
+ dnssec_resolution_complete_ = true;
+ if (dnssec_resolution_callback_)
+ callback = dnssec_resolution_callback_;
+ }
+
+ if (callback)
+ callback->Run(OK);
+
+ Release();
+}
+
+int SSLSocketParams::GetDNSSECRecords(RRResponse** out,
+ CompletionCallback* callback) {
+ if (!dnssec_resolution_attempted_) {
+ *out = NULL;
+ return OK;
+ }
+
+ if (dnssec_resolution_complete_) {
+ *out = dnssec_response_.get();
+ return OK;
+ }
+
+ DCHECK(dnssec_resolution_callback_ == NULL);
+
+ dnssec_resolution_callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
// Timeout for the SSL handshake portion of the connect.
static const int kSSLHandshakeTimeoutInSeconds = 30;
@@ -183,6 +243,10 @@ int SSLConnectJob::DoLoop(int result) {
int SSLConnectJob::DoTCPConnect() {
DCHECK(tcp_pool_.get());
+
+ if (SSLConfigService::dnssec_enabled())
+ params_->StartDNSSECResolution();
+
next_state_ = STATE_TCP_CONNECT_COMPLETE;
transport_socket_handle_.reset(new ClientSocketHandle());
scoped_refptr<TCPSocketParams> tcp_params = params_->tcp_params();
@@ -267,6 +331,8 @@ int SSLConnectJob::DoSSLConnect() {
ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
transport_socket_handle_.release(), params_->hostname(),
params_->ssl_config()));
+ if (SSLConfigService::dnssec_enabled())
+ ssl_socket_->UseDNSSEC(params_.get());
return ssl_socket_->Connect(&callback_);
}
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index f613fcf..0c8f90f 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -15,6 +15,7 @@
#include "net/base/ssl_config_service.h"
#include "net/http/http_response_info.h"
#include "net/proxy/proxy_server.h"
+#include "net/socket/ssl_client_socket.h"
#include "net/socket/client_socket_pool_base.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/client_socket_pool.h"
@@ -30,10 +31,12 @@ class SOCKSSocketParams;
class SSLClientSocket;
class TCPClientSocketPool;
class TCPSocketParams;
+struct RRResponse;
// SSLSocketParams only needs the socket params for the transport socket
// that will be used (denoted by |proxy|).
-class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
+class SSLSocketParams : public base::RefCounted<SSLSocketParams>,
+ public DNSSECProvider {
public:
SSLSocketParams(const scoped_refptr<TCPSocketParams>& tcp_params,
const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
@@ -58,10 +61,16 @@ class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
int load_flags() const { return load_flags_; }
bool force_spdy_over_ssl() const { return force_spdy_over_ssl_; }
bool want_spdy_over_npn() const { return want_spdy_over_npn_; }
+ // Start to resolve DNSSEC records for the given hostname.
+ void StartDNSSECResolution();
+
+ // DNSSECProvider implementation.
+ virtual int GetDNSSECRecords(RRResponse** out, CompletionCallback* callback);
private:
friend class base::RefCounted<SSLSocketParams>;
~SSLSocketParams();
+ void DNSSECResolutionComplete(int rv);
const scoped_refptr<TCPSocketParams> tcp_params_;
const scoped_refptr<HttpProxySocketParams> http_proxy_params_;
@@ -73,6 +82,13 @@ class SSLSocketParams : public base::RefCounted<SSLSocketParams> {
const bool force_spdy_over_ssl_;
const bool want_spdy_over_npn_;
+ // This is true if we have started a DNSSEC resolution.
+ bool dnssec_resolution_attempted_;
+ // This is true if |dnssec_response_| is valid.
+ bool dnssec_resolution_complete_;
+ scoped_ptr<RRResponse> dnssec_response_;
+ CompletionCallback* dnssec_resolution_callback_;
+
DISALLOW_COPY_AND_ASSIGN(SSLSocketParams);
};