diff options
-rw-r--r-- | DEPS | 2 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.cc | 19 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_openssl.h | 4 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 17 | ||||
-rw-r--r-- | net/test/spawned_test_server/base_test_server.cc | 22 | ||||
-rw-r--r-- | net/test/spawned_test_server/base_test_server.h | 6 | ||||
-rwxr-xr-x | net/tools/testserver/testserver.py | 33 | ||||
-rw-r--r-- | third_party/tlslite/README.chromium | 2 | ||||
-rw-r--r-- | third_party/tlslite/patches/req_cert_types.patch | 153 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/api.py | 3 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/constants.py | 4 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/messages.py | 4 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/tlsconnection.py | 31 |
13 files changed, 273 insertions, 27 deletions
@@ -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 |