Add a request_client_cert argument to server SSL conversion.

By default, we now do not request the client cert. We're supposed to be able to
do this with no negative effects - if the client has no cert to present, we're
notified and proceed as usual.  Unfortunately, Android seems to have a bug
(tested on 4.2.2) - when an Android client is asked to present a certificate it
does not have, it hangs up, which is frankly bogus.  Some time down the track
we may be able to make the proper behaviour the default again, but until then
we're conservative.
This commit is contained in:
Aldo Cortesi 2013-05-13 08:48:21 +12:00
parent 9c13224353
commit 7f0aa415e1
4 changed files with 24 additions and 8 deletions

View File

@ -5,9 +5,6 @@ from pyasn1.error import PyAsn1Error
import OpenSSL
import tcp
CERT_SLEEP_TIME = 1
CERT_EXPIRY = str(365 * 3)
def create_ca():
key = OpenSSL.crypto.PKey()

View File

@ -240,6 +240,7 @@ class TCPClient:
class BaseHandler:
"""
The instantiator is expected to call the handle() and finish() methods.
"""
rbufsize = -1
wbufsize = -1
@ -252,9 +253,10 @@ class BaseHandler:
self.server = server
self.finished = False
self.ssl_established = False
self.clientcert = None
def convert_to_ssl(self, cert, key, method=SSLv23_METHOD, options=None, handle_sni=None):
def convert_to_ssl(self, cert, key, method=SSLv23_METHOD, options=None, handle_sni=None, request_client_cert=False):
"""
method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or TLSv1_METHOD
handle_sni: SNI handler, should take a connection object. Server
@ -268,6 +270,15 @@ class BaseHandler:
new_context.use_privatekey(key)
new_context.use_certificate(cert)
connection.set_context(new_context)
The request_client_cert argument requires some explanation. We're
supposed to be able to do this with no negative effects - if the
client has no cert to present, we're notified and proceed as usual.
Unfortunately, Android seems to have a bug (tested on 4.2.2) - when
an Android client is asked to present a certificate it does not
have, it hangs up, which is frankly bogus. Some time down the track
we may be able to make the proper behaviour the default again, but
until then we're conservative.
"""
ctx = SSL.Context(method)
if not options is None:
@ -277,9 +288,10 @@ class BaseHandler:
ctx.set_tlsext_servername_callback(handle_sni)
ctx.use_privatekey_file(key)
ctx.use_certificate_file(cert)
def ver(*args):
self.clientcert = certutils.SSLCert(args[1])
ctx.set_verify(SSL.VERIFY_PEER, ver)
if request_client_cert:
def ver(*args):
self.clientcert = certutils.SSLCert(args[1])
ctx.set_verify(SSL.VERIFY_PEER, ver)
self.connection = SSL.Connection(ctx, self.connection)
self.ssl_established = True
self.connection.set_accept_state()

View File

@ -62,7 +62,8 @@ class TServer(tcp.TCPServer):
self.ssl["key"],
method = method,
options = options,
handle_sni = getattr(h, "handle_sni", None)
handle_sni = getattr(h, "handle_sni", None),
request_client_cert = self.ssl["request_client_cert"]
)
h.handle()
h.finish()

View File

@ -111,6 +111,7 @@ class TestServerSSL(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = False,
v3_only = False
)
def test_echo(self):
@ -131,6 +132,7 @@ class TestSSLv3Only(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = False,
v3_only = True
)
def test_failure(self):
@ -144,6 +146,7 @@ class TestSSLClientCert(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = True,
v3_only = False
)
def test_clientcert(self):
@ -167,6 +170,7 @@ class TestSNI(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = False,
v3_only = False
)
def test_echo(self):
@ -181,6 +185,7 @@ class TestSSLDisconnect(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = False,
v3_only = False
)
def test_echo(self):
@ -228,6 +233,7 @@ class TestSSLTimeOut(test.ServerTestBase):
ssl = dict(
cert = tutils.test_data.path("data/server.crt"),
key = tutils.test_data.path("data/server.key"),
request_client_cert = False,
v3_only = False
)
def test_timeout_client(self):