Index: third_party/tlslite/tlslite/x509certchain.py |
diff --git a/third_party/tlslite/tlslite/x509certchain.py b/third_party/tlslite/tlslite/x509certchain.py |
index 5db6d470b5e7109e8e3990de837934b61e9e3eb1..2a592b6d86318fbc10cf8c3527070d35a41df618 100644 |
--- a/third_party/tlslite/tlslite/x509certchain.py |
+++ b/third_party/tlslite/tlslite/x509certchain.py |
@@ -1,13 +1,18 @@ |
+# Author: Trevor Perrin |
+# See the LICENSE file for legal information regarding use of this file. |
+ |
"""Class representing an X.509 certificate chain.""" |
-from utils import cryptomath |
-from x509 import X509 |
+from .utils import cryptomath |
+from .utils.tackwrapper import * |
+from .utils.pem import * |
+from .x509 import X509 |
-class X509CertChain: |
+class X509CertChain(object): |
"""This class represents a chain of X.509 certificates. |
@type x509List: list |
- @ivar x509List: A list of L{tlslite.X509.X509} instances, |
+ @ivar x509List: A list of L{tlslite.x509.X509} instances, |
starting with the end-entity certificate and with every |
subsequent certificate certifying the previous. |
""" |
@@ -16,7 +21,7 @@ class X509CertChain: |
"""Create a new X509CertChain. |
@type x509List: list |
- @param x509List: A list of L{tlslite.X509.X509} instances, |
+ @param x509List: A list of L{tlslite.x509.X509} instances, |
starting with the end-entity certificate and with every |
subsequent certificate certifying the previous. |
""" |
@@ -25,65 +30,18 @@ class X509CertChain: |
else: |
self.x509List = [] |
- def parseChain(self, s): |
- """Parse a PEM-encoded X.509 certificate file chain file. |
+ def parsePemList(self, s): |
+ """Parse a string containing a sequence of PEM certs. |
- @type s: str |
- @param s: A PEM-encoded (eg: Base64) X.509 certificate file, with every |
- certificate wrapped within "-----BEGIN CERTIFICATE-----" and |
- "-----END CERTIFICATE-----" tags). Extraneous data outside such tags, |
- such as human readable representations, will be ignored. |
+ Raise a SyntaxError if input is malformed. |
""" |
- |
- class PEMIterator(object): |
- """Simple iterator over PEM-encoded certificates within a string. |
- |
- @type data: string |
- @ivar data: A string containing PEM-encoded (Base64) certificates, |
- with every certificate wrapped within "-----BEGIN CERTIFICATE-----" |
- and "-----END CERTIFICATE-----" tags). Extraneous data outside such |
- tags, such as human readable representations, will be ignored. |
- |
- @type index: integer |
- @ivar index: The current offset within data to begin iterating from. |
- """ |
- |
- _CERTIFICATE_HEADER = "-----BEGIN CERTIFICATE-----" |
- """The PEM encoding block header for X.509 certificates.""" |
- |
- _CERTIFICATE_FOOTER = "-----END CERTIFICATE-----" |
- """The PEM encoding block footer for X.509 certificates.""" |
- |
- def __init__(self, s): |
- self.data = s |
- self.index = 0 |
- |
- def __iter__(self): |
- return self |
- |
- def next(self): |
- """Iterates and returns the next L{tlslite.X509.X509} |
- certificate in data. |
- |
- @rtype tlslite.X509.X509 |
- """ |
- |
- self.index = self.data.find(self._CERTIFICATE_HEADER, |
- self.index) |
- if self.index == -1: |
- raise StopIteration |
- end = self.data.find(self._CERTIFICATE_FOOTER, self.index) |
- if end == -1: |
- raise StopIteration |
- |
- certStr = self.data[self.index+len(self._CERTIFICATE_HEADER) : |
- end] |
- self.index = end + len(self._CERTIFICATE_FOOTER) |
- bytes = cryptomath.base64ToBytes(certStr) |
- return X509().parseBinary(bytes) |
- |
- self.x509List = list(PEMIterator(s)) |
- return self |
+ x509List = [] |
+ bList = dePemList(s, "CERTIFICATE") |
+ for b in bList: |
+ x509 = X509() |
+ x509.parseBinary(b) |
+ x509List.append(x509) |
+ self.x509List = x509List |
def getNumCerts(self): |
"""Get the number of certificates in this chain. |
@@ -95,7 +53,7 @@ class X509CertChain: |
def getEndEntityPublicKey(self): |
"""Get the public key from the end-entity certificate. |
- @rtype: L{tlslite.utils.RSAKey.RSAKey} |
+ @rtype: L{tlslite.utils.rsakey.RSAKey} |
""" |
if self.getNumCerts() == 0: |
raise AssertionError() |
@@ -110,133 +68,24 @@ class X509CertChain: |
if self.getNumCerts() == 0: |
raise AssertionError() |
return self.x509List[0].getFingerprint() |
- |
- def getCommonName(self): |
- """Get the Subject's Common Name from the end-entity certificate. |
- |
- The cryptlib_py module must be installed in order to use this |
- function. |
- |
- @rtype: str or None |
- @return: The CN component of the certificate's subject DN, if |
- present. |
- """ |
- if self.getNumCerts() == 0: |
- raise AssertionError() |
- return self.x509List[0].getCommonName() |
- |
- def validate(self, x509TrustList): |
- """Check the validity of the certificate chain. |
- |
- This checks that every certificate in the chain validates with |
- the subsequent one, until some certificate validates with (or |
- is identical to) one of the passed-in root certificates. |
- |
- The cryptlib_py module must be installed in order to use this |
- function. |
- |
- @type x509TrustList: list of L{tlslite.X509.X509} |
- @param x509TrustList: A list of trusted root certificates. The |
- certificate chain must extend to one of these certificates to |
- be considered valid. |
- """ |
- |
- import cryptlib_py |
- c1 = None |
- c2 = None |
- lastC = None |
- rootC = None |
- |
- try: |
- rootFingerprints = [c.getFingerprint() for c in x509TrustList] |
- |
- #Check that every certificate in the chain validates with the |
- #next one |
- for cert1, cert2 in zip(self.x509List, self.x509List[1:]): |
- |
- #If we come upon a root certificate, we're done. |
- if cert1.getFingerprint() in rootFingerprints: |
- return True |
- |
- c1 = cryptlib_py.cryptImportCert(cert1.writeBytes(), |
- cryptlib_py.CRYPT_UNUSED) |
- c2 = cryptlib_py.cryptImportCert(cert2.writeBytes(), |
- cryptlib_py.CRYPT_UNUSED) |
- try: |
- cryptlib_py.cryptCheckCert(c1, c2) |
- except: |
- return False |
- cryptlib_py.cryptDestroyCert(c1) |
- c1 = None |
- cryptlib_py.cryptDestroyCert(c2) |
- c2 = None |
- |
- #If the last certificate is one of the root certificates, we're |
- #done. |
- if self.x509List[-1].getFingerprint() in rootFingerprints: |
+ |
+ def checkTack(self, tack): |
+ if self.x509List: |
+ tlsCert = TlsCertificate(self.x509List[0].bytes) |
+ if tlsCert.matches(tack): |
return True |
- |
- #Otherwise, find a root certificate that the last certificate |
- #chains to, and validate them. |
- lastC = cryptlib_py.cryptImportCert(self.x509List[-1].writeBytes(), |
- cryptlib_py.CRYPT_UNUSED) |
- for rootCert in x509TrustList: |
- rootC = cryptlib_py.cryptImportCert(rootCert.writeBytes(), |
- cryptlib_py.CRYPT_UNUSED) |
- if self._checkChaining(lastC, rootC): |
- try: |
- cryptlib_py.cryptCheckCert(lastC, rootC) |
- return True |
- except: |
- return False |
- return False |
- finally: |
- if not (c1 is None): |
- cryptlib_py.cryptDestroyCert(c1) |
- if not (c2 is None): |
- cryptlib_py.cryptDestroyCert(c2) |
- if not (lastC is None): |
- cryptlib_py.cryptDestroyCert(lastC) |
- if not (rootC is None): |
- cryptlib_py.cryptDestroyCert(rootC) |
- |
- |
- |
- def _checkChaining(self, lastC, rootC): |
- import cryptlib_py |
- import array |
- def compareNames(name): |
- try: |
- length = cryptlib_py.cryptGetAttributeString(lastC, name, None) |
- lastName = array.array('B', [0] * length) |
- cryptlib_py.cryptGetAttributeString(lastC, name, lastName) |
- lastName = lastName.tostring() |
- except cryptlib_py.CryptException, e: |
- if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: |
- lastName = None |
- try: |
- length = cryptlib_py.cryptGetAttributeString(rootC, name, None) |
- rootName = array.array('B', [0] * length) |
- cryptlib_py.cryptGetAttributeString(rootC, name, rootName) |
- rootName = rootName.tostring() |
- except cryptlib_py.CryptException, e: |
- if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: |
- rootName = None |
- |
- return lastName == rootName |
- |
- cryptlib_py.cryptSetAttribute(lastC, |
- cryptlib_py.CRYPT_CERTINFO_ISSUERNAME, |
- cryptlib_py.CRYPT_UNUSED) |
- |
- if not compareNames(cryptlib_py.CRYPT_CERTINFO_COUNTRYNAME): |
- return False |
- if not compareNames(cryptlib_py.CRYPT_CERTINFO_LOCALITYNAME): |
- return False |
- if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONNAME): |
- return False |
- if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONALUNITNAME): |
- return False |
- if not compareNames(cryptlib_py.CRYPT_CERTINFO_COMMONNAME): |
- return False |
- return True |
+ return False |
+ |
+ def getTackExt(self): |
+ """Get the TACK and/or Break Sigs from a TACK Cert in the chain.""" |
+ tackExt = None |
+ # Search list in backwards order |
+ for x509 in self.x509List[::-1]: |
+ tlsCert = TlsCertificate(x509.bytes) |
+ if tlsCert.tackExt: |
+ if tackExt: |
+ raise SyntaxError("Multiple TACK Extensions") |
+ else: |
+ tackExt = tlsCert.tackExt |
+ return tackExt |
+ |