File size: 7,483 Bytes
a2075a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import os
import subprocess
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.hazmat.primitives.asymmetric import ec, rsa
from datetime import datetime
import pytz

def get_date(date):
    date = datetime.fromisoformat(date)
    timezone = pytz.timezone('Asia/Kolkata')
    local_datetime = date.astimezone(timezone)
    formatted_date = local_datetime.strftime('%d %B, %Y %H:%M:%S %z')
    day = local_datetime.day
    ordinal_suffix = 'th' if 4 <= day <= 20 else {1: 'st', 2: 'nd', 3: 'rd'}.get(day % 10, 'th')
    formatted_date_with_suffix = formatted_date.replace(f"{day}", f"{day}{ordinal_suffix}")
    return formatted_date_with_suffix

def check_expiry(date):
    date = datetime.fromisoformat(date)
    timezone = pytz.timezone('Asia/Kolkata')
    current_date = datetime.now(timezone)
    days_left = (date - current_date).days
    if days_left > 0:
        return f"No ({days_left} days till expiration)"
    else:
        return f"Yes ({abs(days_left)} days since expired)"
    
def get_key_data(public_key):
    if isinstance(public_key, ec.EllipticCurvePublicKey):
        public_key_curve = public_key.curve.name
        public_key_size = public_key.curve.key_size
        data = {
            "type": f"ECDSA ({public_key_curve})",
            "size": f"{public_key_size} bits"
        }
    elif isinstance(public_key, rsa.RSAPublicKey):
        public_key_size = public_key.key_size
        data = {
            "type": "RSA",
            "size": f"{public_key_size} bits"
        }
    else:
        data = {
            "type": "Unknown",
            "size": "Unknown"
        }
    return data

def general_info(cert, public_key):
    subject = None
    sans = None
    not_valid_after = None
    not_valid_before = None
    expiry = None
    key_data = None
    signature_algorithm = None
    serial_number = None
    subject = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value if subject else None
    sans = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value.get_values_for_type(x509.DNSName) if sans else None
    not_valid_after = get_date(str(cert.not_valid_after_utc)) if not_valid_after else None
    not_valid_before = get_date(str(cert.not_valid_before_utc)) if not_valid_before else None
    expiry = check_expiry(str(cert.not_valid_after_utc)) if expiry else None
    key_data = get_key_data(public_key) if key_data else None
    signature_algorithm = cert.signature_algorithm_oid._name if signature_algorithm else None
    serial_number = f"{cert.serial_number} ({hex(cert.serial_number)})"
    gen_info = {
        "subject": subject,
        "sans": sans,
        "not_valid_after": not_valid_after,
        "not_valid_before": not_valid_before,
        "expiry": expiry,
        "key_data": key_data,
        "signature_algorithm": signature_algorithm,
        "serial_number": serial_number
    }
    return gen_info

def issuer_info(cert):
    issuer = None; organization = None; country = None
    issuer = cert.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value if issuer else None
    organization = cert.issuer.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)[0].value if organization else None
    country = cert.issuer.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)[0].value if country else None
    return {
        "issuer": issuer,
        "organization": organization,
        "country": country
    }

def extenstions_data(cert):
    authorityinfo = None; ocsp_url = None; ca_issuer_url = None; subject_alt_name = None
    if (tempdata1 := cert.extensions.get_extension_for_oid(x509.OID_AUTHORITY_KEY_IDENTIFIER).value.key_identifier):
        authorityKeyIdentifier = ':'.join(f'{b:02X}' for b in tempdata1)
    else:
        authorityKeyIdentifier = None
    if (subject := cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_KEY_IDENTIFIER).value.digest):
        subjectKeyIdentifier = ':'.join(f'{b:02X}' for b in subject)
    else:
        subjectKeyIdentifier = None
    if (key_usage := cert.extensions.get_extension_for_oid(x509.OID_KEY_USAGE).value):
        key_usage_info = list(vars(key_usage).items())
        key_usage_data =[]
        for item in key_usage_info:
            key_usage_data.append(f"{item[0][1:]} : {item[1]}")
        key_usage_data = key_usage_data
    else:
        key_usage_data = None
    if (ext_key_usage := cert.extensions.get_extension_for_oid(x509.OID_EXTENDED_KEY_USAGE).value):
        ext_key_usage_data = [oid._name for oid in ext_key_usage]
    else:
        ext_key_usage_data = None
    crl_distribution_points = []
    try:
        crl_extension = cert.extensions.get_extension_for_oid(x509.OID_CRL_DISTRIBUTION_POINTS)
        for distribution_point in crl_extension.value:
            # Extracting the full names (URIs)
            if distribution_point.full_name:
                uris = [name.value for name in distribution_point.full_name]
                crl_distribution_points.extend(uris)
    except x509.ExtensionNotFound:
        crl_distribution_points.append("No CRL Distribution Points extension")
    authorityinfo = cert.extensions.get_extension_for_oid(x509.OID_AUTHORITY_INFORMATION_ACCESS).value if authorityinfo else None
    ocsp_url = authorityinfo[0].access_location.value if ocsp_url else None
    ca_issuer_url = authorityinfo[1].access_location.value  if ca_issuer_url else None
    authority_info_data = {
        "ocsp_url": ocsp_url,
        "ca_issuer_url": ca_issuer_url
    }
    subject_alt_name = cert.extensions.get_extension_for_oid(x509.OID_SUBJECT_ALTERNATIVE_NAME).value.get_values_for_type(x509.DNSName) if subject_alt_name else None    
    return {
        "authorityKeyIdentifier": authorityKeyIdentifier,
        "subjectKeyIdentifier": subjectKeyIdentifier,
        "key_usage": key_usage_data,
        "extended_key_usage": ext_key_usage_data,
        "crl_distribution_points": crl_distribution_points,
        "authority_info": authority_info_data,
        "subject_alt_name": subject_alt_name
    }

def get_openssl_data(cert_file):
    result1 = subprocess.run(["openssl", "x509", "-in", cert_file, "-text", "-noout"], capture_output=True, text=True)
    result2 = subprocess.run(['openssl', 'asn1parse', '-in', cert_file], capture_output=True, text=True)
    data = {
        'raw_openssl_data': result1.stdout,
        'openssl_asn1parse_data': result2.stdout
    }
    return data

def decode_ssl_certificate(cert):
    subject = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
    with open(f'{subject}.pem', 'wb') as cert_file:
        cert_file.write(cert.public_bytes(Encoding.PEM))
    public_key = cert.public_key()
    general_info_data = general_info(cert, public_key)
    issuer_info_data = issuer_info(cert)
    extensions_data_data = extenstions_data(cert)
    raw_openssl_data = get_openssl_data(f'{subject}.pem')
    os.remove(f'{subject}.pem')
    data = {
        "general_info": general_info_data,
        "issuer_info": issuer_info_data,
        "extensions_data": extensions_data_data,
        "raw_openssl_data": raw_openssl_data
    }
    return data