class HCSIPacket(six.with_metaclass(_Geotag_metaclass, PPI_Element)): def post_build(self, p, pay): if self.geotag_len is None: sl_g = struct.pack('<H', len(p)) p = p[:2] + sl_g + p[4:] p += pay return p
class _GenericHMAC(six.with_metaclass(_GenericHMACMetaclass, object)): def __init__(self, key=None): if key is None: self.key = b"" else: self.key = bytes_encode(key) def digest(self, tbd): if self.key is None: raise HMACError tbd = bytes_encode(tbd) return hmac.new(self.key, tbd, self.hash_alg.hash_cls).digest() def digest_sslv3(self, tbd): if self.key is None: raise HMACError h = self.hash_alg() if h.name == "SHA": pad1 = _SSLv3_PAD1_SHA1 pad2 = _SSLv3_PAD2_SHA1 elif h.name == "MD5": pad1 = _SSLv3_PAD1_MD5 pad2 = _SSLv3_PAD2_MD5 else: raise HMACError("Provided hash does not work with SSLv3.") return h.digest(self.key + pad2 + h.digest(self.key + pad1 + tbd))
class PubKey(six.with_metaclass(_PubKeyFactory, object)): """ Parent class for both PubKeyRSA and PubKeyECDSA. Provides a common verifyCert() method. """ def verifyCert(self, cert): """ Verifies either a Cert or an X509_Cert. """ tbsCert = cert.tbsCertificate sigAlg = tbsCert.signature h = hash_by_oid[sigAlg.algorithm.val] sigVal = raw(cert.signatureValue) return self.verify(raw(tbsCert), sigVal, h=h, t='pkcs')
class _GenericCipherSuite( six.with_metaclass(_GenericCipherSuiteMetaclass, object)): # noqa: E501 def __init__(self, tls_version=0x0303): """ Most of the attributes are fixed and have already been set by the metaclass, but we still have to provide tls_version differentiation. For now, the key_block_len remains the only application if this. Indeed for TLS 1.1+, when using a block cipher, there are no implicit IVs derived from the master secret. Note that an overlong key_block_len would not affect the secret generation (the trailing bytes would simply be discarded), but we still provide this for completeness. """ super(_GenericCipherSuite, self).__init__() if tls_version <= 0x301: self.key_block_len = self._key_block_len_v1_0
class PrivKey(six.with_metaclass(_PrivKeyFactory, object)): """ Parent class for both PrivKeyRSA and PrivKeyECDSA. Provides common signTBSCert() and resignCert() methods. """ def signTBSCert(self, tbsCert, h="sha256"): """ Note that this will always copy the signature field from the tbsCertificate into the signatureAlgorithm field of the result, regardless of the coherence between its contents (which might indicate ecdsa-with-SHA512) and the result (e.g. RSA signing MD2). There is a small inheritance trick for the computation of sigVal below: in order to use a sign() method which would apply to both PrivKeyRSA and PrivKeyECDSA, the sign() methods of the subclasses accept any argument, be it from the RSA or ECDSA world, and then they keep the ones they're interested in. Here, t will be passed eventually to pkcs1._DecryptAndSignRSA.sign(). """ sigAlg = tbsCert.signature h = h or hash_by_oid[sigAlg.algorithm.val] sigVal = self.sign(raw(tbsCert), h=h, t='pkcs') c = X509_Cert() c.tbsCertificate = tbsCert c.signatureAlgorithm = sigAlg c.signatureValue = _Raw_ASN1_BIT_STRING(sigVal, readable=True) return c def resignCert(self, cert): """ Rewrite the signature of either a Cert or an X509_Cert. """ return self.signTBSCert(cert.tbsCertificate, h=None) def verifyCert(self, cert): """ Verifies either a Cert or an X509_Cert. """ tbsCert = cert.tbsCertificate sigAlg = tbsCert.signature h = hash_by_oid[sigAlg.algorithm.val] sigVal = raw(cert.signatureValue) return self.verify(raw(tbsCert), sigVal, h=h, t='pkcs')
class _StreamCipher(six.with_metaclass(_StreamCipherMetaclass, object)): type = "stream" def __init__(self, key=None): """ Note that we have to keep the encryption/decryption state in unique encryptor and decryptor objects. This differs from _BlockCipher. In order to do connection state snapshots, we need to be able to recreate past cipher contexts. This is why we feed _enc_updated_with and _dec_updated_with every time encrypt() or decrypt() is called. """ self.ready = {"key": True} if key is None: self.ready["key"] = False if hasattr(self, "expanded_key_len"): tmp_len = self.expanded_key_len else: tmp_len = self.key_len key = b"\0" * tmp_len # we use super() in order to avoid any deadlock with __setattr__ super(_StreamCipher, self).__setattr__("key", key) self._cipher = Cipher(self.pc_cls(key), mode=None, backend=default_backend()) self.encryptor = self._cipher.encryptor() self.decryptor = self._cipher.decryptor() self._enc_updated_with = b"" self._dec_updated_with = b"" def __setattr__(self, name, val): """ We have to keep the encryptor/decryptor for a long time, however they have to be updated every time the key is changed. """ if name == "key": if self._cipher is not None: self._cipher.algorithm.key = val self.encryptor = self._cipher.encryptor() self.decryptor = self._cipher.decryptor() self.ready["key"] = True super(_StreamCipher, self).__setattr__(name, val) def encrypt(self, data): if False in six.itervalues(self.ready): raise CipherError(data) self._enc_updated_with += data return self.encryptor.update(data) def decrypt(self, data): if False in six.itervalues(self.ready): raise CipherError(data) self._dec_updated_with += data return self.decryptor.update(data) def snapshot(self): c = self.__class__(self.key) c.ready = self.ready.copy() c.encryptor.update(self._enc_updated_with) c.decryptor.update(self._dec_updated_with) c._enc_updated_with = self._enc_updated_with c._dec_updated_with = self._dec_updated_with return c
class _FFDHParams(six.with_metaclass(_FFDHParamsMetaclass)): pass
class _BlockCipher(six.with_metaclass(_BlockCipherMetaclass, object)): type = "block" def __init__(self, key=None, iv=None): self.ready = {"key": True, "iv": True} if key is None: self.ready["key"] = False if hasattr(self, "expanded_key_len"): key_len = self.expanded_key_len else: key_len = self.key_len key = b"\0" * key_len if not iv: self.ready["iv"] = False iv = b"\0" * self.block_size # we use super() in order to avoid any deadlock with __setattr__ super(_BlockCipher, self).__setattr__("key", key) super(_BlockCipher, self).__setattr__("iv", iv) self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(iv), backend=backend) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: self._cipher.algorithm.key = val self.ready["key"] = True elif name == "iv": if self._cipher is not None: self._cipher.mode._initialization_vector = val self.ready["iv"] = True super(_BlockCipher, self).__setattr__(name, val) def encrypt(self, data): """ Encrypt the data. Also, update the cipher iv. This is needed for SSLv3 and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.post_build(). """ if False in six.itervalues(self.ready): raise CipherError(data) encryptor = self._cipher.encryptor() tmp = encryptor.update(data) + encryptor.finalize() self.iv = tmp[-self.block_size:] return tmp def decrypt(self, data): """ Decrypt the data. Also, update the cipher iv. This is needed for SSLv3 and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.pre_dissect(). If we lack the key, we raise a CipherError which contains the input. """ if False in six.itervalues(self.ready): raise CipherError(data) decryptor = self._cipher.decryptor() tmp = decryptor.update(data) + decryptor.finalize() self.iv = data[-self.block_size:] return tmp def snapshot(self): c = self.__class__(self.key, self.iv) c.ready = self.ready.copy() return c
class _GenericKX(six.with_metaclass(_GenericKXMetaclass)): pass
class _GenericHash(six.with_metaclass(_GenericHashMetaclass, object)): def digest(self, tbd): return self.hash_cls(tbd).digest()
class _AEADCipher(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") tests correspond to the legacy API of the crypto library. With cryptography v2.0, both CCM and GCM should follow the else case. Note that the "fixed_iv" in TLS RFCs is called "salt" in the AEAD RFC 5116. """ type = "aead" fixed_iv_len = 4 nonce_explicit_len = 8 def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings, whereas the internal # noqa: E501 'nonce_explicit' is an integer (it is simpler for incrementation). !! The whole 'nonce' may be called IV in certain RFCs. """ self.ready = {"key": True, "fixed_iv": True, "nonce_explicit": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len if nonce_explicit is None: self.ready["nonce_explicit"] = False nonce_explicit = 0 if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher, self).__setattr__("key", key) super(_AEADCipher, self).__setattr__("fixed_iv", fixed_iv) super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit) if hasattr(self, "pc_cls"): if isinstance(self.pc_cls, AESCCM): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(self._get_nonce()), backend=default_backend(), tag_length=self.tag_len) else: self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(self._get_nonce()), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True elif name == "nonce_explicit": if isinstance(val, str): val = pkcs_os2ip(val) self.ready["nonce_explicit"] = True super(_AEADCipher, self).__setattr__(name, val) def _get_nonce(self): return (self.fixed_iv + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len)) def _update_nonce_explicit(self): """ Increment the explicit nonce while avoiding any overflow. """ ne = self.nonce_explicit + 1 self.nonce_explicit = ne % 2**(self.nonce_explicit_len * 8) def auth_encrypt(self, P, A, seq_num=None): """ Encrypt the data then prepend the explicit part of the nonce. The authentication tag is directly appended with the most recent crypto API. Additional data may be authenticated without encryption (as A). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = None encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: res = self._cipher.encrypt(self._get_nonce(), P, A) nonce_explicit = pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) self._update_nonce_explicit() return nonce_explicit + res def auth_decrypt(self, A, C, seq_num=None, add_length=True): """ Decrypt the data and authenticate the associated data (i.e. A). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. Note that we add the TLSCiphertext length to A although we're supposed to add the TLSCompressed length. Fortunately, they are the same, but the specifications actually messed up here. :'( The 'add_length' switch should always be True for TLS, but we provide it anyway (mostly for test cases, hum). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len], C[self.nonce_explicit_len:-self.tag_len], C[-self.tag_len:]) if False in six.itervalues(self.ready): raise CipherError(nonce_explicit_str, C, mac) self.nonce_explicit = pkcs_os2ip(nonce_explicit_str) if add_length: A += struct.pack("!H", len(C)) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(nonce_explicit_str, P, mac) else: try: P = self._cipher.decrypt(self._get_nonce(), C + mac, A) except InvalidTag: raise AEADTagError(nonce_explicit_str, "<unauthenticated data>", mac) return nonce_explicit_str, P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv, self.nonce_explicit) c.ready = self.ready.copy() return c
class _AEADCipher_TLS13(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") enable support for the legacy implementation of GCM in the cryptography library. They should not be used, and might eventually be removed, with cryptography v2.0. XXX """ type = "aead" def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings. This IV never changes: it is either the client_write_IV or server_write_IV. Note that 'nonce_explicit' is never used. It is only a safeguard for a call in session.py to the TLS 1.2/ChaCha20Poly1305 case (see RFC 7905). """ self.ready = {"key": True, "fixed_iv": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher_TLS13, self).__setattr__("key", key) super(_AEADCipher_TLS13, self).__setattr__("fixed_iv", fixed_iv) if hasattr(self, "pc_cls"): if isinstance(self.pc_cls, AESCCM): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(fixed_iv), backend=default_backend(), tag_length=self.tag_len) else: self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(fixed_iv), backend=default_backend()) else: if self.cipher_cls == ChaCha20Poly1305: # ChaCha20Poly1305 doesn't have a tag_length argument... self._cipher = self.cipher_cls(key) else: self._cipher = self.cipher_cls(key, tag_length=self.tag_len) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True super(_AEADCipher_TLS13, self).__setattr__(name, val) def _get_nonce(self, seq_num): padlen = self.fixed_iv_len - len(seq_num) padded_seq_num = b"\x00" * padlen + seq_num return strxor(padded_seq_num, self.fixed_iv) def auth_encrypt(self, P, A, seq_num): """ Encrypt the data, and append the computed authentication code. The additional data for TLS 1.3 is the record header. Note that the cipher's authentication tag must be None when encrypting. """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._tag = None self._cipher.mode._initialization_vector = self._get_nonce(seq_num) encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): res = self._cipher.encrypt(self._get_nonce(seq_num), P, A) else: res = self._cipher.encrypt(self._get_nonce(seq_num), P, A) return res def auth_decrypt(self, A, C, seq_num): """ Decrypt the data and verify the authentication code (in this order). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. """ C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): raise CipherError(C, mac) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce(seq_num) self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(P, mac) else: try: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) # noqa: E501 else: if (conf.crypto_valid_advanced and isinstance(self, Cipher_CHACHA20_POLY1305)): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) # noqa: E501 except InvalidTag: raise AEADTagError("<unauthenticated data>", mac) return P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv) c.ready = self.ready.copy() return c
class CRL(six.with_metaclass(_CRLMaker, object)): """ Wrapper for the X509_CRL from layers/x509.py. Use the 'x509CRL' attribute to access original object. """ def import_from_asn1pkt(self, crl): error_msg = "Unable to import CRL" self.x509CRL = crl tbsCertList = crl.tbsCertList self.tbsCertList = raw(tbsCertList) if tbsCertList.version: self.version = tbsCertList.version.val + 1 else: self.version = 1 self.sigAlg = tbsCertList.signature.algorithm.oidname self.issuer = tbsCertList.get_issuer() self.issuer_str = tbsCertList.get_issuer_str() self.issuer_hash = hash(self.issuer_str) self.lastUpdate_str = tbsCertList.this_update.pretty_time lastUpdate = tbsCertList.this_update.val if lastUpdate[-1] == "Z": lastUpdate = lastUpdate[:-1] try: self.lastUpdate = time.strptime(lastUpdate, "%y%m%d%H%M%S") except Exception: raise Exception(error_msg) self.lastUpdate_str_simple = time.strftime("%x", self.lastUpdate) self.nextUpdate = None self.nextUpdate_str_simple = None if tbsCertList.next_update: self.nextUpdate_str = tbsCertList.next_update.pretty_time nextUpdate = tbsCertList.next_update.val if nextUpdate[-1] == "Z": nextUpdate = nextUpdate[:-1] try: self.nextUpdate = time.strptime(nextUpdate, "%y%m%d%H%M%S") except Exception: raise Exception(error_msg) self.nextUpdate_str_simple = time.strftime("%x", self.nextUpdate) if tbsCertList.crlExtensions: for extension in tbsCertList.crlExtensions: if extension.extnID.oidname == "cRLNumber": self.number = extension.extnValue.cRLNumber.val revoked = [] if tbsCertList.revokedCertificates: for cert in tbsCertList.revokedCertificates: serial = cert.serialNumber.val date = cert.revocationDate.val if date[-1] == "Z": date = date[:-1] try: time.strptime(date, "%y%m%d%H%M%S") except Exception: raise Exception(error_msg) revoked.append((serial, date)) self.revoked_cert_serials = revoked self.signatureValue = raw(crl.signatureValue) self.signatureLen = len(self.signatureValue) def isIssuerCert(self, other): # This is exactly the same thing as in Cert method. if self.issuer_hash != other.subject_hash: return False return other.pubKey.verifyCert(self) def verify(self, anchors): # Return True iff the CRL is signed by one of the provided anchors. return any(self.isIssuerCert(a) for a in anchors) def show(self): print("Version: %d" % self.version) print("sigAlg: " + self.sigAlg) print("Issuer: " + self.issuer_str) print("lastUpdate: %s" % self.lastUpdate_str) print("nextUpdate: %s" % self.nextUpdate_str)
class Cert(six.with_metaclass(_CertMaker, object)): """ Wrapper for the X509_Cert from layers/x509.py. Use the 'x509Cert' attribute to access original object. """ def import_from_asn1pkt(self, cert): error_msg = "Unable to import certificate" self.x509Cert = cert tbsCert = cert.tbsCertificate self.tbsCertificate = tbsCert if tbsCert.version: self.version = tbsCert.version.val + 1 else: self.version = 1 self.serial = tbsCert.serialNumber.val self.sigAlg = tbsCert.signature.algorithm.oidname self.issuer = tbsCert.get_issuer() self.issuer_str = tbsCert.get_issuer_str() self.issuer_hash = hash(self.issuer_str) self.subject = tbsCert.get_subject() self.subject_str = tbsCert.get_subject_str() self.subject_hash = hash(self.subject_str) self.authorityKeyID = None self.notBefore_str = tbsCert.validity.not_before.pretty_time try: self.notBefore = tbsCert.validity.not_before.datetime.timetuple() except ValueError: raise Exception(error_msg) self.notBefore_str_simple = time.strftime("%x", self.notBefore) self.notAfter_str = tbsCert.validity.not_after.pretty_time try: self.notAfter = tbsCert.validity.not_after.datetime.timetuple() except ValueError: raise Exception(error_msg) self.notAfter_str_simple = time.strftime("%x", self.notAfter) self.pubKey = PubKey(raw(tbsCert.subjectPublicKeyInfo)) if tbsCert.extensions: for extn in tbsCert.extensions: if extn.extnID.oidname == "basicConstraints": self.cA = False if extn.extnValue.cA: self.cA = not (extn.extnValue.cA.val == 0) elif extn.extnID.oidname == "keyUsage": self.keyUsage = extn.extnValue.get_keyUsage() elif extn.extnID.oidname == "extKeyUsage": self.extKeyUsage = extn.extnValue.get_extendedKeyUsage() elif extn.extnID.oidname == "authorityKeyIdentifier": self.authorityKeyID = extn.extnValue.keyIdentifier.val self.signatureValue = raw(cert.signatureValue) self.signatureLen = len(self.signatureValue) def isIssuerCert(self, other): """ True if 'other' issued 'self', i.e.: - self.issuer == other.subject - self is signed by other """ if self.issuer_hash != other.subject_hash: return False return other.pubKey.verifyCert(self) def isSelfSigned(self): """ Return True if the certificate is self-signed: - issuer and subject are the same - the signature of the certificate is valid. """ if self.issuer_hash == self.subject_hash: return self.isIssuerCert(self) return False def encrypt(self, msg, t="pkcs", h="sha256", mgf=None, L=None): # no ECDSA *encryption* support, hence only RSA specific keywords here return self.pubKey.encrypt(msg, t=t, h=h, mgf=mgf, L=L) def verify(self, msg, sig, t="pkcs", h="sha256", mgf=None, L=None): return self.pubKey.verify(msg, sig, t=t, h=h, mgf=mgf, L=L) def remainingDays(self, now=None): """ Based on the value of notAfter field, returns the number of days the certificate will still be valid. The date used for the comparison is the current and local date, as returned by time.localtime(), except if 'now' argument is provided another one. 'now' argument can be given as either a time tuple or a string representing the date. Accepted format for the string version are: - '%b %d %H:%M:%S %Y %Z' e.g. 'Jan 30 07:38:59 2008 GMT' - '%m/%d/%y' e.g. '01/30/08' (less precise) If the certificate is no more valid at the date considered, then a negative value is returned representing the number of days since it has expired. The number of days is returned as a float to deal with the unlikely case of certificates that are still just valid. """ if now is None: now = time.localtime() elif isinstance(now, str): try: if '/' in now: now = time.strptime(now, '%m/%d/%y') else: now = time.strptime(now, '%b %d %H:%M:%S %Y %Z') except Exception: warning( "Bad time string provided, will use localtime() instead." ) # noqa: E501 now = time.localtime() now = time.mktime(now) nft = time.mktime(self.notAfter) diff = (nft - now) / (24. * 3600) return diff def isRevoked(self, crl_list): """ Given a list of trusted CRL (their signature has already been verified with trusted anchors), this function returns True if the certificate is marked as revoked by one of those CRL. Note that if the Certificate was on hold in a previous CRL and is now valid again in a new CRL and bot are in the list, it will be considered revoked: this is because _all_ CRLs are checked (not only the freshest) and revocation status is not handled. Also note that the check on the issuer is performed on the Authority Key Identifier if available in _both_ the CRL and the Cert. Otherwise, the issuers are simply compared. """ for c in crl_list: if (self.authorityKeyID is not None and c.authorityKeyID is not None and self.authorityKeyID == c.authorityKeyID): return self.serial in (x[0] for x in c.revoked_cert_serials) elif self.issuer == c.issuer: return self.serial in (x[0] for x in c.revoked_cert_serials) return False def export(self, filename, fmt="DER"): """ Export certificate in 'fmt' format (DER or PEM) to file 'filename' """ with open(filename, "wb") as f: if fmt == "DER": f.write(self.der) elif fmt == "PEM": f.write(self.pem) def show(self): print("Serial: %s" % self.serial) print("Issuer: " + self.issuer_str) print("Subject: " + self.subject_str) print("Validity: %s to %s" % (self.notBefore_str, self.notAfter_str)) def __repr__(self): return "[X.509 Cert. Subject:%s, Issuer:%s]" % ( self.subject_str, self.issuer_str) # noqa: E501