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

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. 

4 

5import typing 

6 

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 

12 

13 

14def load_pem_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]: 

15 from cryptography.hazmat.backends.openssl.backend import backend 

16 

17 return backend.load_pem_pkcs7_certificates(data) 

18 

19 

20def load_der_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]: 

21 from cryptography.hazmat.backends.openssl.backend import backend 

22 

23 return backend.load_der_pkcs7_certificates(data) 

24 

25 

26def serialize_certificates( 

27 certs: typing.List[x509.Certificate], 

28 encoding: serialization.Encoding, 

29) -> bytes: 

30 from cryptography.hazmat.backends.openssl.backend import backend 

31 

32 return backend.pkcs7_serialize_certificates(certs, encoding) 

33 

34 

35_ALLOWED_PKCS7_HASH_TYPES = typing.Union[ 

36 hashes.SHA1, 

37 hashes.SHA224, 

38 hashes.SHA256, 

39 hashes.SHA384, 

40 hashes.SHA512, 

41] 

42 

43_ALLOWED_PRIVATE_KEY_TYPES = typing.Union[ 

44 rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey 

45] 

46 

47 

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" 

55 

56 

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 

73 

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") 

78 

79 return PKCS7SignatureBuilder(data, self._signers) 

80 

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") 

103 

104 if not isinstance( 

105 private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) 

106 ): 

107 raise TypeError("Only RSA & EC keys are supported at this time.") 

108 

109 return PKCS7SignatureBuilder( 

110 self._data, 

111 self._signers + [(certificate, private_key, hash_algorithm)], 

112 ) 

113 

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") 

119 

120 return PKCS7SignatureBuilder( 

121 self._data, self._signers, self._additional_certs + [certificate] 

122 ) 

123 

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 ) 

145 

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 ) 

156 

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 ) 

164 

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 ) 

175 

176 from cryptography.hazmat.backends.openssl.backend import ( 

177 backend as ossl, 

178 ) 

179 

180 return ossl.pkcs7_sign(self, encoding, options)