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 |