Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py: 40%

82 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 07:26 +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 

5from __future__ import annotations 

6 

7import typing 

8 

9from cryptography import x509 

10from cryptography.hazmat.primitives import serialization 

11from cryptography.hazmat.primitives._serialization import PBES as PBES 

12from cryptography.hazmat.primitives.asymmetric import ( 

13 dsa, 

14 ec, 

15 ed448, 

16 ed25519, 

17 rsa, 

18) 

19from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes 

20 

21__all__ = [ 

22 "PBES", 

23 "PKCS12PrivateKeyTypes", 

24 "PKCS12Certificate", 

25 "PKCS12KeyAndCertificates", 

26 "load_key_and_certificates", 

27 "load_pkcs12", 

28 "serialize_key_and_certificates", 

29] 

30 

31PKCS12PrivateKeyTypes = typing.Union[ 

32 rsa.RSAPrivateKey, 

33 dsa.DSAPrivateKey, 

34 ec.EllipticCurvePrivateKey, 

35 ed25519.Ed25519PrivateKey, 

36 ed448.Ed448PrivateKey, 

37] 

38 

39 

40class PKCS12Certificate: 

41 def __init__( 

42 self, 

43 cert: x509.Certificate, 

44 friendly_name: bytes | None, 

45 ): 

46 if not isinstance(cert, x509.Certificate): 

47 raise TypeError("Expecting x509.Certificate object") 

48 if friendly_name is not None and not isinstance(friendly_name, bytes): 

49 raise TypeError("friendly_name must be bytes or None") 

50 self._cert = cert 

51 self._friendly_name = friendly_name 

52 

53 @property 

54 def friendly_name(self) -> bytes | None: 

55 return self._friendly_name 

56 

57 @property 

58 def certificate(self) -> x509.Certificate: 

59 return self._cert 

60 

61 def __eq__(self, other: object) -> bool: 

62 if not isinstance(other, PKCS12Certificate): 

63 return NotImplemented 

64 

65 return ( 

66 self.certificate == other.certificate 

67 and self.friendly_name == other.friendly_name 

68 ) 

69 

70 def __hash__(self) -> int: 

71 return hash((self.certificate, self.friendly_name)) 

72 

73 def __repr__(self) -> str: 

74 return "<PKCS12Certificate({}, friendly_name={!r})>".format( 

75 self.certificate, self.friendly_name 

76 ) 

77 

78 

79class PKCS12KeyAndCertificates: 

80 def __init__( 

81 self, 

82 key: PrivateKeyTypes | None, 

83 cert: PKCS12Certificate | None, 

84 additional_certs: list[PKCS12Certificate], 

85 ): 

86 if key is not None and not isinstance( 

87 key, 

88 ( 

89 rsa.RSAPrivateKey, 

90 dsa.DSAPrivateKey, 

91 ec.EllipticCurvePrivateKey, 

92 ed25519.Ed25519PrivateKey, 

93 ed448.Ed448PrivateKey, 

94 ), 

95 ): 

96 raise TypeError( 

97 "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" 

98 " private key, or None." 

99 ) 

100 if cert is not None and not isinstance(cert, PKCS12Certificate): 

101 raise TypeError("cert must be a PKCS12Certificate object or None") 

102 if not all( 

103 isinstance(add_cert, PKCS12Certificate) 

104 for add_cert in additional_certs 

105 ): 

106 raise TypeError( 

107 "all values in additional_certs must be PKCS12Certificate" 

108 " objects" 

109 ) 

110 self._key = key 

111 self._cert = cert 

112 self._additional_certs = additional_certs 

113 

114 @property 

115 def key(self) -> PrivateKeyTypes | None: 

116 return self._key 

117 

118 @property 

119 def cert(self) -> PKCS12Certificate | None: 

120 return self._cert 

121 

122 @property 

123 def additional_certs(self) -> list[PKCS12Certificate]: 

124 return self._additional_certs 

125 

126 def __eq__(self, other: object) -> bool: 

127 if not isinstance(other, PKCS12KeyAndCertificates): 

128 return NotImplemented 

129 

130 return ( 

131 self.key == other.key 

132 and self.cert == other.cert 

133 and self.additional_certs == other.additional_certs 

134 ) 

135 

136 def __hash__(self) -> int: 

137 return hash((self.key, self.cert, tuple(self.additional_certs))) 

138 

139 def __repr__(self) -> str: 

140 fmt = ( 

141 "<PKCS12KeyAndCertificates(key={}, cert={}, additional_certs={})>" 

142 ) 

143 return fmt.format(self.key, self.cert, self.additional_certs) 

144 

145 

146def load_key_and_certificates( 

147 data: bytes, 

148 password: bytes | None, 

149 backend: typing.Any = None, 

150) -> tuple[ 

151 PrivateKeyTypes | None, 

152 x509.Certificate | None, 

153 list[x509.Certificate], 

154]: 

155 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

156 

157 return ossl.load_key_and_certificates_from_pkcs12(data, password) 

158 

159 

160def load_pkcs12( 

161 data: bytes, 

162 password: bytes | None, 

163 backend: typing.Any = None, 

164) -> PKCS12KeyAndCertificates: 

165 from cryptography.hazmat.backends.openssl.backend import backend as ossl 

166 

167 return ossl.load_pkcs12(data, password) 

168 

169 

170_PKCS12CATypes = typing.Union[ 

171 x509.Certificate, 

172 PKCS12Certificate, 

173] 

174 

175 

176def serialize_key_and_certificates( 

177 name: bytes | None, 

178 key: PKCS12PrivateKeyTypes | None, 

179 cert: x509.Certificate | None, 

180 cas: typing.Iterable[_PKCS12CATypes] | None, 

181 encryption_algorithm: serialization.KeySerializationEncryption, 

182) -> bytes: 

183 if key is not None and not isinstance( 

184 key, 

185 ( 

186 rsa.RSAPrivateKey, 

187 dsa.DSAPrivateKey, 

188 ec.EllipticCurvePrivateKey, 

189 ed25519.Ed25519PrivateKey, 

190 ed448.Ed448PrivateKey, 

191 ), 

192 ): 

193 raise TypeError( 

194 "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" 

195 " private key, or None." 

196 ) 

197 if cert is not None and not isinstance(cert, x509.Certificate): 

198 raise TypeError("cert must be a certificate or None") 

199 

200 if cas is not None: 

201 cas = list(cas) 

202 if not all( 

203 isinstance( 

204 val, 

205 ( 

206 x509.Certificate, 

207 PKCS12Certificate, 

208 ), 

209 ) 

210 for val in cas 

211 ): 

212 raise TypeError("all values in cas must be certificates") 

213 

214 if not isinstance( 

215 encryption_algorithm, serialization.KeySerializationEncryption 

216 ): 

217 raise TypeError( 

218 "Key encryption algorithm must be a " 

219 "KeySerializationEncryption instance" 

220 ) 

221 

222 if key is None and cert is None and not cas: 

223 raise ValueError("You must supply at least one of key, cert, or cas") 

224 

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

226 

227 return backend.serialize_key_and_certificates_to_pkcs12( 

228 name, key, cert, cas, encryption_algorithm 

229 )