Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py: 38%
64 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
5import typing
7from cryptography import utils
8from cryptography import x509
9from cryptography.hazmat.primitives import hashes, serialization
10from cryptography.hazmat.primitives.asymmetric import ec, rsa
11from cryptography.utils import _check_byteslike
14def load_pem_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]:
15 from cryptography.hazmat.backends.openssl.backend import backend
17 return backend.load_pem_pkcs7_certificates(data)
20def load_der_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]:
21 from cryptography.hazmat.backends.openssl.backend import backend
23 return backend.load_der_pkcs7_certificates(data)
26def serialize_certificates(
27 certs: typing.List[x509.Certificate],
28 encoding: serialization.Encoding,
29) -> bytes:
30 from cryptography.hazmat.backends.openssl.backend import backend
32 return backend.pkcs7_serialize_certificates(certs, encoding)
35_ALLOWED_PKCS7_HASH_TYPES = typing.Union[
36 hashes.SHA1,
37 hashes.SHA224,
38 hashes.SHA256,
39 hashes.SHA384,
40 hashes.SHA512,
41]
43_ALLOWED_PRIVATE_KEY_TYPES = typing.Union[
44 rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey
45]
48class PKCS7Options(utils.Enum):
49 Text = "Add text/plain MIME type"
50 Binary = "Don't translate input data into canonical MIME format"
51 DetachedSignature = "Don't embed data in the PKCS7 structure"
52 NoCapabilities = "Don't embed SMIME capabilities"
53 NoAttributes = "Don't embed authenticatedAttributes"
54 NoCerts = "Don't embed signer certificate"
57class PKCS7SignatureBuilder:
58 def __init__(
59 self,
60 data: typing.Optional[bytes] = None,
61 signers: typing.List[
62 typing.Tuple[
63 x509.Certificate,
64 _ALLOWED_PRIVATE_KEY_TYPES,
65 _ALLOWED_PKCS7_HASH_TYPES,
66 ]
67 ] = [],
68 additional_certs: typing.List[x509.Certificate] = [],
69 ):
70 self._data = data
71 self._signers = signers
72 self._additional_certs = additional_certs
74 def set_data(self, data: bytes) -> "PKCS7SignatureBuilder":
75 _check_byteslike("data", data)
76 if self._data is not None:
77 raise ValueError("data may only be set once")
79 return PKCS7SignatureBuilder(data, self._signers)
81 def add_signer(
82 self,
83 certificate: x509.Certificate,
84 private_key: _ALLOWED_PRIVATE_KEY_TYPES,
85 hash_algorithm: _ALLOWED_PKCS7_HASH_TYPES,
86 ) -> "PKCS7SignatureBuilder":
87 if not isinstance(
88 hash_algorithm,
89 (
90 hashes.SHA1,
91 hashes.SHA224,
92 hashes.SHA256,
93 hashes.SHA384,
94 hashes.SHA512,
95 ),
96 ):
97 raise TypeError(
98 "hash_algorithm must be one of hashes.SHA1, SHA224, "
99 "SHA256, SHA384, or SHA512"
100 )
101 if not isinstance(certificate, x509.Certificate):
102 raise TypeError("certificate must be a x509.Certificate")
104 if not isinstance(
105 private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey)
106 ):
107 raise TypeError("Only RSA & EC keys are supported at this time.")
109 return PKCS7SignatureBuilder(
110 self._data,
111 self._signers + [(certificate, private_key, hash_algorithm)],
112 )
114 def add_certificate(
115 self, certificate: x509.Certificate
116 ) -> "PKCS7SignatureBuilder":
117 if not isinstance(certificate, x509.Certificate):
118 raise TypeError("certificate must be a x509.Certificate")
120 return PKCS7SignatureBuilder(
121 self._data, self._signers, self._additional_certs + [certificate]
122 )
124 def sign(
125 self,
126 encoding: serialization.Encoding,
127 options: typing.Iterable[PKCS7Options],
128 backend: typing.Any = None,
129 ) -> bytes:
130 if len(self._signers) == 0:
131 raise ValueError("Must have at least one signer")
132 if self._data is None:
133 raise ValueError("You must add data to sign")
134 options = list(options)
135 if not all(isinstance(x, PKCS7Options) for x in options):
136 raise ValueError("options must be from the PKCS7Options enum")
137 if encoding not in (
138 serialization.Encoding.PEM,
139 serialization.Encoding.DER,
140 serialization.Encoding.SMIME,
141 ):
142 raise ValueError(
143 "Must be PEM, DER, or SMIME from the Encoding enum"
144 )
146 # Text is a meaningless option unless it is accompanied by
147 # DetachedSignature
148 if (
149 PKCS7Options.Text in options
150 and PKCS7Options.DetachedSignature not in options
151 ):
152 raise ValueError(
153 "When passing the Text option you must also pass "
154 "DetachedSignature"
155 )
157 if PKCS7Options.Text in options and encoding in (
158 serialization.Encoding.DER,
159 serialization.Encoding.PEM,
160 ):
161 raise ValueError(
162 "The Text option is only available for SMIME serialization"
163 )
165 # No attributes implies no capabilities so we'll error if you try to
166 # pass both.
167 if (
168 PKCS7Options.NoAttributes in options
169 and PKCS7Options.NoCapabilities in options
170 ):
171 raise ValueError(
172 "NoAttributes is a superset of NoCapabilities. Do not pass "
173 "both values."
174 )
176 from cryptography.hazmat.backends.openssl.backend import (
177 backend as ossl,
178 )
180 return ossl.pkcs7_sign(self, encoding, options)