File size: 6,822 Bytes
2a4ddb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f90cf6e
d549d68
f1b171e
 
 
 
 
 
2a4ddb8
 
f90cf6e
2a4ddb8
 
 
 
 
 
 
 
 
 
 
 
f1b171e
 
 
2a4ddb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1b171e
 
 
2a4ddb8
 
 
 
f1b171e
2a4ddb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1b171e
2a4ddb8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1b171e
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
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):
    common_name = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
    print(common_name)
    sans = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value.get_values_for_type(x509.DNSName)
    not_valid_after = get_date(str(cert.not_valid_after_utc))
    not_valid_before = get_date(str(cert.not_valid_before_utc))
    expiry = check_expiry(str(cert.not_valid_after_utc))
    key_data = get_key_data(public_key)
    signature_algorithm = cert.signature_algorithm_oid._name
    serial_number = f"{cert.serial_number} ({hex(cert.serial_number)})"
    gen_info = {
        "common_name": common_name,
        "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
    organization = cert.issuer.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)[0].value
    country = cert.issuer.get_attributes_for_oid(x509.NameOID.COUNTRY_NAME)[0].value
    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
    ocsp_url = authorityinfo[0].access_location.value
    ca_issuer_url = authorityinfo[1].access_location.value
    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)    
    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