summaryrefslogtreecommitdiffstats
path: root/third_party/tlslite
diff options
context:
space:
mode:
authorrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-21 04:02:44 +0000
committerrsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-21 04:02:44 +0000
commitb3992377f4e52a205164d4da5dc7e465e749a57e (patch)
tree6f1b1f6216ffa5053edb6836be53d89475463a8f /third_party/tlslite
parentbbf7e53f9a96ebd3a4f2835ea5ee561f03ef534e (diff)
downloadchromium_src-b3992377f4e52a205164d4da5dc7e465e749a57e.zip
chromium_src-b3992377f4e52a205164d4da5dc7e465e749a57e.tar.gz
chromium_src-b3992377f4e52a205164d4da5dc7e465e749a57e.tar.bz2
Improve support for requesting client certs in tlslite
Currently, tlslite only supports the caller passing in a list of CAs pre-encoded for the TLS CertificateRequest message. This CL improves that, by providing a means of extracting the DER-encoded subject name from an X509 certificate, supplying a list of such names to tlslite's server routines, and having tlslite encode the list of CAs as part of the CertificateRequest. BUG=47656, 47658 TEST=net_unittests Review URL: http://codereview.chromium.org/3177015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56982 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tlslite')
-rw-r--r--third_party/tlslite/README.chromium11
-rw-r--r--third_party/tlslite/patches/ca_request.patch176
-rw-r--r--third_party/tlslite/tlslite/TLSConnection.py24
-rw-r--r--third_party/tlslite/tlslite/X509.py8
-rw-r--r--third_party/tlslite/tlslite/messages.py20
-rw-r--r--third_party/tlslite/tlslite/utils/ASN1Parser.py5
6 files changed, 233 insertions, 11 deletions
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index 8e2d3729..792d7e4 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -10,3 +10,14 @@ Local Modifications:
http://sourceforge.net/mailarchive/forum.php?thread_name=41C9B18B.2010201%40ag.com&forum_name=tlslite-users
- patches/python26.patch: Replace sha, md5 module imports with hashlib, as
they are deprecated in Python 2.6
+- patches/ca_request.patch: tlslite/X509.py was changed to obtain the
+ DER-encoded distinguished name for a certificate, without requiring any
+ addition libraries.
+ tlslite/utils/ASN1Parser.py was changed to allow obtaining the unparsed
+ data for an element in a SEQUENCE, in addition to providing the parsed
+ value (tag and length removed)
+ tlslite/messages.py was changed from accepting/returning a single byte
+ array in the CertificateRequest message for the CA names to accept a list
+ of byte arrays, each containing a DER-encoded distinguished name.
+ tlslite/TLSConnection.py was changed to take a list of such byte arrays
+ when creating a TLS server that will request client authentication.
diff --git a/third_party/tlslite/patches/ca_request.patch b/third_party/tlslite/patches/ca_request.patch
new file mode 100644
index 0000000..c1270c0
--- /dev/null
+++ b/third_party/tlslite/patches/ca_request.patch
@@ -0,0 +1,176 @@
+Only in chromium: patches
+diff -aur tlslite-0.3.8/tlslite/TLSConnection.py chromium/tlslite/TLSConnection.py
+--- tlslite-0.3.8/tlslite/TLSConnection.py 2004-10-06 01:55:37.000000000 -0400
++++ chromium/tlslite/TLSConnection.py 2010-08-18 22:17:30.962786700 -0400
+@@ -931,7 +931,8 @@
+
+ def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+- sessionCache=None, settings=None, checker=None):
++ sessionCache=None, settings=None, checker=None,
++ reqCAs=None):
+ """Perform a handshake in the role of server.
+
+ This function performs an SSL or TLS handshake. Depending on
+@@ -997,6 +998,11 @@
+ invoked to examine the other party's authentication
+ credentials, if the handshake completes succesfully.
+
++ @type reqCAs: list of L{array.array} of unsigned bytes
++ @param reqCAs: A collection of DER-encoded DistinguishedNames that
++ will be sent along with a certificate request. This does not affect
++ verification.
++
+ @raise socket.error: If a socket error occurs.
+ @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
+ without a preceding alert.
+@@ -1006,13 +1012,14 @@
+ """
+ for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
+ certChain, privateKey, reqCert, sessionCache, settings,
+- checker):
++ checker, reqCAs):
+ pass
+
+
+ def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
+ certChain=None, privateKey=None, reqCert=False,
+- sessionCache=None, settings=None, checker=None):
++ sessionCache=None, settings=None, checker=None,
++ reqCAs=None):
+ """Start a server handshake operation on the TLS connection.
+
+ This function returns a generator which behaves similarly to
+@@ -1028,14 +1035,15 @@
+ sharedKeyDB=sharedKeyDB,
+ verifierDB=verifierDB, certChain=certChain,
+ privateKey=privateKey, reqCert=reqCert,
+- sessionCache=sessionCache, settings=settings)
++ sessionCache=sessionCache, settings=settings,
++ reqCAs=reqCAs)
+ for result in self._handshakeWrapperAsync(handshaker, checker):
+ yield result
+
+
+ def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB,
+ certChain, privateKey, reqCert, sessionCache,
+- settings):
++ settings, reqCAs):
+
+ self._handshakeStart(client=False)
+
+@@ -1045,6 +1053,8 @@
+ raise ValueError("Caller passed a certChain but no privateKey")
+ if privateKey and not certChain:
+ raise ValueError("Caller passed a privateKey but no certChain")
++ if reqCAs and not reqCert:
++ raise ValueError("Caller passed reqCAs but not reqCert")
+
+ if not settings:
+ settings = HandshakeSettings()
+@@ -1380,7 +1390,9 @@
+ msgs.append(ServerHello().create(self.version, serverRandom,
+ sessionID, cipherSuite, certificateType))
+ msgs.append(Certificate(certificateType).create(serverCertChain))
+- if reqCert:
++ if reqCert and reqCAs:
++ msgs.append(CertificateRequest().create([], reqCAs))
++ elif reqCert:
+ msgs.append(CertificateRequest())
+ msgs.append(ServerHelloDone())
+ for result in self._sendMsgs(msgs):
+diff -aur tlslite-0.3.8/tlslite/X509.py chromium/tlslite/X509.py
+--- tlslite-0.3.8/tlslite/X509.py 2004-03-19 21:43:19.000000000 -0400
++++ chromium/tlslite/X509.py 2010-08-18 22:17:30.967787000 -0400
+@@ -13,11 +13,15 @@
+
+ @type publicKey: L{tlslite.utils.RSAKey.RSAKey}
+ @ivar publicKey: The subject public key from the certificate.
++
++ @type subject: L{array.array} of unsigned bytes
++ @ivar subject: The DER-encoded ASN.1 subject distinguished name.
+ """
+
+ def __init__(self):
+ self.bytes = createByteArraySequence([])
+ self.publicKey = None
++ self.subject = None
+
+ def parse(self, s):
+ """Parse a PEM-encoded X.509 certificate.
+@@ -63,6 +67,10 @@
+ else:
+ subjectPublicKeyInfoIndex = 5
+
++ #Get the subject
++ self.subject = tbsCertificateP.getChildBytes(\
++ subjectPublicKeyInfoIndex - 1)
++
+ #Get the subjectPublicKeyInfo
+ subjectPublicKeyInfoP = tbsCertificateP.getChild(\
+ subjectPublicKeyInfoIndex)
+diff -aur tlslite-0.3.8/tlslite/messages.py chromium/tlslite/messages.py
+--- tlslite-0.3.8/tlslite/messages.py 2004-10-06 01:01:24.000000000 -0400
++++ chromium/tlslite/messages.py 2010-08-18 22:17:30.976787500 -0400
+@@ -338,8 +338,7 @@
+ def __init__(self):
+ self.contentType = ContentType.handshake
+ self.certificate_types = []
+- #treat as opaque bytes for now
+- self.certificate_authorities = createByteArraySequence([])
++ self.certificate_authorities = []
+
+ def create(self, certificate_types, certificate_authorities):
+ self.certificate_types = certificate_types
+@@ -349,7 +348,13 @@
+ def parse(self, p):
+ p.startLengthCheck(3)
+ self.certificate_types = p.getVarList(1, 1)
+- self.certificate_authorities = p.getVarBytes(2)
++ ca_list_length = p.get(2)
++ index = 0
++ self.certificate_authorities = []
++ while index != ca_list_length:
++ ca_bytes = p.getVarBytes(2)
++ self.certificate_authorities.append(ca_bytes)
++ index += len(ca_bytes)+2
+ p.stopLengthCheck()
+ return self
+
+@@ -357,7 +362,14 @@
+ w = HandshakeMsg.preWrite(self, HandshakeType.certificate_request,
+ trial)
+ w.addVarSeq(self.certificate_types, 1, 1)
+- w.addVarSeq(self.certificate_authorities, 1, 2)
++ caLength = 0
++ #determine length
++ for ca_dn in self.certificate_authorities:
++ caLength += len(ca_dn)+2
++ w.add(caLength, 2)
++ #add bytes
++ for ca_dn in self.certificate_authorities:
++ w.addVarSeq(ca_dn, 1, 2)
+ return HandshakeMsg.postWrite(self, w, trial)
+
+ class ServerKeyExchange(HandshakeMsg):
+diff -aur tlslite-0.3.8/tlslite/utils/ASN1Parser.py chromium/tlslite/utils/ASN1Parser.py
+--- tlslite-0.3.8/tlslite/utils/ASN1Parser.py 2004-10-06 01:02:40.000000000 -0400
++++ chromium/tlslite/utils/ASN1Parser.py 2010-08-18 22:17:30.979787700 -0400
+@@ -16,13 +16,16 @@
+
+ #Assuming this is a sequence...
+ def getChild(self, which):
++ return ASN1Parser(self.getChildBytes(which))
++
++ def getChildBytes(self, which):
+ p = Parser(self.value)
+ for x in range(which+1):
+ markIndex = p.index
+ p.get(1) #skip Type
+ length = self._getASN1Length(p)
+ p.getFixBytes(length)
+- return ASN1Parser(p.bytes[markIndex : p.index])
++ return p.bytes[markIndex : p.index]
+
+ #Decode the ASN.1 DER length field
+ def _getASN1Length(self, p):
diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py
index d125f8f..7e38a23 100644
--- a/third_party/tlslite/tlslite/TLSConnection.py
+++ b/third_party/tlslite/tlslite/TLSConnection.py
@@ -931,7 +931,8 @@ class TLSConnection(TLSRecordLayer):
def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
- sessionCache=None, settings=None, checker=None):
+ sessionCache=None, settings=None, checker=None,
+ reqCAs=None):
"""Perform a handshake in the role of server.
This function performs an SSL or TLS handshake. Depending on
@@ -997,6 +998,11 @@ class TLSConnection(TLSRecordLayer):
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
+ @type reqCAs: list of L{array.array} of unsigned bytes
+ @param reqCAs: A collection of DER-encoded DistinguishedNames that
+ will be sent along with a certificate request. This does not affect
+ verification.
+
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@@ -1006,13 +1012,14 @@ class TLSConnection(TLSRecordLayer):
"""
for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
- checker):
+ checker, reqCAs):
pass
def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
- sessionCache=None, settings=None, checker=None):
+ sessionCache=None, settings=None, checker=None,
+ reqCAs=None):
"""Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
@@ -1028,14 +1035,15 @@ class TLSConnection(TLSRecordLayer):
sharedKeyDB=sharedKeyDB,
verifierDB=verifierDB, certChain=certChain,
privateKey=privateKey, reqCert=reqCert,
- sessionCache=sessionCache, settings=settings)
+ sessionCache=sessionCache, settings=settings,
+ reqCAs=reqCAs)
for result in self._handshakeWrapperAsync(handshaker, checker):
yield result
def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache,
- settings):
+ settings, reqCAs):
self._handshakeStart(client=False)
@@ -1045,6 +1053,8 @@ class TLSConnection(TLSRecordLayer):
raise ValueError("Caller passed a certChain but no privateKey")
if privateKey and not certChain:
raise ValueError("Caller passed a privateKey but no certChain")
+ if reqCAs and not reqCert:
+ raise ValueError("Caller passed reqCAs but not reqCert")
if not settings:
settings = HandshakeSettings()
@@ -1380,7 +1390,9 @@ class TLSConnection(TLSRecordLayer):
msgs.append(ServerHello().create(self.version, serverRandom,
sessionID, cipherSuite, certificateType))
msgs.append(Certificate(certificateType).create(serverCertChain))
- if reqCert:
+ if reqCert and reqCAs:
+ msgs.append(CertificateRequest().create([], reqCAs))
+ elif reqCert:
msgs.append(CertificateRequest())
msgs.append(ServerHelloDone())
for result in self._sendMsgs(msgs):
diff --git a/third_party/tlslite/tlslite/X509.py b/third_party/tlslite/tlslite/X509.py
index a47ddcf..d8b8bcc 100644
--- a/third_party/tlslite/tlslite/X509.py
+++ b/third_party/tlslite/tlslite/X509.py
@@ -13,11 +13,15 @@ class X509:
@type publicKey: L{tlslite.utils.RSAKey.RSAKey}
@ivar publicKey: The subject public key from the certificate.
+
+ @type subject: L{array.array} of unsigned bytes
+ @ivar subject: The DER-encoded ASN.1 subject distinguished name.
"""
def __init__(self):
self.bytes = createByteArraySequence([])
self.publicKey = None
+ self.subject = None
def parse(self, s):
"""Parse a PEM-encoded X.509 certificate.
@@ -63,6 +67,10 @@ class X509:
else:
subjectPublicKeyInfoIndex = 5
+ #Get the subject
+ self.subject = tbsCertificateP.getChildBytes(\
+ subjectPublicKeyInfoIndex - 1)
+
#Get the subjectPublicKeyInfo
subjectPublicKeyInfoP = tbsCertificateP.getChild(\
subjectPublicKeyInfoIndex)
diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
index 06c46b9..fb4cc21 100644
--- a/third_party/tlslite/tlslite/messages.py
+++ b/third_party/tlslite/tlslite/messages.py
@@ -347,8 +347,7 @@ class CertificateRequest(HandshakeMsg):
def __init__(self):
self.contentType = ContentType.handshake
self.certificate_types = []
- #treat as opaque bytes for now
- self.certificate_authorities = createByteArraySequence([])
+ self.certificate_authorities = []
def create(self, certificate_types, certificate_authorities):
self.certificate_types = certificate_types
@@ -358,7 +357,13 @@ class CertificateRequest(HandshakeMsg):
def parse(self, p):
p.startLengthCheck(3)
self.certificate_types = p.getVarList(1, 1)
- self.certificate_authorities = p.getVarBytes(2)
+ ca_list_length = p.get(2)
+ index = 0
+ self.certificate_authorities = []
+ while index != ca_list_length:
+ ca_bytes = p.getVarBytes(2)
+ self.certificate_authorities.append(ca_bytes)
+ index += len(ca_bytes)+2
p.stopLengthCheck()
return self
@@ -366,7 +371,14 @@ class CertificateRequest(HandshakeMsg):
w = HandshakeMsg.preWrite(self, HandshakeType.certificate_request,
trial)
w.addVarSeq(self.certificate_types, 1, 1)
- w.addVarSeq(self.certificate_authorities, 1, 2)
+ caLength = 0
+ #determine length
+ for ca_dn in self.certificate_authorities:
+ caLength += len(ca_dn)+2
+ w.add(caLength, 2)
+ #add bytes
+ for ca_dn in self.certificate_authorities:
+ w.addVarSeq(ca_dn, 1, 2)
return HandshakeMsg.postWrite(self, w, trial)
class ServerKeyExchange(HandshakeMsg):
diff --git a/third_party/tlslite/tlslite/utils/ASN1Parser.py b/third_party/tlslite/tlslite/utils/ASN1Parser.py
index 16b50f2..c85c138 100644
--- a/third_party/tlslite/tlslite/utils/ASN1Parser.py
+++ b/third_party/tlslite/tlslite/utils/ASN1Parser.py
@@ -16,13 +16,16 @@ class ASN1Parser:
#Assuming this is a sequence...
def getChild(self, which):
+ return ASN1Parser(self.getChildBytes(which))
+
+ def getChildBytes(self, which):
p = Parser(self.value)
for x in range(which+1):
markIndex = p.index
p.get(1) #skip Type
length = self._getASN1Length(p)
p.getFixBytes(length)
- return ASN1Parser(p.bytes[markIndex : p.index])
+ return p.bytes[markIndex : p.index]
#Decode the ASN.1 DER length field
def _getASN1Length(self, p):