blob: 0783f73627bc14c791a7a1674d0da43d041c5354 [file] [log] [blame]
#
# Copyright (C) 2023 Savoir-faire Linux Inc.
#
# Author: Xavier Jouslin de Noray <xavier.joulindenoray@savoirfairelinux.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Creates packaging targets for a distribution and architecture.
# This helps reduce the length of the top Makefile.
#
from typing import Optional, List, Tuple
from datetime import datetime
from OpenSSL import crypto
from certificate import Certificate
from abstactCertificate import AbstractCertificate
from utils import read, save, save_archive
class CertificateRevocationList(AbstractCertificate):
"""
A class representing a certificate revocation list.
"""
def __init__(self, key: Optional[crypto.PKey], cert: Optional[crypto.CRL], issuer: 'Certificate'):
self._cert = cert
self._key = key
self._issuer = issuer
@property
def cert(self) -> Tuple[crypto.PKey, crypto.CRL]:
"""
Get the certificate.
:return: A tuple containing the certificate and the key.
"""
return self._key, self._cert
@staticmethod
def create(issuer: 'Certificate', revoked: List[Tuple[int, datetime]]) -> 'CertificateRevocationList':
"""
Create a certificate revocation list.
:param issuer: The issuer of the certificate revocation list.
:param revoked: The list of revoked certificates.
:return: A Certificate object.
"""
crl = crypto.CRL()
crl.set_lastUpdate(datetime.utcnow().strftime('%Y%m%d%H%M%SZ').encode('ascii'))
for serial, date in revoked:
revoked_cert = crypto.Revoked()
revoked_cert.set_serial(str(serial).encode('ascii'))
revoked_cert.set_rev_date(date.strftime('%Y%m%d%H%M%SZ').encode('ascii'))
crl.add_revoked(revoked)
return CertificateRevocationList(None, crl, issuer).sign(issuer)
@staticmethod
def load(file_path: str, issuer: str) -> 'CertificateRevocationList':
"""
Load a certificate from a file.
:param file_path: The path to the certificate.
:return: A Certificate object.
"""
crl = crypto.load_crl(crypto.FILETYPE_PEM, read(f'{file_path}.crl', 'rb'))
issuer = crypto.load_certificate(crypto.FILETYPE_PEM, read(f'{issuer}.crt', 'rb'))
return CertificateRevocationList(None, crl, Certificate(None, issuer, None))
def revoke(self, subject: 'Certificate', reason: str = 'unspecified') -> 'CertificateRevocationList':
"""
Revoke a certificate.
:param subject: The certificate to revoke.
:param reason: The reason for revocation.
"""
if self._cert is None:
raise ValueError
revoked = crypto.Revoked()
revoked.set_serial(hex(subject.cert[1].get_serial_number())[2:].encode('ascii'))
revoked.set_reason(reason.encode('ascii'))
now = datetime.utcnow()
revoked.set_rev_date(now.strftime("%Y%m%d%H%M%SZ").encode('ascii'))
self._cert.add_revoked(revoked)
return CertificateRevocationList(None, self._cert, self._issuer).sign(self._issuer)
def sign(self, issuer: 'Certificate') -> 'CertificateRevocationList':
"""
Sign the certificate.
:param issuer: The issuer certificate.
"""
if self._cert is None:
raise ValueError
self._cert.sign(issuer.cert[1], issuer.cert[0], b'sha512')
return CertificateRevocationList(None, self._cert, self._issuer)
def save(self, file_path: str) -> None:
"""
Save the certificate to a file.
:param file_path: The path to the file.
"""
if self._cert is None:
raise ValueError
save(f'{file_path}.crl', crypto.dump_crl(crypto.FILETYPE_PEM, self._cert), 'wb')
def save_archive(self, path_2_file: str) -> None:
"""
Save the CRL to a archive file.
:param path_2_file: The path to the file.
"""
if self._cert is None:
raise ValueError
save_archive(path_2_file, crypto.dump_crl(crypto.FILETYPE_PEM, self._cert), 'wb')