| OLD | NEW |
| (Empty) |
| 1 """Class representing an X.509 certificate.""" | |
| 2 | |
| 3 from utils.ASN1Parser import ASN1Parser | |
| 4 from utils.cryptomath import * | |
| 5 from utils.keyfactory import _createPublicRSAKey | |
| 6 | |
| 7 | |
| 8 class X509: | |
| 9 """This class represents an X.509 certificate. | |
| 10 | |
| 11 @type bytes: L{array.array} of unsigned bytes | |
| 12 @ivar bytes: The DER-encoded ASN.1 certificate | |
| 13 | |
| 14 @type publicKey: L{tlslite.utils.RSAKey.RSAKey} | |
| 15 @ivar publicKey: The subject public key from the certificate. | |
| 16 | |
| 17 @type subject: L{array.array} of unsigned bytes | |
| 18 @ivar subject: The DER-encoded ASN.1 subject distinguished name. | |
| 19 """ | |
| 20 | |
| 21 def __init__(self): | |
| 22 self.bytes = createByteArraySequence([]) | |
| 23 self.publicKey = None | |
| 24 self.subject = None | |
| 25 | |
| 26 def parse(self, s): | |
| 27 """Parse a PEM-encoded X.509 certificate. | |
| 28 | |
| 29 @type s: str | |
| 30 @param s: A PEM-encoded X.509 certificate (i.e. a base64-encoded | |
| 31 certificate wrapped with "-----BEGIN CERTIFICATE-----" and | |
| 32 "-----END CERTIFICATE-----" tags). | |
| 33 """ | |
| 34 | |
| 35 start = s.find("-----BEGIN CERTIFICATE-----") | |
| 36 end = s.find("-----END CERTIFICATE-----") | |
| 37 if start == -1: | |
| 38 raise SyntaxError("Missing PEM prefix") | |
| 39 if end == -1: | |
| 40 raise SyntaxError("Missing PEM postfix") | |
| 41 s = s[start+len("-----BEGIN CERTIFICATE-----") : end] | |
| 42 | |
| 43 bytes = base64ToBytes(s) | |
| 44 self.parseBinary(bytes) | |
| 45 return self | |
| 46 | |
| 47 def parseBinary(self, bytes): | |
| 48 """Parse a DER-encoded X.509 certificate. | |
| 49 | |
| 50 @type bytes: str or L{array.array} of unsigned bytes | |
| 51 @param bytes: A DER-encoded X.509 certificate. | |
| 52 """ | |
| 53 | |
| 54 if isinstance(bytes, type("")): | |
| 55 bytes = stringToBytes(bytes) | |
| 56 | |
| 57 self.bytes = bytes | |
| 58 p = ASN1Parser(bytes) | |
| 59 | |
| 60 #Get the tbsCertificate | |
| 61 tbsCertificateP = p.getChild(0) | |
| 62 | |
| 63 #Is the optional version field present? | |
| 64 #This determines which index the key is at. | |
| 65 if tbsCertificateP.value[0]==0xA0: | |
| 66 subjectPublicKeyInfoIndex = 6 | |
| 67 else: | |
| 68 subjectPublicKeyInfoIndex = 5 | |
| 69 | |
| 70 #Get the subject | |
| 71 self.subject = tbsCertificateP.getChildBytes(\ | |
| 72 subjectPublicKeyInfoIndex - 1) | |
| 73 | |
| 74 #Get the subjectPublicKeyInfo | |
| 75 subjectPublicKeyInfoP = tbsCertificateP.getChild(\ | |
| 76 subjectPublicKeyInfoIndex) | |
| 77 | |
| 78 #Get the algorithm | |
| 79 algorithmP = subjectPublicKeyInfoP.getChild(0) | |
| 80 rsaOID = algorithmP.value | |
| 81 if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]: | |
| 82 raise SyntaxError("Unrecognized AlgorithmIdentifier") | |
| 83 | |
| 84 #Get the subjectPublicKey | |
| 85 subjectPublicKeyP = subjectPublicKeyInfoP.getChild(1) | |
| 86 | |
| 87 #Adjust for BIT STRING encapsulation | |
| 88 if (subjectPublicKeyP.value[0] !=0): | |
| 89 raise SyntaxError() | |
| 90 subjectPublicKeyP = ASN1Parser(subjectPublicKeyP.value[1:]) | |
| 91 | |
| 92 #Get the modulus and exponent | |
| 93 modulusP = subjectPublicKeyP.getChild(0) | |
| 94 publicExponentP = subjectPublicKeyP.getChild(1) | |
| 95 | |
| 96 #Decode them into numbers | |
| 97 n = bytesToNumber(modulusP.value) | |
| 98 e = bytesToNumber(publicExponentP.value) | |
| 99 | |
| 100 #Create a public key instance | |
| 101 self.publicKey = _createPublicRSAKey(n, e) | |
| 102 return self | |
| 103 | |
| 104 def getFingerprint(self): | |
| 105 """Get the hex-encoded fingerprint of this certificate. | |
| 106 | |
| 107 @rtype: str | |
| 108 @return: A hex-encoded fingerprint. | |
| 109 """ | |
| 110 return sha.sha(self.bytes).hexdigest() | |
| 111 | |
| 112 def getCommonName(self): | |
| 113 """Get the Subject's Common Name from the certificate. | |
| 114 | |
| 115 The cryptlib_py module must be installed in order to use this | |
| 116 function. | |
| 117 | |
| 118 @rtype: str or None | |
| 119 @return: The CN component of the certificate's subject DN, if | |
| 120 present. | |
| 121 """ | |
| 122 import cryptlib_py | |
| 123 import array | |
| 124 c = cryptlib_py.cryptImportCert(self.bytes, cryptlib_py.CRYPT_UNUSED) | |
| 125 name = cryptlib_py.CRYPT_CERTINFO_COMMONNAME | |
| 126 try: | |
| 127 try: | |
| 128 length = cryptlib_py.cryptGetAttributeString(c, name, None) | |
| 129 returnVal = array.array('B', [0] * length) | |
| 130 cryptlib_py.cryptGetAttributeString(c, name, returnVal) | |
| 131 returnVal = returnVal.tostring() | |
| 132 except cryptlib_py.CryptException, e: | |
| 133 if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: | |
| 134 returnVal = None | |
| 135 return returnVal | |
| 136 finally: | |
| 137 cryptlib_py.cryptDestroyCert(c) | |
| 138 | |
| 139 def writeBytes(self): | |
| 140 return self.bytes | |
| 141 | |
| 142 | |
| OLD | NEW |