mirror of
				https://gitlab.sectorq.eu/jaydee/omv_backup.git
				synced 2025-10-31 10:31:11 +01:00 
			
		
		
		
	added v3
This commit is contained in:
		| @@ -0,0 +1,63 @@ | ||||
| # This file is dual licensed under the terms of the Apache License, Version | ||||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||||
| # for complete details. | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| from cryptography.hazmat.primitives._serialization import ( | ||||
|     BestAvailableEncryption, | ||||
|     Encoding, | ||||
|     KeySerializationEncryption, | ||||
|     NoEncryption, | ||||
|     ParameterFormat, | ||||
|     PrivateFormat, | ||||
|     PublicFormat, | ||||
|     _KeySerializationEncryption, | ||||
| ) | ||||
| from cryptography.hazmat.primitives.serialization.base import ( | ||||
|     load_der_parameters, | ||||
|     load_der_private_key, | ||||
|     load_der_public_key, | ||||
|     load_pem_parameters, | ||||
|     load_pem_private_key, | ||||
|     load_pem_public_key, | ||||
| ) | ||||
| from cryptography.hazmat.primitives.serialization.ssh import ( | ||||
|     SSHCertificate, | ||||
|     SSHCertificateBuilder, | ||||
|     SSHCertificateType, | ||||
|     SSHCertPrivateKeyTypes, | ||||
|     SSHCertPublicKeyTypes, | ||||
|     SSHPrivateKeyTypes, | ||||
|     SSHPublicKeyTypes, | ||||
|     load_ssh_private_key, | ||||
|     load_ssh_public_identity, | ||||
|     load_ssh_public_key, | ||||
| ) | ||||
|  | ||||
| __all__ = [ | ||||
|     "BestAvailableEncryption", | ||||
|     "Encoding", | ||||
|     "KeySerializationEncryption", | ||||
|     "NoEncryption", | ||||
|     "ParameterFormat", | ||||
|     "PrivateFormat", | ||||
|     "PublicFormat", | ||||
|     "SSHCertPrivateKeyTypes", | ||||
|     "SSHCertPublicKeyTypes", | ||||
|     "SSHCertificate", | ||||
|     "SSHCertificateBuilder", | ||||
|     "SSHCertificateType", | ||||
|     "SSHPrivateKeyTypes", | ||||
|     "SSHPublicKeyTypes", | ||||
|     "_KeySerializationEncryption", | ||||
|     "load_der_parameters", | ||||
|     "load_der_private_key", | ||||
|     "load_der_public_key", | ||||
|     "load_pem_parameters", | ||||
|     "load_pem_private_key", | ||||
|     "load_pem_public_key", | ||||
|     "load_ssh_private_key", | ||||
|     "load_ssh_public_identity", | ||||
|     "load_ssh_public_key", | ||||
| ] | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # This file is dual licensed under the terms of the Apache License, Version | ||||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||||
| # for complete details. | ||||
|  | ||||
| from cryptography.hazmat.bindings._rust import openssl as rust_openssl | ||||
|  | ||||
| load_pem_private_key = rust_openssl.keys.load_pem_private_key | ||||
| load_der_private_key = rust_openssl.keys.load_der_private_key | ||||
|  | ||||
| load_pem_public_key = rust_openssl.keys.load_pem_public_key | ||||
| load_der_public_key = rust_openssl.keys.load_der_public_key | ||||
|  | ||||
| load_pem_parameters = rust_openssl.dh.from_pem_parameters | ||||
| load_der_parameters = rust_openssl.dh.from_der_parameters | ||||
| @@ -0,0 +1,156 @@ | ||||
| # This file is dual licensed under the terms of the Apache License, Version | ||||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||||
| # for complete details. | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| import typing | ||||
|  | ||||
| from cryptography import x509 | ||||
| from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12 | ||||
| from cryptography.hazmat.primitives import serialization | ||||
| from cryptography.hazmat.primitives._serialization import PBES as PBES | ||||
| from cryptography.hazmat.primitives.asymmetric import ( | ||||
|     dsa, | ||||
|     ec, | ||||
|     ed448, | ||||
|     ed25519, | ||||
|     rsa, | ||||
| ) | ||||
| from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes | ||||
|  | ||||
| __all__ = [ | ||||
|     "PBES", | ||||
|     "PKCS12Certificate", | ||||
|     "PKCS12KeyAndCertificates", | ||||
|     "PKCS12PrivateKeyTypes", | ||||
|     "load_key_and_certificates", | ||||
|     "load_pkcs12", | ||||
|     "serialize_key_and_certificates", | ||||
| ] | ||||
|  | ||||
| PKCS12PrivateKeyTypes = typing.Union[ | ||||
|     rsa.RSAPrivateKey, | ||||
|     dsa.DSAPrivateKey, | ||||
|     ec.EllipticCurvePrivateKey, | ||||
|     ed25519.Ed25519PrivateKey, | ||||
|     ed448.Ed448PrivateKey, | ||||
| ] | ||||
|  | ||||
|  | ||||
| PKCS12Certificate = rust_pkcs12.PKCS12Certificate | ||||
|  | ||||
|  | ||||
| class PKCS12KeyAndCertificates: | ||||
|     def __init__( | ||||
|         self, | ||||
|         key: PrivateKeyTypes | None, | ||||
|         cert: PKCS12Certificate | None, | ||||
|         additional_certs: list[PKCS12Certificate], | ||||
|     ): | ||||
|         if key is not None and not isinstance( | ||||
|             key, | ||||
|             ( | ||||
|                 rsa.RSAPrivateKey, | ||||
|                 dsa.DSAPrivateKey, | ||||
|                 ec.EllipticCurvePrivateKey, | ||||
|                 ed25519.Ed25519PrivateKey, | ||||
|                 ed448.Ed448PrivateKey, | ||||
|             ), | ||||
|         ): | ||||
|             raise TypeError( | ||||
|                 "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" | ||||
|                 " private key, or None." | ||||
|             ) | ||||
|         if cert is not None and not isinstance(cert, PKCS12Certificate): | ||||
|             raise TypeError("cert must be a PKCS12Certificate object or None") | ||||
|         if not all( | ||||
|             isinstance(add_cert, PKCS12Certificate) | ||||
|             for add_cert in additional_certs | ||||
|         ): | ||||
|             raise TypeError( | ||||
|                 "all values in additional_certs must be PKCS12Certificate" | ||||
|                 " objects" | ||||
|             ) | ||||
|         self._key = key | ||||
|         self._cert = cert | ||||
|         self._additional_certs = additional_certs | ||||
|  | ||||
|     @property | ||||
|     def key(self) -> PrivateKeyTypes | None: | ||||
|         return self._key | ||||
|  | ||||
|     @property | ||||
|     def cert(self) -> PKCS12Certificate | None: | ||||
|         return self._cert | ||||
|  | ||||
|     @property | ||||
|     def additional_certs(self) -> list[PKCS12Certificate]: | ||||
|         return self._additional_certs | ||||
|  | ||||
|     def __eq__(self, other: object) -> bool: | ||||
|         if not isinstance(other, PKCS12KeyAndCertificates): | ||||
|             return NotImplemented | ||||
|  | ||||
|         return ( | ||||
|             self.key == other.key | ||||
|             and self.cert == other.cert | ||||
|             and self.additional_certs == other.additional_certs | ||||
|         ) | ||||
|  | ||||
|     def __hash__(self) -> int: | ||||
|         return hash((self.key, self.cert, tuple(self.additional_certs))) | ||||
|  | ||||
|     def __repr__(self) -> str: | ||||
|         fmt = ( | ||||
|             "<PKCS12KeyAndCertificates(key={}, cert={}, additional_certs={})>" | ||||
|         ) | ||||
|         return fmt.format(self.key, self.cert, self.additional_certs) | ||||
|  | ||||
|  | ||||
| load_key_and_certificates = rust_pkcs12.load_key_and_certificates | ||||
| load_pkcs12 = rust_pkcs12.load_pkcs12 | ||||
|  | ||||
|  | ||||
| _PKCS12CATypes = typing.Union[ | ||||
|     x509.Certificate, | ||||
|     PKCS12Certificate, | ||||
| ] | ||||
|  | ||||
|  | ||||
| def serialize_key_and_certificates( | ||||
|     name: bytes | None, | ||||
|     key: PKCS12PrivateKeyTypes | None, | ||||
|     cert: x509.Certificate | None, | ||||
|     cas: typing.Iterable[_PKCS12CATypes] | None, | ||||
|     encryption_algorithm: serialization.KeySerializationEncryption, | ||||
| ) -> bytes: | ||||
|     if key is not None and not isinstance( | ||||
|         key, | ||||
|         ( | ||||
|             rsa.RSAPrivateKey, | ||||
|             dsa.DSAPrivateKey, | ||||
|             ec.EllipticCurvePrivateKey, | ||||
|             ed25519.Ed25519PrivateKey, | ||||
|             ed448.Ed448PrivateKey, | ||||
|         ), | ||||
|     ): | ||||
|         raise TypeError( | ||||
|             "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" | ||||
|             " private key, or None." | ||||
|         ) | ||||
|  | ||||
|     if not isinstance( | ||||
|         encryption_algorithm, serialization.KeySerializationEncryption | ||||
|     ): | ||||
|         raise TypeError( | ||||
|             "Key encryption algorithm must be a " | ||||
|             "KeySerializationEncryption instance" | ||||
|         ) | ||||
|  | ||||
|     if key is None and cert is None and not cas: | ||||
|         raise ValueError("You must supply at least one of key, cert, or cas") | ||||
|  | ||||
|     return rust_pkcs12.serialize_key_and_certificates( | ||||
|         name, key, cert, cas, encryption_algorithm | ||||
|     ) | ||||
| @@ -0,0 +1,369 @@ | ||||
| # This file is dual licensed under the terms of the Apache License, Version | ||||
| # 2.0, and the BSD License. See the LICENSE file in the root of this repository | ||||
| # for complete details. | ||||
|  | ||||
| from __future__ import annotations | ||||
|  | ||||
| import email.base64mime | ||||
| import email.generator | ||||
| import email.message | ||||
| import email.policy | ||||
| import io | ||||
| import typing | ||||
|  | ||||
| from cryptography import utils, x509 | ||||
| from cryptography.exceptions import UnsupportedAlgorithm, _Reasons | ||||
| from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 | ||||
| from cryptography.hazmat.primitives import hashes, serialization | ||||
| from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa | ||||
| from cryptography.utils import _check_byteslike | ||||
|  | ||||
| load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates | ||||
|  | ||||
| load_der_pkcs7_certificates = rust_pkcs7.load_der_pkcs7_certificates | ||||
|  | ||||
| serialize_certificates = rust_pkcs7.serialize_certificates | ||||
|  | ||||
| PKCS7HashTypes = typing.Union[ | ||||
|     hashes.SHA224, | ||||
|     hashes.SHA256, | ||||
|     hashes.SHA384, | ||||
|     hashes.SHA512, | ||||
| ] | ||||
|  | ||||
| PKCS7PrivateKeyTypes = typing.Union[ | ||||
|     rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey | ||||
| ] | ||||
|  | ||||
|  | ||||
| class PKCS7Options(utils.Enum): | ||||
|     Text = "Add text/plain MIME type" | ||||
|     Binary = "Don't translate input data into canonical MIME format" | ||||
|     DetachedSignature = "Don't embed data in the PKCS7 structure" | ||||
|     NoCapabilities = "Don't embed SMIME capabilities" | ||||
|     NoAttributes = "Don't embed authenticatedAttributes" | ||||
|     NoCerts = "Don't embed signer certificate" | ||||
|  | ||||
|  | ||||
| class PKCS7SignatureBuilder: | ||||
|     def __init__( | ||||
|         self, | ||||
|         data: bytes | None = None, | ||||
|         signers: list[ | ||||
|             tuple[ | ||||
|                 x509.Certificate, | ||||
|                 PKCS7PrivateKeyTypes, | ||||
|                 PKCS7HashTypes, | ||||
|                 padding.PSS | padding.PKCS1v15 | None, | ||||
|             ] | ||||
|         ] = [], | ||||
|         additional_certs: list[x509.Certificate] = [], | ||||
|     ): | ||||
|         self._data = data | ||||
|         self._signers = signers | ||||
|         self._additional_certs = additional_certs | ||||
|  | ||||
|     def set_data(self, data: bytes) -> PKCS7SignatureBuilder: | ||||
|         _check_byteslike("data", data) | ||||
|         if self._data is not None: | ||||
|             raise ValueError("data may only be set once") | ||||
|  | ||||
|         return PKCS7SignatureBuilder(data, self._signers) | ||||
|  | ||||
|     def add_signer( | ||||
|         self, | ||||
|         certificate: x509.Certificate, | ||||
|         private_key: PKCS7PrivateKeyTypes, | ||||
|         hash_algorithm: PKCS7HashTypes, | ||||
|         *, | ||||
|         rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, | ||||
|     ) -> PKCS7SignatureBuilder: | ||||
|         if not isinstance( | ||||
|             hash_algorithm, | ||||
|             ( | ||||
|                 hashes.SHA224, | ||||
|                 hashes.SHA256, | ||||
|                 hashes.SHA384, | ||||
|                 hashes.SHA512, | ||||
|             ), | ||||
|         ): | ||||
|             raise TypeError( | ||||
|                 "hash_algorithm must be one of hashes.SHA224, " | ||||
|                 "SHA256, SHA384, or SHA512" | ||||
|             ) | ||||
|         if not isinstance(certificate, x509.Certificate): | ||||
|             raise TypeError("certificate must be a x509.Certificate") | ||||
|  | ||||
|         if not isinstance( | ||||
|             private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) | ||||
|         ): | ||||
|             raise TypeError("Only RSA & EC keys are supported at this time.") | ||||
|  | ||||
|         if rsa_padding is not None: | ||||
|             if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): | ||||
|                 raise TypeError("Padding must be PSS or PKCS1v15") | ||||
|             if not isinstance(private_key, rsa.RSAPrivateKey): | ||||
|                 raise TypeError("Padding is only supported for RSA keys") | ||||
|  | ||||
|         return PKCS7SignatureBuilder( | ||||
|             self._data, | ||||
|             [ | ||||
|                 *self._signers, | ||||
|                 (certificate, private_key, hash_algorithm, rsa_padding), | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     def add_certificate( | ||||
|         self, certificate: x509.Certificate | ||||
|     ) -> PKCS7SignatureBuilder: | ||||
|         if not isinstance(certificate, x509.Certificate): | ||||
|             raise TypeError("certificate must be a x509.Certificate") | ||||
|  | ||||
|         return PKCS7SignatureBuilder( | ||||
|             self._data, self._signers, [*self._additional_certs, certificate] | ||||
|         ) | ||||
|  | ||||
|     def sign( | ||||
|         self, | ||||
|         encoding: serialization.Encoding, | ||||
|         options: typing.Iterable[PKCS7Options], | ||||
|         backend: typing.Any = None, | ||||
|     ) -> bytes: | ||||
|         if len(self._signers) == 0: | ||||
|             raise ValueError("Must have at least one signer") | ||||
|         if self._data is None: | ||||
|             raise ValueError("You must add data to sign") | ||||
|         options = list(options) | ||||
|         if not all(isinstance(x, PKCS7Options) for x in options): | ||||
|             raise ValueError("options must be from the PKCS7Options enum") | ||||
|         if encoding not in ( | ||||
|             serialization.Encoding.PEM, | ||||
|             serialization.Encoding.DER, | ||||
|             serialization.Encoding.SMIME, | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "Must be PEM, DER, or SMIME from the Encoding enum" | ||||
|             ) | ||||
|  | ||||
|         # Text is a meaningless option unless it is accompanied by | ||||
|         # DetachedSignature | ||||
|         if ( | ||||
|             PKCS7Options.Text in options | ||||
|             and PKCS7Options.DetachedSignature not in options | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "When passing the Text option you must also pass " | ||||
|                 "DetachedSignature" | ||||
|             ) | ||||
|  | ||||
|         if PKCS7Options.Text in options and encoding in ( | ||||
|             serialization.Encoding.DER, | ||||
|             serialization.Encoding.PEM, | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "The Text option is only available for SMIME serialization" | ||||
|             ) | ||||
|  | ||||
|         # No attributes implies no capabilities so we'll error if you try to | ||||
|         # pass both. | ||||
|         if ( | ||||
|             PKCS7Options.NoAttributes in options | ||||
|             and PKCS7Options.NoCapabilities in options | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "NoAttributes is a superset of NoCapabilities. Do not pass " | ||||
|                 "both values." | ||||
|             ) | ||||
|  | ||||
|         return rust_pkcs7.sign_and_serialize(self, encoding, options) | ||||
|  | ||||
|  | ||||
| class PKCS7EnvelopeBuilder: | ||||
|     def __init__( | ||||
|         self, | ||||
|         *, | ||||
|         _data: bytes | None = None, | ||||
|         _recipients: list[x509.Certificate] | None = None, | ||||
|     ): | ||||
|         from cryptography.hazmat.backends.openssl.backend import ( | ||||
|             backend as ossl, | ||||
|         ) | ||||
|  | ||||
|         if not ossl.rsa_encryption_supported(padding=padding.PKCS1v15()): | ||||
|             raise UnsupportedAlgorithm( | ||||
|                 "RSA with PKCS1 v1.5 padding is not supported by this version" | ||||
|                 " of OpenSSL.", | ||||
|                 _Reasons.UNSUPPORTED_PADDING, | ||||
|             ) | ||||
|         self._data = _data | ||||
|         self._recipients = _recipients if _recipients is not None else [] | ||||
|  | ||||
|     def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder: | ||||
|         _check_byteslike("data", data) | ||||
|         if self._data is not None: | ||||
|             raise ValueError("data may only be set once") | ||||
|  | ||||
|         return PKCS7EnvelopeBuilder(_data=data, _recipients=self._recipients) | ||||
|  | ||||
|     def add_recipient( | ||||
|         self, | ||||
|         certificate: x509.Certificate, | ||||
|     ) -> PKCS7EnvelopeBuilder: | ||||
|         if not isinstance(certificate, x509.Certificate): | ||||
|             raise TypeError("certificate must be a x509.Certificate") | ||||
|  | ||||
|         if not isinstance(certificate.public_key(), rsa.RSAPublicKey): | ||||
|             raise TypeError("Only RSA keys are supported at this time.") | ||||
|  | ||||
|         return PKCS7EnvelopeBuilder( | ||||
|             _data=self._data, | ||||
|             _recipients=[ | ||||
|                 *self._recipients, | ||||
|                 certificate, | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     def encrypt( | ||||
|         self, | ||||
|         encoding: serialization.Encoding, | ||||
|         options: typing.Iterable[PKCS7Options], | ||||
|     ) -> bytes: | ||||
|         if len(self._recipients) == 0: | ||||
|             raise ValueError("Must have at least one recipient") | ||||
|         if self._data is None: | ||||
|             raise ValueError("You must add data to encrypt") | ||||
|         options = list(options) | ||||
|         if not all(isinstance(x, PKCS7Options) for x in options): | ||||
|             raise ValueError("options must be from the PKCS7Options enum") | ||||
|         if encoding not in ( | ||||
|             serialization.Encoding.PEM, | ||||
|             serialization.Encoding.DER, | ||||
|             serialization.Encoding.SMIME, | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "Must be PEM, DER, or SMIME from the Encoding enum" | ||||
|             ) | ||||
|  | ||||
|         # Only allow options that make sense for encryption | ||||
|         if any( | ||||
|             opt not in [PKCS7Options.Text, PKCS7Options.Binary] | ||||
|             for opt in options | ||||
|         ): | ||||
|             raise ValueError( | ||||
|                 "Only the following options are supported for encryption: " | ||||
|                 "Text, Binary" | ||||
|             ) | ||||
|         elif PKCS7Options.Text in options and PKCS7Options.Binary in options: | ||||
|             # OpenSSL accepts both options at the same time, but ignores Text. | ||||
|             # We fail defensively to avoid unexpected outputs. | ||||
|             raise ValueError( | ||||
|                 "Cannot use Binary and Text options at the same time" | ||||
|             ) | ||||
|  | ||||
|         return rust_pkcs7.encrypt_and_serialize(self, encoding, options) | ||||
|  | ||||
|  | ||||
| pkcs7_decrypt_der = rust_pkcs7.decrypt_der | ||||
| pkcs7_decrypt_pem = rust_pkcs7.decrypt_pem | ||||
| pkcs7_decrypt_smime = rust_pkcs7.decrypt_smime | ||||
|  | ||||
|  | ||||
| def _smime_signed_encode( | ||||
|     data: bytes, signature: bytes, micalg: str, text_mode: bool | ||||
| ) -> bytes: | ||||
|     # This function works pretty hard to replicate what OpenSSL does | ||||
|     # precisely. For good and for ill. | ||||
|  | ||||
|     m = email.message.Message() | ||||
|     m.add_header("MIME-Version", "1.0") | ||||
|     m.add_header( | ||||
|         "Content-Type", | ||||
|         "multipart/signed", | ||||
|         protocol="application/x-pkcs7-signature", | ||||
|         micalg=micalg, | ||||
|     ) | ||||
|  | ||||
|     m.preamble = "This is an S/MIME signed message\n" | ||||
|  | ||||
|     msg_part = OpenSSLMimePart() | ||||
|     msg_part.set_payload(data) | ||||
|     if text_mode: | ||||
|         msg_part.add_header("Content-Type", "text/plain") | ||||
|     m.attach(msg_part) | ||||
|  | ||||
|     sig_part = email.message.MIMEPart() | ||||
|     sig_part.add_header( | ||||
|         "Content-Type", "application/x-pkcs7-signature", name="smime.p7s" | ||||
|     ) | ||||
|     sig_part.add_header("Content-Transfer-Encoding", "base64") | ||||
|     sig_part.add_header( | ||||
|         "Content-Disposition", "attachment", filename="smime.p7s" | ||||
|     ) | ||||
|     sig_part.set_payload( | ||||
|         email.base64mime.body_encode(signature, maxlinelen=65) | ||||
|     ) | ||||
|     del sig_part["MIME-Version"] | ||||
|     m.attach(sig_part) | ||||
|  | ||||
|     fp = io.BytesIO() | ||||
|     g = email.generator.BytesGenerator( | ||||
|         fp, | ||||
|         maxheaderlen=0, | ||||
|         mangle_from_=False, | ||||
|         policy=m.policy.clone(linesep="\r\n"), | ||||
|     ) | ||||
|     g.flatten(m) | ||||
|     return fp.getvalue() | ||||
|  | ||||
|  | ||||
| def _smime_enveloped_encode(data: bytes) -> bytes: | ||||
|     m = email.message.Message() | ||||
|     m.add_header("MIME-Version", "1.0") | ||||
|     m.add_header("Content-Disposition", "attachment", filename="smime.p7m") | ||||
|     m.add_header( | ||||
|         "Content-Type", | ||||
|         "application/pkcs7-mime", | ||||
|         smime_type="enveloped-data", | ||||
|         name="smime.p7m", | ||||
|     ) | ||||
|     m.add_header("Content-Transfer-Encoding", "base64") | ||||
|  | ||||
|     m.set_payload(email.base64mime.body_encode(data, maxlinelen=65)) | ||||
|  | ||||
|     return m.as_bytes(policy=m.policy.clone(linesep="\n", max_line_length=0)) | ||||
|  | ||||
|  | ||||
| def _smime_enveloped_decode(data: bytes) -> bytes: | ||||
|     m = email.message_from_bytes(data) | ||||
|     if m.get_content_type() not in { | ||||
|         "application/x-pkcs7-mime", | ||||
|         "application/pkcs7-mime", | ||||
|     }: | ||||
|         raise ValueError("Not an S/MIME enveloped message") | ||||
|     return bytes(m.get_payload(decode=True)) | ||||
|  | ||||
|  | ||||
| def _smime_remove_text_headers(data: bytes) -> bytes: | ||||
|     m = email.message_from_bytes(data) | ||||
|     # Using get() instead of get_content_type() since it has None as default, | ||||
|     # where the latter has "text/plain". Both methods are case-insensitive. | ||||
|     content_type = m.get("content-type") | ||||
|     if content_type is None: | ||||
|         raise ValueError( | ||||
|             "Decrypted MIME data has no 'Content-Type' header. " | ||||
|             "Please remove the 'Text' option to parse it manually." | ||||
|         ) | ||||
|     if "text/plain" not in content_type: | ||||
|         raise ValueError( | ||||
|             f"Decrypted MIME data content type is '{content_type}', not " | ||||
|             "'text/plain'. Remove the 'Text' option to parse it manually." | ||||
|         ) | ||||
|     return bytes(m.get_payload(decode=True)) | ||||
|  | ||||
|  | ||||
| class OpenSSLMimePart(email.message.MIMEPart): | ||||
|     # A MIMEPart subclass that replicates OpenSSL's behavior of not including | ||||
|     # a newline if there are no headers. | ||||
|     def _write_headers(self, generator) -> None: | ||||
|         if list(self.raw_items()): | ||||
|             generator._write_headers(self) | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user