summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--net/socket/ssl_client_socket_openssl.cc19
-rw-r--r--net/socket/ssl_client_socket_openssl.h4
-rw-r--r--net/socket/ssl_client_socket_unittest.cc17
-rw-r--r--net/test/spawned_test_server/base_test_server.cc22
-rw-r--r--net/test/spawned_test_server/base_test_server.h6
-rwxr-xr-xnet/tools/testserver/testserver.py33
-rw-r--r--third_party/tlslite/README.chromium2
-rw-r--r--third_party/tlslite/patches/req_cert_types.patch153
-rw-r--r--third_party/tlslite/tlslite/api.py3
-rw-r--r--third_party/tlslite/tlslite/constants.py4
-rw-r--r--third_party/tlslite/tlslite/messages.py4
-rw-r--r--third_party/tlslite/tlslite/tlsconnection.py31
13 files changed, 273 insertions, 27 deletions
diff --git a/DEPS b/DEPS
index a8e0c53..faf5ea5 100644
--- a/DEPS
+++ b/DEPS
@@ -65,7 +65,7 @@ vars = {
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling openssl
# and whatever else without interference from each other.
- "openssl_revision": "269063",
+ "openssl_revision": "270417",
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ANGLE
# and whatever else without interference from each other.
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 35598d8..7bf24c6 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -370,6 +370,7 @@ void SSLClientSocketOpenSSL::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) {
cert_request_info->host_and_port = host_and_port_;
cert_request_info->cert_authorities = cert_authorities_;
+ cert_request_info->cert_key_types = cert_key_types_;
}
SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto(
@@ -473,6 +474,7 @@ void SSLClientSocketOpenSSL::Disconnect() {
completed_handshake_ = false;
cert_authorities_.clear();
+ cert_key_types_.clear();
client_auth_cert_needed_ = false;
}
@@ -1264,7 +1266,6 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
DCHECK(ssl == ssl_);
DCHECK(*x509 == NULL);
DCHECK(*pkey == NULL);
-#if defined(USE_OPENSSL_CERTS)
if (!ssl_config_.send_client_cert) {
// First pass: we know that a client certificate is needed, but we do not
// have one at hand.
@@ -1280,11 +1281,21 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
OPENSSL_free(str);
}
+ const unsigned char* client_cert_types;
+ size_t num_client_cert_types;
+ SSL_get_client_certificate_types(ssl, &client_cert_types,
+ &num_client_cert_types);
+ for (size_t i = 0; i < num_client_cert_types; i++) {
+ cert_key_types_.push_back(
+ static_cast<SSLClientCertType>(client_cert_types[i]));
+ }
+
return -1; // Suspends handshake.
}
// Second pass: a client certificate should have been selected.
if (ssl_config_.client_cert.get()) {
+#if defined(USE_OPENSSL_CERTS)
// A note about ownership: FetchClientCertPrivateKey() increments
// the reference count of the EVP_PKEY. Ownership of this reference
// is passed directly to OpenSSL, which will release the reference
@@ -1300,11 +1311,11 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
return 1;
}
LOG(WARNING) << "Client cert found without private key";
- }
#else // !defined(USE_OPENSSL_CERTS)
- // OS handling of client certificates is not yet implemented.
- NOTIMPLEMENTED();
+ // OS handling of client certificates is not yet implemented.
+ NOTIMPLEMENTED();
#endif // defined(USE_OPENSSL_CERTS)
+ }
// Send no client certificate.
return 0;
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index c5b7556..5d70c05 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -16,6 +16,7 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/server_bound_cert_service.h"
+#include "net/ssl/ssl_client_cert_type.h"
#include "net/ssl/ssl_config_service.h"
// Avoid including misc OpenSSL headers, i.e.:
@@ -197,6 +198,9 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
// List of DER-encoded X.509 DistinguishedName of certificate authorities
// allowed by the server.
std::vector<std::string> cert_authorities_;
+ // List of SSLClientCertType values for client certificates allowed by the
+ // server.
+ std::vector<SSLClientCertType> cert_key_types_;
CertVerifier* const cert_verifier_;
scoped_ptr<SingleRequestCertVerifier> verifier_;
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 8d8e2fd..2639870 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -704,6 +704,8 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest {
sock->GetSSLCertRequestInfo(request_info.get());
sock->Disconnect();
EXPECT_FALSE(sock->IsConnected());
+ EXPECT_TRUE(
+ test_server.host_port_pair().Equals(request_info->host_and_port));
return request_info;
}
@@ -2219,6 +2221,21 @@ TEST_F(SSLClientSocketCertRequestInfoTest, TwoAuthorities) {
request_info->cert_authorities[1]);
}
+// cert_key_types is currently only populated on OpenSSL.
+#if defined(USE_OPENSSL)
+TEST_F(SSLClientSocketCertRequestInfoTest, CertKeyTypes) {
+ SpawnedTestServer::SSLOptions ssl_options;
+ ssl_options.request_client_certificate = true;
+ ssl_options.client_cert_types.push_back(CLIENT_CERT_RSA_SIGN);
+ ssl_options.client_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
+ scoped_refptr<SSLCertRequestInfo> request_info = GetCertRequest(ssl_options);
+ ASSERT_TRUE(request_info.get());
+ ASSERT_EQ(2u, request_info->cert_key_types.size());
+ EXPECT_EQ(CLIENT_CERT_RSA_SIGN, request_info->cert_key_types[0]);
+ EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, request_info->cert_key_types[1]);
+}
+#endif // defined(USE_OPENSSL)
+
TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) {
SpawnedTestServer::SSLOptions ssl_options;
ssl_options.signed_cert_timestamps_tls_ext = "test";
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index a781c6e..016c930 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -40,6 +40,20 @@ std::string GetHostname(BaseTestServer::Type type,
return BaseTestServer::kLocalhost;
}
+std::string GetClientCertType(SSLClientCertType type) {
+ switch (type) {
+ case CLIENT_CERT_RSA_SIGN:
+ return "rsa_sign";
+ case CLIENT_CERT_DSS_SIGN:
+ return "dss_sign";
+ case CLIENT_CERT_ECDSA_SIGN:
+ return "ecdsa_sign";
+ default:
+ NOTREACHED();
+ return "";
+ }
+}
+
void GetKeyExchangesList(int key_exchange, base::ListValue* values) {
if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_RSA)
values->Append(new base::StringValue("rsa"));
@@ -386,6 +400,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
if (ssl_client_certs->GetSize())
arguments->Set("ssl-client-ca", ssl_client_certs.release());
+
+ scoped_ptr<base::ListValue> client_cert_types(new base::ListValue());
+ for (size_t i = 0; i < ssl_options_.client_cert_types.size(); i++) {
+ client_cert_types->Append(new base::StringValue(
+ GetClientCertType(ssl_options_.client_cert_types[i])));
+ }
+ if (client_cert_types->GetSize())
+ arguments->Set("ssl-client-cert-type", client_cert_types.release());
}
if (type_ == TYPE_HTTPS) {
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index 392a72b..5c47ebc 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -13,6 +13,7 @@
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/host_port_pair.h"
+#include "net/ssl/ssl_client_cert_type.h"
class GURL;
@@ -146,6 +147,11 @@ class BaseTestServer {
// field of the CertificateRequest.
std::vector<base::FilePath> client_authorities;
+ // If |request_client_certificate| is true, an optional list of
+ // SSLClientCertType values to populate the certificate_types field of the
+ // CertificateRequest.
+ std::vector<SSLClientCertType> client_cert_types;
+
// A bitwise-OR of KeyExchnage that should be used by the
// HTTPS server, or KEY_EXCHANGE_ANY to indicate that all implemented
// key exchange algorithms are acceptable.
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 9e86cf2..c7af46b 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -152,7 +152,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
client verification."""
def __init__(self, server_address, request_hander_class, pem_cert_and_key,
- ssl_client_auth, ssl_client_cas,
+ ssl_client_auth, ssl_client_cas, ssl_client_cert_types,
ssl_bulk_ciphers, ssl_key_exchanges, enable_npn,
record_resume_info, tls_intolerant, signed_cert_timestamps,
fallback_scsv_enabled, ocsp_response):
@@ -167,6 +167,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
implementations=['python'])
self.ssl_client_auth = ssl_client_auth
self.ssl_client_cas = []
+ self.ssl_client_cert_types = []
if enable_npn:
self.next_protos = ['http/1.1']
else:
@@ -179,11 +180,20 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
self.fallback_scsv_enabled = fallback_scsv_enabled
self.ocsp_response = ocsp_response
- for ca_file in ssl_client_cas:
- s = open(ca_file).read()
- x509 = tlslite.api.X509()
- x509.parse(s)
- self.ssl_client_cas.append(x509.subject)
+ if ssl_client_auth:
+ for ca_file in ssl_client_cas:
+ s = open(ca_file).read()
+ x509 = tlslite.api.X509()
+ x509.parse(s)
+ self.ssl_client_cas.append(x509.subject)
+
+ for cert_type in ssl_client_cert_types:
+ self.ssl_client_cert_types.append({
+ "rsa_sign": tlslite.api.ClientCertificateType.rsa_sign,
+ "dss_sign": tlslite.api.ClientCertificateType.dss_sign,
+ "ecdsa_sign": tlslite.api.ClientCertificateType.ecdsa_sign,
+ }[cert_type])
+
self.ssl_handshake_settings = tlslite.api.HandshakeSettings()
if ssl_bulk_ciphers is not None:
self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers
@@ -211,6 +221,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
reqCert=self.ssl_client_auth,
settings=self.ssl_handshake_settings,
reqCAs=self.ssl_client_cas,
+ reqCertTypes=self.ssl_client_cert_types,
nextProtos=self.next_protos,
tlsIntolerant=self.tls_intolerant,
signedCertTimestamps=
@@ -1989,6 +2000,7 @@ class ServerRunner(testserver_base.TestServerRunner):
server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
self.options.ssl_client_auth,
self.options.ssl_client_ca,
+ self.options.ssl_client_cert_type,
self.options.ssl_bulk_cipher,
self.options.ssl_key_exchange,
self.options.enable_npn,
@@ -2172,6 +2184,15 @@ class ServerRunner(testserver_base.TestServerRunner):
'file. This option may appear multiple '
'times, indicating multiple CA names should '
'be sent in the request.')
+ self.option_parser.add_option('--ssl-client-cert-type', action='append',
+ default=[], help='Specify that the client '
+ 'certificate request should include the '
+ 'specified certificate_type value. This '
+ 'option may appear multiple times, '
+ 'indicating multiple values should be send '
+ 'in the request. Valid values are '
+ '"rsa_sign", "dss_sign", and "ecdsa_sign". '
+ 'If omitted, "rsa_sign" will be used.')
self.option_parser.add_option('--ssl-bulk-cipher', action='append',
help='Specify the bulk encryption '
'algorithm(s) that will be accepted by the '
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index 28dded0..029c2db 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -31,3 +31,5 @@ Local Modifications:
- patches/fix_test_file.patch: Fix #! line in random test file to appease our
presubmit checks.
- patches/dhe_rsa.patch: Implement DHE_RSA-based cipher suites.
+- patches/req_cert_types.patch: Add a reqCertTypes parameter to populate the
+ certificate_types field of CertificateRequest.
diff --git a/third_party/tlslite/patches/req_cert_types.patch b/third_party/tlslite/patches/req_cert_types.patch
new file mode 100644
index 0000000..2774e77
--- /dev/null
+++ b/third_party/tlslite/patches/req_cert_types.patch
@@ -0,0 +1,153 @@
+diff --git a/third_party/tlslite/tlslite/api.py b/third_party/tlslite/tlslite/api.py
+index faef6cb..562fb81 100644
+--- a/third_party/tlslite/tlslite/api.py
++++ b/third_party/tlslite/tlslite/api.py
+@@ -2,7 +2,8 @@
+ # See the LICENSE file for legal information regarding use of this file.
+
+ __version__ = "0.4.6"
+-from .constants import AlertLevel, AlertDescription, Fault
++from .constants import AlertLevel, AlertDescription, ClientCertificateType, \
++ Fault
+ from .errors import *
+ from .checker import Checker
+ from .handshakesettings import HandshakeSettings
+diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
+index 30d1f9f..457b339 100644
+--- a/third_party/tlslite/tlslite/constants.py
++++ b/third_party/tlslite/tlslite/constants.py
+@@ -14,10 +14,14 @@ class CertificateType:
+ openpgp = 1
+
+ class ClientCertificateType:
++ # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-2
+ rsa_sign = 1
+ dss_sign = 2
+ rsa_fixed_dh = 3
+ dss_fixed_dh = 4
++ ecdsa_sign = 64
++ rsa_fixed_ecdh = 65
++ ecdsa_fixed_ecdh = 66
+
+ class HandshakeType:
+ hello_request = 0
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index 550b387..c8a913c 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -454,9 +454,7 @@ class CertificateStatus(HandshakeMsg):
+ class CertificateRequest(HandshakeMsg):
+ def __init__(self):
+ HandshakeMsg.__init__(self, HandshakeType.certificate_request)
+- #Apple's Secure Transport library rejects empty certificate_types, so
+- #default to rsa_sign.
+- self.certificate_types = [ClientCertificateType.rsa_sign]
++ self.certificate_types = []
+ self.certificate_authorities = []
+
+ def create(self, certificate_types, certificate_authorities):
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index e6f7820..044ad59 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -1062,7 +1062,7 @@ class TLSConnection(TLSRecordLayer):
+ def handshakeServer(self, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+ sessionCache=None, settings=None, checker=None,
+- reqCAs = None,
++ reqCAs = None, reqCertTypes = None,
+ tacks=None, activationFlags=0,
+ nextProtos=None, anon=False,
+ tlsIntolerant=None, signedCertTimestamps=None,
+@@ -1130,6 +1130,10 @@ class TLSConnection(TLSRecordLayer):
+ will be sent along with a certificate request. This does not affect
+ verification.
+
++ @type reqCertTypes: list of int
++ @param reqCertTypes: A list of certificate_type values to be sent
++ along with a certificate request. This does not affect verification.
++
+ @type nextProtos: list of strings.
+ @param nextProtos: A list of upper layer protocols to expose to the
+ clients through the Next-Protocol Negotiation Extension,
+@@ -1169,7 +1173,7 @@ class TLSConnection(TLSRecordLayer):
+ """
+ for result in self.handshakeServerAsync(verifierDB,
+ certChain, privateKey, reqCert, sessionCache, settings,
+- checker, reqCAs,
++ checker, reqCAs, reqCertTypes,
+ tacks=tacks, activationFlags=activationFlags,
+ nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant,
+ signedCertTimestamps=signedCertTimestamps,
+@@ -1180,7 +1184,7 @@ class TLSConnection(TLSRecordLayer):
+ def handshakeServerAsync(self, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+ sessionCache=None, settings=None, checker=None,
+- reqCAs=None,
++ reqCAs=None, reqCertTypes=None,
+ tacks=None, activationFlags=0,
+ nextProtos=None, anon=False,
+ tlsIntolerant=None,
+@@ -1203,7 +1207,7 @@ class TLSConnection(TLSRecordLayer):
+ verifierDB=verifierDB, certChain=certChain,
+ privateKey=privateKey, reqCert=reqCert,
+ sessionCache=sessionCache, settings=settings,
+- reqCAs=reqCAs,
++ reqCAs=reqCAs, reqCertTypes=reqCertTypes,
+ tacks=tacks, activationFlags=activationFlags,
+ nextProtos=nextProtos, anon=anon,
+ tlsIntolerant=tlsIntolerant,
+@@ -1216,7 +1220,7 @@ class TLSConnection(TLSRecordLayer):
+
+ def _handshakeServerAsyncHelper(self, verifierDB,
+ certChain, privateKey, reqCert, sessionCache,
+- settings, reqCAs,
++ settings, reqCAs, reqCertTypes,
+ tacks, activationFlags,
+ nextProtos, anon,
+ tlsIntolerant, signedCertTimestamps, fallbackSCSV,
+@@ -1232,6 +1236,8 @@ class TLSConnection(TLSRecordLayer):
+ raise ValueError("Caller passed a privateKey but no certChain")
+ if reqCAs and not reqCert:
+ raise ValueError("Caller passed reqCAs but not reqCert")
++ if reqCertTypes and not reqCert:
++ raise ValueError("Caller passed reqCertTypes but not reqCert")
+ if certChain and not isinstance(certChain, X509CertChain):
+ raise ValueError("Unrecognized certificate type")
+ if activationFlags and not tacks:
+@@ -1320,7 +1326,7 @@ class TLSConnection(TLSRecordLayer):
+ assert(False)
+ for result in self._serverCertKeyExchange(clientHello, serverHello,
+ certChain, keyExchange,
+- reqCert, reqCAs, cipherSuite,
++ reqCert, reqCAs, reqCertTypes, cipherSuite,
+ settings, ocspResponse):
+ if result in (0,1): yield result
+ else: break
+@@ -1597,7 +1603,7 @@ class TLSConnection(TLSRecordLayer):
+
+ def _serverCertKeyExchange(self, clientHello, serverHello,
+ serverCertChain, keyExchange,
+- reqCert, reqCAs, cipherSuite,
++ reqCert, reqCAs, reqCertTypes, cipherSuite,
+ settings, ocspResponse):
+ #Send ServerHello, Certificate[, ServerKeyExchange]
+ #[, CertificateRequest], ServerHelloDone
+@@ -1613,11 +1619,12 @@ class TLSConnection(TLSRecordLayer):
+ serverKeyExchange = keyExchange.makeServerKeyExchange()
+ if serverKeyExchange is not None:
+ msgs.append(serverKeyExchange)
+- if reqCert and reqCAs:
+- msgs.append(CertificateRequest().create(\
+- [ClientCertificateType.rsa_sign], reqCAs))
+- elif reqCert:
+- msgs.append(CertificateRequest())
++ if reqCert:
++ reqCAs = reqCAs or []
++ #Apple's Secure Transport library rejects empty certificate_types,
++ #so default to rsa_sign.
++ reqCertTypes = reqCertTypes or [ClientCertificateType.rsa_sign]
++ msgs.append(CertificateRequest().create(reqCertTypes, reqCAs))
+ msgs.append(ServerHelloDone())
+ for result in self._sendMsgs(msgs):
+ yield result
diff --git a/third_party/tlslite/tlslite/api.py b/third_party/tlslite/tlslite/api.py
index faef6cb..562fb81 100644
--- a/third_party/tlslite/tlslite/api.py
+++ b/third_party/tlslite/tlslite/api.py
@@ -2,7 +2,8 @@
# See the LICENSE file for legal information regarding use of this file.
__version__ = "0.4.6"
-from .constants import AlertLevel, AlertDescription, Fault
+from .constants import AlertLevel, AlertDescription, ClientCertificateType, \
+ Fault
from .errors import *
from .checker import Checker
from .handshakesettings import HandshakeSettings
diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
index 30d1f9f..457b339 100644
--- a/third_party/tlslite/tlslite/constants.py
+++ b/third_party/tlslite/tlslite/constants.py
@@ -14,10 +14,14 @@ class CertificateType:
openpgp = 1
class ClientCertificateType:
+ # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-2
rsa_sign = 1
dss_sign = 2
rsa_fixed_dh = 3
dss_fixed_dh = 4
+ ecdsa_sign = 64
+ rsa_fixed_ecdh = 65
+ ecdsa_fixed_ecdh = 66
class HandshakeType:
hello_request = 0
diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
index 550b387..c8a913c 100644
--- a/third_party/tlslite/tlslite/messages.py
+++ b/third_party/tlslite/tlslite/messages.py
@@ -454,9 +454,7 @@ class CertificateStatus(HandshakeMsg):
class CertificateRequest(HandshakeMsg):
def __init__(self):
HandshakeMsg.__init__(self, HandshakeType.certificate_request)
- #Apple's Secure Transport library rejects empty certificate_types, so
- #default to rsa_sign.
- self.certificate_types = [ClientCertificateType.rsa_sign]
+ self.certificate_types = []
self.certificate_authorities = []
def create(self, certificate_types, certificate_authorities):
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
index e6f7820..044ad59 100644
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -1062,7 +1062,7 @@ class TLSConnection(TLSRecordLayer):
def handshakeServer(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs = None,
+ reqCAs = None, reqCertTypes = None,
tacks=None, activationFlags=0,
nextProtos=None, anon=False,
tlsIntolerant=None, signedCertTimestamps=None,
@@ -1130,6 +1130,10 @@ class TLSConnection(TLSRecordLayer):
will be sent along with a certificate request. This does not affect
verification.
+ @type reqCertTypes: list of int
+ @param reqCertTypes: A list of certificate_type values to be sent
+ along with a certificate request. This does not affect verification.
+
@type nextProtos: list of strings.
@param nextProtos: A list of upper layer protocols to expose to the
clients through the Next-Protocol Negotiation Extension,
@@ -1169,7 +1173,7 @@ class TLSConnection(TLSRecordLayer):
"""
for result in self.handshakeServerAsync(verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
- checker, reqCAs,
+ checker, reqCAs, reqCertTypes,
tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant,
signedCertTimestamps=signedCertTimestamps,
@@ -1180,7 +1184,7 @@ class TLSConnection(TLSRecordLayer):
def handshakeServerAsync(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs=None,
+ reqCAs=None, reqCertTypes=None,
tacks=None, activationFlags=0,
nextProtos=None, anon=False,
tlsIntolerant=None,
@@ -1203,7 +1207,7 @@ class TLSConnection(TLSRecordLayer):
verifierDB=verifierDB, certChain=certChain,
privateKey=privateKey, reqCert=reqCert,
sessionCache=sessionCache, settings=settings,
- reqCAs=reqCAs,
+ reqCAs=reqCAs, reqCertTypes=reqCertTypes,
tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon,
tlsIntolerant=tlsIntolerant,
@@ -1216,7 +1220,7 @@ class TLSConnection(TLSRecordLayer):
def _handshakeServerAsyncHelper(self, verifierDB,
certChain, privateKey, reqCert, sessionCache,
- settings, reqCAs,
+ settings, reqCAs, reqCertTypes,
tacks, activationFlags,
nextProtos, anon,
tlsIntolerant, signedCertTimestamps, fallbackSCSV,
@@ -1232,6 +1236,8 @@ class TLSConnection(TLSRecordLayer):
raise ValueError("Caller passed a privateKey but no certChain")
if reqCAs and not reqCert:
raise ValueError("Caller passed reqCAs but not reqCert")
+ if reqCertTypes and not reqCert:
+ raise ValueError("Caller passed reqCertTypes but not reqCert")
if certChain and not isinstance(certChain, X509CertChain):
raise ValueError("Unrecognized certificate type")
if activationFlags and not tacks:
@@ -1320,7 +1326,7 @@ class TLSConnection(TLSRecordLayer):
assert(False)
for result in self._serverCertKeyExchange(clientHello, serverHello,
certChain, keyExchange,
- reqCert, reqCAs, cipherSuite,
+ reqCert, reqCAs, reqCertTypes, cipherSuite,
settings, ocspResponse):
if result in (0,1): yield result
else: break
@@ -1597,7 +1603,7 @@ class TLSConnection(TLSRecordLayer):
def _serverCertKeyExchange(self, clientHello, serverHello,
serverCertChain, keyExchange,
- reqCert, reqCAs, cipherSuite,
+ reqCert, reqCAs, reqCertTypes, cipherSuite,
settings, ocspResponse):
#Send ServerHello, Certificate[, ServerKeyExchange]
#[, CertificateRequest], ServerHelloDone
@@ -1613,11 +1619,12 @@ class TLSConnection(TLSRecordLayer):
serverKeyExchange = keyExchange.makeServerKeyExchange()
if serverKeyExchange is not None:
msgs.append(serverKeyExchange)
- if reqCert and reqCAs:
- msgs.append(CertificateRequest().create(\
- [ClientCertificateType.rsa_sign], reqCAs))
- elif reqCert:
- msgs.append(CertificateRequest())
+ if reqCert:
+ reqCAs = reqCAs or []
+ #Apple's Secure Transport library rejects empty certificate_types,
+ #so default to rsa_sign.
+ reqCertTypes = reqCertTypes or [ClientCertificateType.rsa_sign]
+ msgs.append(CertificateRequest().create(reqCertTypes, reqCAs))
msgs.append(ServerHelloDone())
for result in self._sendMsgs(msgs):
yield result