Module cevast.analysis.modules.validation_clients.botan
This module contains an implementation of a certificate chain validation client for Botan.
The validation client can be both imported and used externally (as a standalone module) through the provided command-line interface.
Important
The validation client must be set up correctly before use. It is necessary to ensure, that TRUST_STORE_DIRECTORY
is set to the path to the local trust store.
When using the validation client externally, these prerequisites are always checked before validation is performed.
When the validation client is imported, it is necessary to do these checks manually (i.e., using the method is_setup_correctly()
).
Expand source code
#!/usr/bin/python3
"""
This module contains an implementation of a certificate chain validation client for Botan.
The validation client can be both imported and used externally (as a standalone module) through the provided
command-line interface.
..Important::
The validation client must be set up correctly before use. It is necessary to ensure, that `TRUST_STORE_DIRECTORY` is set to the path to the local trust store.
When using the validation client externally, these prerequisites are always checked before validation is performed.
When the validation client is imported, it is necessary to do these checks manually (i.e., using the method `is_setup_correctly()`).
"""
import argparse
import datetime
import contextlib
import io
import os
import botan2 as botan
# noinspection PyBroadException
class Botan:
"""
A class for certificate chain validation client utilizing Botan.
Special error codes:
-1: any error / exception not related to the certificate chain validation (algorithm) itself
"""
TRUST_STORE_DIRECTORY = "/etc/pki/ca-trust/extracted/pem/"
@staticmethod
def verify(chain, reference_time=None, crls=None, **kwargs):
"""
Validates a certificate chain.
`chain` is a list of paths to certificates forming a chain.
`reference_time` is a reference time of validation in seconds since the epoch.
`crls` is a list of paths to CRLs.
`kwargs` are other, unexpected arguments.
The returned result is a list containing a single error code returned by Botan.
"""
with contextlib.redirect_stderr(io.StringIO()):
chain = list(chain)
try:
server = botan.X509Cert(**{"filename": chain[0]})
intermediates = [botan.X509Cert(**{"filename": i}) for i in chain[1:]] if len(chain) > 1 else None
result = int(server.verify(intermediates=intermediates,
trusted_path=Botan.TRUST_STORE_DIRECTORY,
reference_time=reference_time if reference_time else 0,
crls=[botan.X509CRL(**{"filename": crl}) for crl in crls] if crls else None))
except Exception:
result = -1
return [result]
@staticmethod
def is_setup_correctly():
"""
Verifies that the validation client is set up correctly. (trust store exists)
"""
is_setup_correctly = True
if not os.path.isdir(Botan.TRUST_STORE_DIRECTORY):
is_setup_correctly = False
return is_setup_correctly
if __name__ == "__main__":
argument_parser = argparse.ArgumentParser(description="chain format: ENDPOINT [INTERMEDIATE ...] [CA]")
argument_parser.add_argument("-r", type=lambda s: int(datetime.datetime.strptime(s, "%Y-%m-%d").timestamp()),
required=False, dest="reference_date_as_time", metavar="DATE",
help="reference date in format YYYY-MM-DD (at 00:00:00)")
argument_parser.add_argument("-t", type=int, required=False, dest="reference_time", metavar="N",
help="reference time in seconds since the epoch (surpassing reference date)")
argument_parser.add_argument("--crl", type=str, action="append", required=False, dest="crls", metavar="FILE",
help="certificate revocation list (can be used multiple times)")
argument_parser.add_argument("CERTIFICATE", type=str, nargs="+")
if Botan.is_setup_correctly():
args = argument_parser.parse_args()
print(Botan.verify(args.CERTIFICATE, reference_time=args.reference_time if args.reference_time is not None else args.reference_date_as_time, crls=args.crls))
else:
print("Client is not set up correctly")
Classes
class Botan
-
A class for certificate chain validation client utilizing Botan.
Special error codes:
-1: any error / exception not related to the certificate chain validation (algorithm) itself
Expand source code
class Botan: """ A class for certificate chain validation client utilizing Botan. Special error codes: -1: any error / exception not related to the certificate chain validation (algorithm) itself """ TRUST_STORE_DIRECTORY = "/etc/pki/ca-trust/extracted/pem/" @staticmethod def verify(chain, reference_time=None, crls=None, **kwargs): """ Validates a certificate chain. `chain` is a list of paths to certificates forming a chain. `reference_time` is a reference time of validation in seconds since the epoch. `crls` is a list of paths to CRLs. `kwargs` are other, unexpected arguments. The returned result is a list containing a single error code returned by Botan. """ with contextlib.redirect_stderr(io.StringIO()): chain = list(chain) try: server = botan.X509Cert(**{"filename": chain[0]}) intermediates = [botan.X509Cert(**{"filename": i}) for i in chain[1:]] if len(chain) > 1 else None result = int(server.verify(intermediates=intermediates, trusted_path=Botan.TRUST_STORE_DIRECTORY, reference_time=reference_time if reference_time else 0, crls=[botan.X509CRL(**{"filename": crl}) for crl in crls] if crls else None)) except Exception: result = -1 return [result] @staticmethod def is_setup_correctly(): """ Verifies that the validation client is set up correctly. (trust store exists) """ is_setup_correctly = True if not os.path.isdir(Botan.TRUST_STORE_DIRECTORY): is_setup_correctly = False return is_setup_correctly
Class variables
var TRUST_STORE_DIRECTORY
Static methods
def is_setup_correctly()
-
Verifies that the validation client is set up correctly. (trust store exists)
Expand source code
@staticmethod def is_setup_correctly(): """ Verifies that the validation client is set up correctly. (trust store exists) """ is_setup_correctly = True if not os.path.isdir(Botan.TRUST_STORE_DIRECTORY): is_setup_correctly = False return is_setup_correctly
def verify(chain, reference_time=None, crls=None, **kwargs)
-
Validates a certificate chain.
chain
is a list of paths to certificates forming a chain.reference_time
is a reference time of validation in seconds since the epoch.crls
is a list of paths to CRLs.kwargs
are other, unexpected arguments.The returned result is a list containing a single error code returned by Botan.
Expand source code
@staticmethod def verify(chain, reference_time=None, crls=None, **kwargs): """ Validates a certificate chain. `chain` is a list of paths to certificates forming a chain. `reference_time` is a reference time of validation in seconds since the epoch. `crls` is a list of paths to CRLs. `kwargs` are other, unexpected arguments. The returned result is a list containing a single error code returned by Botan. """ with contextlib.redirect_stderr(io.StringIO()): chain = list(chain) try: server = botan.X509Cert(**{"filename": chain[0]}) intermediates = [botan.X509Cert(**{"filename": i}) for i in chain[1:]] if len(chain) > 1 else None result = int(server.verify(intermediates=intermediates, trusted_path=Botan.TRUST_STORE_DIRECTORY, reference_time=reference_time if reference_time else 0, crls=[botan.X509CRL(**{"filename": crl}) for crl in crls] if crls else None)) except Exception: result = -1 return [result]