diff options
author | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-21 04:02:44 +0000 |
---|---|---|
committer | rsleevi@chromium.org <rsleevi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-21 04:02:44 +0000 |
commit | b3992377f4e52a205164d4da5dc7e465e749a57e (patch) | |
tree | 6f1b1f6216ffa5053edb6836be53d89475463a8f /third_party/tlslite | |
parent | bbf7e53f9a96ebd3a4f2835ea5ee561f03ef534e (diff) | |
download | chromium_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.chromium | 11 | ||||
-rw-r--r-- | third_party/tlslite/patches/ca_request.patch | 176 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/TLSConnection.py | 24 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/X509.py | 8 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/messages.py | 20 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/utils/ASN1Parser.py | 5 |
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): |