1# Authors:
2#   Trevor Perrin
3#   Google - parsing subject field
4#
5# See the LICENSE file for legal information regarding use of this file.
6
7"""Class representing an X.509 certificate."""
8
9from .utils.asn1parser import ASN1Parser
10from .utils.cryptomath import *
11from .utils.keyfactory import _createPublicRSAKey
12from .utils.pem import *
13
14
15class X509(object):
16    """This class represents an X.509 certificate.
17
18    @type bytes: L{bytearray} of unsigned bytes
19    @ivar bytes: The DER-encoded ASN.1 certificate
20
21    @type publicKey: L{tlslite.utils.rsakey.RSAKey}
22    @ivar publicKey: The subject public key from the certificate.
23
24    @type subject: L{bytearray} of unsigned bytes
25    @ivar subject: The DER-encoded ASN.1 subject distinguished name.
26    """
27
28    def __init__(self):
29        self.bytes = bytearray(0)
30        self.publicKey = None
31        self.subject = None
32
33    def parse(self, s):
34        """Parse a PEM-encoded X.509 certificate.
35
36        @type s: str
37        @param s: A PEM-encoded X.509 certificate (i.e. a base64-encoded
38        certificate wrapped with "-----BEGIN CERTIFICATE-----" and
39        "-----END CERTIFICATE-----" tags).
40        """
41
42        bytes = dePem(s, "CERTIFICATE")
43        self.parseBinary(bytes)
44        return self
45
46    def parseBinary(self, bytes):
47        """Parse a DER-encoded X.509 certificate.
48
49        @type bytes: str or L{bytearray} of unsigned bytes
50        @param bytes: A DER-encoded X.509 certificate.
51        """
52
53        self.bytes = bytearray(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 subject
67        self.subject = tbsCertificateP.getChildBytes(\
68                           subjectPublicKeyInfoIndex - 1)
69
70        #Get the subjectPublicKeyInfo
71        subjectPublicKeyInfoP = tbsCertificateP.getChild(\
72                                    subjectPublicKeyInfoIndex)
73
74        #Get the algorithm
75        algorithmP = subjectPublicKeyInfoP.getChild(0)
76        rsaOID = algorithmP.value
77        if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
78            raise SyntaxError("Unrecognized AlgorithmIdentifier")
79
80        #Get the subjectPublicKey
81        subjectPublicKeyP = subjectPublicKeyInfoP.getChild(1)
82
83        #Adjust for BIT STRING encapsulation
84        if (subjectPublicKeyP.value[0] !=0):
85            raise SyntaxError()
86        subjectPublicKeyP = ASN1Parser(subjectPublicKeyP.value[1:])
87
88        #Get the modulus and exponent
89        modulusP = subjectPublicKeyP.getChild(0)
90        publicExponentP = subjectPublicKeyP.getChild(1)
91
92        #Decode them into numbers
93        n = bytesToNumber(modulusP.value)
94        e = bytesToNumber(publicExponentP.value)
95
96        #Create a public key instance
97        self.publicKey = _createPublicRSAKey(n, e)
98
99    def getFingerprint(self):
100        """Get the hex-encoded fingerprint of this certificate.
101
102        @rtype: str
103        @return: A hex-encoded fingerprint.
104        """
105        return b2a_hex(SHA1(self.bytes))
106
107    def writeBytes(self):
108        return self.bytes
109
110
111