157 lines
5.4 KiB
Python
157 lines
5.4 KiB
Python
from cryptography import x509
|
|
from cryptography.hazmat.primitives.asymmetric import padding
|
|
from datetime import datetime, UTC # type: ignore
|
|
from cryptography.x509.oid import NameOID
|
|
|
|
|
|
def verify_certificate(
|
|
cert_data, ca_chain_path, correct_organization="[Universität Bremen]"
|
|
) -> tuple[bool, str, list[str], str, str, str]:
|
|
"""
|
|
Extract and print details about the certificate.
|
|
|
|
:param certificate_path: Path to the certificate
|
|
"""
|
|
try:
|
|
|
|
cert = x509.load_pem_x509_certificate(cert_data)
|
|
|
|
for entry in ca_chain_path:
|
|
with open(entry, "rb") as cert_file:
|
|
ca_data = cert_file.read()
|
|
ca_cert = x509.load_pem_x509_certificate(ca_data)
|
|
ca_public_key = ca_cert.public_key()
|
|
|
|
ca_okay: bool = False
|
|
error_message: str = ""
|
|
# Verify the certificate's signature
|
|
try:
|
|
# This will raise an exception if the signature is invalid
|
|
ca_public_key.verify(
|
|
cert.signature,
|
|
cert.tbs_certificate_bytes, # Updated method to get TBS bytes
|
|
padding.PKCS1v15(),
|
|
cert.signature_hash_algorithm,
|
|
)
|
|
ca_okay = True
|
|
break
|
|
|
|
except Exception as sig_error:
|
|
ca_okay = False
|
|
error_message = f"Signature verification failed: {sig_error}"
|
|
|
|
except FileNotFoundError:
|
|
ca_okay = False
|
|
error_message = "Certificate or CA certificate file not found."
|
|
|
|
except Exception as e:
|
|
ca_okay = False
|
|
error_message = f"Error verifying certificate authenticity: {e}"
|
|
|
|
if ca_okay is False:
|
|
return (
|
|
False,
|
|
error_message,
|
|
[],
|
|
"",
|
|
"",
|
|
"",
|
|
)
|
|
|
|
print("Certificate Details:")
|
|
print(f"Subject: {cert.subject}")
|
|
print(f"Issuer: {cert.issuer}")
|
|
print(f"Serial Number: {cert.serial_number}")
|
|
print(f"Not Valid Before (UTC): {cert.not_valid_before_utc}")
|
|
print(f"Not Valid After (UTC): {cert.not_valid_after_utc}")
|
|
|
|
# Check if certificate is currently valid
|
|
current_time = datetime.now(UTC)
|
|
is_valid = (
|
|
current_time >= cert.not_valid_before_utc
|
|
and current_time <= cert.not_valid_after_utc
|
|
)
|
|
|
|
if is_valid is False:
|
|
return False, f"Currently Valid: {is_valid}", [], "", "", ""
|
|
|
|
email_found = None
|
|
name_found = None
|
|
surname_found = None
|
|
given_name_found = None
|
|
for attr in cert.subject:
|
|
if str(NameOID.ORGANIZATION_NAME).lower() == str(attr.oid).lower():
|
|
|
|
organization_okay: bool = False
|
|
|
|
for org_entries in correct_organization:
|
|
if str(attr.value).lower() == str(org_entries).lower():
|
|
organization_okay = True
|
|
|
|
if organization_okay is False:
|
|
return (
|
|
False,
|
|
f"Not issued from the correct organization: {str(attr.value)} vs. {str(correct_organization)}",
|
|
[],
|
|
"",
|
|
"",
|
|
"",
|
|
)
|
|
if str(NameOID.EMAIL_ADDRESS).lower() == str(attr.oid).lower():
|
|
email_found = str(attr.value)
|
|
|
|
if str(NameOID.COMMON_NAME).lower() == str(attr.oid).lower():
|
|
name_found = str(attr.value)
|
|
|
|
if str(NameOID.SURNAME).lower() == str(attr.oid).lower():
|
|
surname_found = str(attr.value)
|
|
|
|
if str(NameOID.GIVEN_NAME).lower() == str(attr.oid).lower():
|
|
given_name_found = str(attr.value)
|
|
|
|
san_ext = cert.extensions.get_extension_for_oid(
|
|
x509.OID_SUBJECT_ALTERNATIVE_NAME
|
|
)
|
|
san_emails = [
|
|
name.value for name in san_ext.value if isinstance(name, x509.RFC822Name)
|
|
]
|
|
|
|
if email_found is not None:
|
|
san_emails.append(email_found)
|
|
san_emails = list(set(san_emails))
|
|
|
|
if len(san_emails) == 0:
|
|
return False, "No emails found in certificate", [], "", "", ""
|
|
|
|
if name_found is None:
|
|
return False, "No common name found in certificate", [], "", "", ""
|
|
|
|
if (surname_found is None) and (given_name_found is None):
|
|
str_splited = name_found.split(" ")
|
|
if len(str_splited) > 2:
|
|
return False, "No surname found in certificate", [], "", "", ""
|
|
given_name_found = str_splited[0]
|
|
surname_found = str_splited[1]
|
|
|
|
if surname_found is None:
|
|
return False, "No surname found in certificate", [], "", "", ""
|
|
|
|
if given_name_found is None:
|
|
return False, "No given name found in certificate", [], "", "", ""
|
|
|
|
except Exception as e:
|
|
|
|
return False, f"Error extracting certificate details: {e}", [], "", "", ""
|
|
|
|
return True, "", san_emails, name_found, given_name_found, surname_found
|
|
|
|
|
|
if __name__ == "__main__":
|
|
certificate_path = "cert.pem"
|
|
ca_chain_path = "ca_chain.pem"
|
|
|
|
# Read the certificate file
|
|
with open(certificate_path, "rb") as cert_file:
|
|
cert_data = cert_file.read()
|
|
|
|
print(verify_certificate(cert_data=cert_data, ca_chain_path=ca_chain_path))
|