X.509 certificate.
| 29 | |
| 30 | |
| 31 | class Certificate: |
| 32 | """X.509 certificate.""" |
| 33 | |
| 34 | def __init__(self, cert: str) -> None: |
| 35 | with reraise_errors( |
| 36 | 'Invalid certificate: {0!r}', errors=(ValueError,) |
| 37 | ): |
| 38 | self._cert = load_pem_x509_certificate( |
| 39 | ensure_bytes(cert), backend=default_backend()) |
| 40 | |
| 41 | if not isinstance(self._cert.public_key(), rsa.RSAPublicKey): |
| 42 | raise ValueError("Non-RSA certificates are not supported.") |
| 43 | |
| 44 | def has_expired(self) -> bool: |
| 45 | """Check if the certificate has expired.""" |
| 46 | return datetime.datetime.now(datetime.timezone.utc) >= self._cert.not_valid_after_utc |
| 47 | |
| 48 | def get_pubkey(self) -> ( |
| 49 | DSAPublicKey | EllipticCurvePublicKey | Ed448PublicKey | Ed25519PublicKey | RSAPublicKey |
| 50 | ): |
| 51 | return self._cert.public_key() |
| 52 | |
| 53 | def get_serial_number(self) -> int: |
| 54 | """Return the serial number in the certificate.""" |
| 55 | return self._cert.serial_number |
| 56 | |
| 57 | def get_issuer(self) -> str: |
| 58 | """Return issuer (CA) as a string.""" |
| 59 | return ' '.join(x.value for x in self._cert.issuer) |
| 60 | |
| 61 | def get_id(self) -> str: |
| 62 | """Serial number/issuer pair uniquely identifies a certificate.""" |
| 63 | return f'{self.get_issuer()} {self.get_serial_number()}' |
| 64 | |
| 65 | def verify(self, data: bytes, signature: bytes, digest: HashAlgorithm | Prehashed) -> None: |
| 66 | """Verify signature for string containing data.""" |
| 67 | with reraise_errors('Bad signature: {0!r}'): |
| 68 | |
| 69 | pad = padding.PSS( |
| 70 | mgf=padding.MGF1(digest), |
| 71 | salt_length=padding.PSS.MAX_LENGTH) |
| 72 | |
| 73 | self.get_pubkey().verify(signature, ensure_bytes(data), pad, digest) |
| 74 | |
| 75 | |
| 76 | class CertStore: |
no outgoing calls