satcfdi.models.certificate_store   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Test Coverage

Coverage 91.89%

Importance

Changes 0
Metric Value
eloc 45
dl 0
loc 75
ccs 34
cts 37
cp 0.9189
rs 10
c 0
b 0
f 0
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
B CertificateStore.verify_certificate() 0 40 6
A CertificateStore.__init__() 0 3 1
A CertificateStore.create() 0 11 2
A CertificateStore.issuer_certificate() 0 2 1
1 1
import os
2 1
import zipfile
3 1
from collections.abc import Iterable
4 1
from datetime import datetime
5
6 1
from cryptography import x509
7 1
from cryptography.exceptions import InvalidSignature
8 1
from cryptography.hazmat.primitives.asymmetric import padding
9 1
from pytz import utc
10
11 1
current_dir = os.path.dirname(__file__)
12
13
14 1
class CertificateStore:
15 1
    def __init__(self, trusted_certificates: Iterable):
16 1
        self._trusted_certificates = {
17
            cert.subject.public_bytes(): cert for cert in trusted_certificates
18
        }
19
20 1
    def issuer_certificate(self, cert):
21 1
        return self._trusted_certificates[cert.issuer.public_bytes()]
22
23 1
    def verify_certificate(self, issued_cert, at: datetime):
24
        """Verifies issued_cert.
25
26
        Args:
27
            issued_cert: The issued certificate.
28
29
        Returns:
30
            True if certificate was issued by a trusted certificate
31
            :param issued_cert: issued certificate to validate
32
            :param at: date at witch to do the validation
33
        """
34 1
        if at.tzinfo:
35 1
            at = at.astimezone(tz=utc).replace(tzinfo=None)
36
37 1
        def validate_date(cert):
38 1
            if not cert.not_valid_before <= at <= cert.not_valid_after:
39
                raise ValueError("Date Not Valid")
40
41 1
        try:
42 1
            validate_date(issued_cert)
43 1
            signing_cert = self.issuer_certificate(issued_cert)
44 1
            validate_date(signing_cert)
45
46 1
            signing_cert.public_key().verify(
47
                signature=issued_cert.signature,
48
                data=issued_cert.tbs_certificate_bytes,
49
                padding=padding.PKCS1v15(),
50
                algorithm=issued_cert.signature_hash_algorithm
51
            )
52
53
            # Assume the parent certificates have been already validated, only checking dates
54 1
            while True:
55 1
                parent_cert = self.issuer_certificate(signing_cert)
56 1
                if parent_cert == signing_cert:
57 1
                    return True
58 1
                validate_date(parent_cert)
59 1
                signing_cert = parent_cert
60
61
        except (IndexError, InvalidSignature, ValueError) as ex:
62
            return False
63
64 1
    @classmethod
65 1
    def create(cls, certs_zip):
66
        """
67
        Creates a Certificate Store from the certificates in a zip file
68
        :param certs_zip:
69
        :return: CertificateStore
70
        """
71 1
        with zipfile.ZipFile(certs_zip, "r") as zf:
72 1
            return cls(
73
                trusted_certificates=
74
                (x509.load_der_x509_certificate(zf.read(fileinfo)) for fileinfo in zf.infolist())
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable fileinfo does not seem to be defined.
Loading history...
75
            )
76