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