Commit c0787704 authored by davidben@chromium.org's avatar davidben@chromium.org

Populate cert_key_types on OpenSSL.

Add a test to ensure it gets plumbed through correctly.

This also rolls third_party/openssl to r270417:
------------------------------------------------------------------------
r269864 | davidben@chromium.org | 2014-05-12 16:21:12 -0400 (Mon, 12 May 2014) | 7 lines

Add SSL_get_client_certificate_types.

Exposes the certificate_types parameter in a CertificateRequest.

BUG=165446

Review URL: https://codereview.chromium.org/254723002
------------------------------------------------------------------------
r270417 | davidben@chromium.org | 2014-05-14 12:27:52 -0400 (Wed, 14 May 2014) | 10 lines

Refactor ssl3_send_client_verify.

The original logic was a confusing spaghetti and mixed up initialization for
all the different cases together. Tidy it up in preparation for having to
adjust this logic later to support asynchronous crypto operations.

BUG=none
R=agl@chromium.org

Review URL: https://codereview.chromium.org//284693002
------------------------------------------------------------------------


BUG=165446

Review URL: https://codereview.chromium.org/257513008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271765 0039d316-1c4b-4281-b951-d872f2087c98
parent e36de125
...@@ -65,7 +65,7 @@ vars = { ...@@ -65,7 +65,7 @@ vars = {
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling openssl # the commit queue can handle CLs rolling openssl
# and whatever else without interference from each other. # and whatever else without interference from each other.
"openssl_revision": "269063", "openssl_revision": "270417",
# Three lines of non-changing comments so that # Three lines of non-changing comments so that
# the commit queue can handle CLs rolling ANGLE # the commit queue can handle CLs rolling ANGLE
# and whatever else without interference from each other. # and whatever else without interference from each other.
......
...@@ -370,6 +370,7 @@ void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( ...@@ -370,6 +370,7 @@ void SSLClientSocketOpenSSL::GetSSLCertRequestInfo(
SSLCertRequestInfo* cert_request_info) { SSLCertRequestInfo* cert_request_info) {
cert_request_info->host_and_port = host_and_port_; cert_request_info->host_and_port = host_and_port_;
cert_request_info->cert_authorities = cert_authorities_; cert_request_info->cert_authorities = cert_authorities_;
cert_request_info->cert_key_types = cert_key_types_;
} }
SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto(
...@@ -473,6 +474,7 @@ void SSLClientSocketOpenSSL::Disconnect() { ...@@ -473,6 +474,7 @@ void SSLClientSocketOpenSSL::Disconnect() {
completed_handshake_ = false; completed_handshake_ = false;
cert_authorities_.clear(); cert_authorities_.clear();
cert_key_types_.clear();
client_auth_cert_needed_ = false; client_auth_cert_needed_ = false;
} }
...@@ -1264,7 +1266,6 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, ...@@ -1264,7 +1266,6 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
DCHECK(ssl == ssl_); DCHECK(ssl == ssl_);
DCHECK(*x509 == NULL); DCHECK(*x509 == NULL);
DCHECK(*pkey == NULL); DCHECK(*pkey == NULL);
#if defined(USE_OPENSSL_CERTS)
if (!ssl_config_.send_client_cert) { if (!ssl_config_.send_client_cert) {
// First pass: we know that a client certificate is needed, but we do not // First pass: we know that a client certificate is needed, but we do not
// have one at hand. // have one at hand.
...@@ -1280,11 +1281,21 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, ...@@ -1280,11 +1281,21 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
OPENSSL_free(str); 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. return -1; // Suspends handshake.
} }
// Second pass: a client certificate should have been selected. // Second pass: a client certificate should have been selected.
if (ssl_config_.client_cert.get()) { if (ssl_config_.client_cert.get()) {
#if defined(USE_OPENSSL_CERTS)
// A note about ownership: FetchClientCertPrivateKey() increments // A note about ownership: FetchClientCertPrivateKey() increments
// the reference count of the EVP_PKEY. Ownership of this reference // the reference count of the EVP_PKEY. Ownership of this reference
// is passed directly to OpenSSL, which will release the reference // is passed directly to OpenSSL, which will release the reference
...@@ -1300,11 +1311,11 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, ...@@ -1300,11 +1311,11 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
return 1; return 1;
} }
LOG(WARNING) << "Client cert found without private key"; LOG(WARNING) << "Client cert found without private key";
}
#else // !defined(USE_OPENSSL_CERTS) #else // !defined(USE_OPENSSL_CERTS)
// OS handling of client certificates is not yet implemented. // OS handling of client certificates is not yet implemented.
NOTIMPLEMENTED(); NOTIMPLEMENTED();
#endif // defined(USE_OPENSSL_CERTS) #endif // defined(USE_OPENSSL_CERTS)
}
// Send no client certificate. // Send no client certificate.
return 0; return 0;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket.h"
#include "net/ssl/server_bound_cert_service.h" #include "net/ssl/server_bound_cert_service.h"
#include "net/ssl/ssl_client_cert_type.h"
#include "net/ssl/ssl_config_service.h" #include "net/ssl/ssl_config_service.h"
// Avoid including misc OpenSSL headers, i.e.: // Avoid including misc OpenSSL headers, i.e.:
...@@ -197,6 +198,9 @@ class SSLClientSocketOpenSSL : public SSLClientSocket { ...@@ -197,6 +198,9 @@ class SSLClientSocketOpenSSL : public SSLClientSocket {
// List of DER-encoded X.509 DistinguishedName of certificate authorities // List of DER-encoded X.509 DistinguishedName of certificate authorities
// allowed by the server. // allowed by the server.
std::vector<std::string> cert_authorities_; 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_; CertVerifier* const cert_verifier_;
scoped_ptr<SingleRequestCertVerifier> verifier_; scoped_ptr<SingleRequestCertVerifier> verifier_;
......
...@@ -704,6 +704,8 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest { ...@@ -704,6 +704,8 @@ class SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest {
sock->GetSSLCertRequestInfo(request_info.get()); sock->GetSSLCertRequestInfo(request_info.get());
sock->Disconnect(); sock->Disconnect();
EXPECT_FALSE(sock->IsConnected()); EXPECT_FALSE(sock->IsConnected());
EXPECT_TRUE(
test_server.host_port_pair().Equals(request_info->host_and_port));
return request_info; return request_info;
} }
...@@ -2219,6 +2221,21 @@ TEST_F(SSLClientSocketCertRequestInfoTest, TwoAuthorities) { ...@@ -2219,6 +2221,21 @@ TEST_F(SSLClientSocketCertRequestInfoTest, TwoAuthorities) {
request_info->cert_authorities[1]); 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) { TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) {
SpawnedTestServer::SSLOptions ssl_options; SpawnedTestServer::SSLOptions ssl_options;
ssl_options.signed_cert_timestamps_tls_ext = "test"; ssl_options.signed_cert_timestamps_tls_ext = "test";
......
...@@ -40,6 +40,20 @@ std::string GetHostname(BaseTestServer::Type type, ...@@ -40,6 +40,20 @@ std::string GetHostname(BaseTestServer::Type type,
return BaseTestServer::kLocalhost; 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) { void GetKeyExchangesList(int key_exchange, base::ListValue* values) {
if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_RSA) if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_RSA)
values->Append(new base::StringValue("rsa")); values->Append(new base::StringValue("rsa"));
...@@ -386,6 +400,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { ...@@ -386,6 +400,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const {
if (ssl_client_certs->GetSize()) if (ssl_client_certs->GetSize())
arguments->Set("ssl-client-ca", ssl_client_certs.release()); 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) { if (type_ == TYPE_HTTPS) {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "net/base/host_port_pair.h" #include "net/base/host_port_pair.h"
#include "net/ssl/ssl_client_cert_type.h"
class GURL; class GURL;
...@@ -146,6 +147,11 @@ class BaseTestServer { ...@@ -146,6 +147,11 @@ class BaseTestServer {
// field of the CertificateRequest. // field of the CertificateRequest.
std::vector<base::FilePath> client_authorities; 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 // A bitwise-OR of KeyExchnage that should be used by the
// HTTPS server, or KEY_EXCHANGE_ANY to indicate that all implemented // HTTPS server, or KEY_EXCHANGE_ANY to indicate that all implemented
// key exchange algorithms are acceptable. // key exchange algorithms are acceptable.
......
...@@ -152,7 +152,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, ...@@ -152,7 +152,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
client verification.""" client verification."""
def __init__(self, server_address, request_hander_class, pem_cert_and_key, 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, ssl_bulk_ciphers, ssl_key_exchanges, enable_npn,
record_resume_info, tls_intolerant, signed_cert_timestamps, record_resume_info, tls_intolerant, signed_cert_timestamps,
fallback_scsv_enabled, ocsp_response): fallback_scsv_enabled, ocsp_response):
...@@ -167,6 +167,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, ...@@ -167,6 +167,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
implementations=['python']) implementations=['python'])
self.ssl_client_auth = ssl_client_auth self.ssl_client_auth = ssl_client_auth
self.ssl_client_cas = [] self.ssl_client_cas = []
self.ssl_client_cert_types = []
if enable_npn: if enable_npn:
self.next_protos = ['http/1.1'] self.next_protos = ['http/1.1']
else: else:
...@@ -179,11 +180,20 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, ...@@ -179,11 +180,20 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
self.fallback_scsv_enabled = fallback_scsv_enabled self.fallback_scsv_enabled = fallback_scsv_enabled
self.ocsp_response = ocsp_response self.ocsp_response = ocsp_response
for ca_file in ssl_client_cas: if ssl_client_auth:
s = open(ca_file).read() for ca_file in ssl_client_cas:
x509 = tlslite.api.X509() s = open(ca_file).read()
x509.parse(s) x509 = tlslite.api.X509()
self.ssl_client_cas.append(x509.subject) 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() self.ssl_handshake_settings = tlslite.api.HandshakeSettings()
if ssl_bulk_ciphers is not None: if ssl_bulk_ciphers is not None:
self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers self.ssl_handshake_settings.cipherNames = ssl_bulk_ciphers
...@@ -211,6 +221,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, ...@@ -211,6 +221,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn,
reqCert=self.ssl_client_auth, reqCert=self.ssl_client_auth,
settings=self.ssl_handshake_settings, settings=self.ssl_handshake_settings,
reqCAs=self.ssl_client_cas, reqCAs=self.ssl_client_cas,
reqCertTypes=self.ssl_client_cert_types,
nextProtos=self.next_protos, nextProtos=self.next_protos,
tlsIntolerant=self.tls_intolerant, tlsIntolerant=self.tls_intolerant,
signedCertTimestamps= signedCertTimestamps=
...@@ -1989,6 +2000,7 @@ class ServerRunner(testserver_base.TestServerRunner): ...@@ -1989,6 +2000,7 @@ class ServerRunner(testserver_base.TestServerRunner):
server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key, server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
self.options.ssl_client_auth, self.options.ssl_client_auth,
self.options.ssl_client_ca, self.options.ssl_client_ca,
self.options.ssl_client_cert_type,
self.options.ssl_bulk_cipher, self.options.ssl_bulk_cipher,
self.options.ssl_key_exchange, self.options.ssl_key_exchange,
self.options.enable_npn, self.options.enable_npn,
...@@ -2172,6 +2184,15 @@ class ServerRunner(testserver_base.TestServerRunner): ...@@ -2172,6 +2184,15 @@ class ServerRunner(testserver_base.TestServerRunner):
'file. This option may appear multiple ' 'file. This option may appear multiple '
'times, indicating multiple CA names should ' 'times, indicating multiple CA names should '
'be sent in the request.') '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', self.option_parser.add_option('--ssl-bulk-cipher', action='append',
help='Specify the bulk encryption ' help='Specify the bulk encryption '
'algorithm(s) that will be accepted by the ' 'algorithm(s) that will be accepted by the '
......
...@@ -31,3 +31,5 @@ Local Modifications: ...@@ -31,3 +31,5 @@ Local Modifications:
- patches/fix_test_file.patch: Fix #! line in random test file to appease our - patches/fix_test_file.patch: Fix #! line in random test file to appease our
presubmit checks. presubmit checks.
- patches/dhe_rsa.patch: Implement DHE_RSA-based cipher suites. - 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/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
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
# See the LICENSE file for legal information regarding use of this file. # See the LICENSE file for legal information regarding use of this file.
__version__ = "0.4.6" __version__ = "0.4.6"
from .constants import AlertLevel, AlertDescription, Fault from .constants import AlertLevel, AlertDescription, ClientCertificateType, \
Fault
from .errors import * from .errors import *
from .checker import Checker from .checker import Checker
from .handshakesettings import HandshakeSettings from .handshakesettings import HandshakeSettings
......
...@@ -14,10 +14,14 @@ class CertificateType: ...@@ -14,10 +14,14 @@ class CertificateType:
openpgp = 1 openpgp = 1
class ClientCertificateType: class ClientCertificateType:
# http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-2
rsa_sign = 1 rsa_sign = 1
dss_sign = 2 dss_sign = 2
rsa_fixed_dh = 3 rsa_fixed_dh = 3
dss_fixed_dh = 4 dss_fixed_dh = 4
ecdsa_sign = 64
rsa_fixed_ecdh = 65
ecdsa_fixed_ecdh = 66
class HandshakeType: class HandshakeType:
hello_request = 0 hello_request = 0
......
...@@ -454,9 +454,7 @@ class CertificateStatus(HandshakeMsg): ...@@ -454,9 +454,7 @@ class CertificateStatus(HandshakeMsg):
class CertificateRequest(HandshakeMsg): class CertificateRequest(HandshakeMsg):
def __init__(self): def __init__(self):
HandshakeMsg.__init__(self, HandshakeType.certificate_request) HandshakeMsg.__init__(self, HandshakeType.certificate_request)
#Apple's Secure Transport library rejects empty certificate_types, so self.certificate_types = []
#default to rsa_sign.
self.certificate_types = [ClientCertificateType.rsa_sign]
self.certificate_authorities = [] self.certificate_authorities = []
def create(self, certificate_types, certificate_authorities): def create(self, certificate_types, certificate_authorities):
......
...@@ -1062,7 +1062,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1062,7 +1062,7 @@ class TLSConnection(TLSRecordLayer):
def handshakeServer(self, verifierDB=None, def handshakeServer(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False, certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None, sessionCache=None, settings=None, checker=None,
reqCAs = None, reqCAs = None, reqCertTypes = None,
tacks=None, activationFlags=0, tacks=None, activationFlags=0,
nextProtos=None, anon=False, nextProtos=None, anon=False,
tlsIntolerant=None, signedCertTimestamps=None, tlsIntolerant=None, signedCertTimestamps=None,
...@@ -1130,6 +1130,10 @@ class TLSConnection(TLSRecordLayer): ...@@ -1130,6 +1130,10 @@ class TLSConnection(TLSRecordLayer):
will be sent along with a certificate request. This does not affect will be sent along with a certificate request. This does not affect
verification. 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. @type nextProtos: list of strings.
@param nextProtos: A list of upper layer protocols to expose to the @param nextProtos: A list of upper layer protocols to expose to the
clients through the Next-Protocol Negotiation Extension, clients through the Next-Protocol Negotiation Extension,
...@@ -1169,7 +1173,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1169,7 +1173,7 @@ class TLSConnection(TLSRecordLayer):
""" """
for result in self.handshakeServerAsync(verifierDB, for result in self.handshakeServerAsync(verifierDB,
certChain, privateKey, reqCert, sessionCache, settings, certChain, privateKey, reqCert, sessionCache, settings,
checker, reqCAs, checker, reqCAs, reqCertTypes,
tacks=tacks, activationFlags=activationFlags, tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant, nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant,
signedCertTimestamps=signedCertTimestamps, signedCertTimestamps=signedCertTimestamps,
...@@ -1180,7 +1184,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1180,7 +1184,7 @@ class TLSConnection(TLSRecordLayer):
def handshakeServerAsync(self, verifierDB=None, def handshakeServerAsync(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False, certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None, sessionCache=None, settings=None, checker=None,
reqCAs=None, reqCAs=None, reqCertTypes=None,
tacks=None, activationFlags=0, tacks=None, activationFlags=0,
nextProtos=None, anon=False, nextProtos=None, anon=False,
tlsIntolerant=None, tlsIntolerant=None,
...@@ -1203,7 +1207,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1203,7 +1207,7 @@ class TLSConnection(TLSRecordLayer):
verifierDB=verifierDB, certChain=certChain, verifierDB=verifierDB, certChain=certChain,
privateKey=privateKey, reqCert=reqCert, privateKey=privateKey, reqCert=reqCert,
sessionCache=sessionCache, settings=settings, sessionCache=sessionCache, settings=settings,
reqCAs=reqCAs, reqCAs=reqCAs, reqCertTypes=reqCertTypes,
tacks=tacks, activationFlags=activationFlags, tacks=tacks, activationFlags=activationFlags,
nextProtos=nextProtos, anon=anon, nextProtos=nextProtos, anon=anon,
tlsIntolerant=tlsIntolerant, tlsIntolerant=tlsIntolerant,
...@@ -1216,7 +1220,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1216,7 +1220,7 @@ class TLSConnection(TLSRecordLayer):
def _handshakeServerAsyncHelper(self, verifierDB, def _handshakeServerAsyncHelper(self, verifierDB,
certChain, privateKey, reqCert, sessionCache, certChain, privateKey, reqCert, sessionCache,
settings, reqCAs, settings, reqCAs, reqCertTypes,
tacks, activationFlags, tacks, activationFlags,
nextProtos, anon, nextProtos, anon,
tlsIntolerant, signedCertTimestamps, fallbackSCSV, tlsIntolerant, signedCertTimestamps, fallbackSCSV,
...@@ -1232,6 +1236,8 @@ class TLSConnection(TLSRecordLayer): ...@@ -1232,6 +1236,8 @@ class TLSConnection(TLSRecordLayer):
raise ValueError("Caller passed a privateKey but no certChain") raise ValueError("Caller passed a privateKey but no certChain")
if reqCAs and not reqCert: if reqCAs and not reqCert:
raise ValueError("Caller passed reqCAs but 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): if certChain and not isinstance(certChain, X509CertChain):
raise ValueError("Unrecognized certificate type") raise ValueError("Unrecognized certificate type")
if activationFlags and not tacks: if activationFlags and not tacks:
...@@ -1320,7 +1326,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1320,7 +1326,7 @@ class TLSConnection(TLSRecordLayer):
assert(False) assert(False)
for result in self._serverCertKeyExchange(clientHello, serverHello, for result in self._serverCertKeyExchange(clientHello, serverHello,
certChain, keyExchange, certChain, keyExchange,
reqCert, reqCAs, cipherSuite, reqCert, reqCAs, reqCertTypes, cipherSuite,
settings, ocspResponse): settings, ocspResponse):
if result in (0,1): yield result if result in (0,1): yield result
else: break else: break
...@@ -1597,7 +1603,7 @@ class TLSConnection(TLSRecordLayer): ...@@ -1597,7 +1603,7 @@ class TLSConnection(TLSRecordLayer):
def _serverCertKeyExchange(self, clientHello, serverHello, def _serverCertKeyExchange(self, clientHello, serverHello,
serverCertChain, keyExchange, serverCertChain, keyExchange,
reqCert, reqCAs, cipherSuite, reqCert, reqCAs, reqCertTypes, cipherSuite,
settings, ocspResponse): settings, ocspResponse):
#Send ServerHello, Certificate[, ServerKeyExchange] #Send ServerHello, Certificate[, ServerKeyExchange]
#[, CertificateRequest], ServerHelloDone #[, CertificateRequest], ServerHelloDone
...@@ -1613,11 +1619,12 @@ class TLSConnection(TLSRecordLayer): ...@@ -1613,11 +1619,12 @@ class TLSConnection(TLSRecordLayer):
serverKeyExchange = keyExchange.makeServerKeyExchange() serverKeyExchange = keyExchange.makeServerKeyExchange()
if serverKeyExchange is not None: if serverKeyExchange is not None:
msgs.append(serverKeyExchange) msgs.append(serverKeyExchange)
if reqCert and reqCAs: if reqCert:
msgs.append(CertificateRequest().create(\ reqCAs = reqCAs or []
[ClientCertificateType.rsa_sign], reqCAs)) #Apple's Secure Transport library rejects empty certificate_types,
elif reqCert: #so default to rsa_sign.
msgs.append(CertificateRequest()) reqCertTypes = reqCertTypes or [ClientCertificateType.rsa_sign]
msgs.append(CertificateRequest().create(reqCertTypes, reqCAs))
msgs.append(ServerHelloDone()) msgs.append(ServerHelloDone())
for result in self._sendMsgs(msgs): for result in self._sendMsgs(msgs):
yield result yield result
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment