pkcs12.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. import typing
  5. from cryptography import x509
  6. from cryptography.hazmat.primitives import serialization
  7. from cryptography.hazmat.primitives.asymmetric import (
  8. dsa,
  9. ec,
  10. ed25519,
  11. ed448,
  12. rsa,
  13. )
  14. from cryptography.hazmat.primitives.asymmetric.types import (
  15. PRIVATE_KEY_TYPES,
  16. )
  17. _ALLOWED_PKCS12_TYPES = typing.Union[
  18. rsa.RSAPrivateKey,
  19. dsa.DSAPrivateKey,
  20. ec.EllipticCurvePrivateKey,
  21. ed25519.Ed25519PrivateKey,
  22. ed448.Ed448PrivateKey,
  23. ]
  24. class PKCS12Certificate:
  25. def __init__(
  26. self,
  27. cert: x509.Certificate,
  28. friendly_name: typing.Optional[bytes],
  29. ):
  30. if not isinstance(cert, x509.Certificate):
  31. raise TypeError("Expecting x509.Certificate object")
  32. if friendly_name is not None and not isinstance(friendly_name, bytes):
  33. raise TypeError("friendly_name must be bytes or None")
  34. self._cert = cert
  35. self._friendly_name = friendly_name
  36. @property
  37. def friendly_name(self) -> typing.Optional[bytes]:
  38. return self._friendly_name
  39. @property
  40. def certificate(self) -> x509.Certificate:
  41. return self._cert
  42. def __eq__(self, other: object) -> bool:
  43. if not isinstance(other, PKCS12Certificate):
  44. return NotImplemented
  45. return (
  46. self.certificate == other.certificate
  47. and self.friendly_name == other.friendly_name
  48. )
  49. def __hash__(self) -> int:
  50. return hash((self.certificate, self.friendly_name))
  51. def __repr__(self) -> str:
  52. return "<PKCS12Certificate({}, friendly_name={!r})>".format(
  53. self.certificate, self.friendly_name
  54. )
  55. class PKCS12KeyAndCertificates:
  56. def __init__(
  57. self,
  58. key: typing.Optional[PRIVATE_KEY_TYPES],
  59. cert: typing.Optional[PKCS12Certificate],
  60. additional_certs: typing.List[PKCS12Certificate],
  61. ):
  62. if key is not None and not isinstance(
  63. key,
  64. (
  65. rsa.RSAPrivateKey,
  66. dsa.DSAPrivateKey,
  67. ec.EllipticCurvePrivateKey,
  68. ed25519.Ed25519PrivateKey,
  69. ed448.Ed448PrivateKey,
  70. ),
  71. ):
  72. raise TypeError(
  73. "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448"
  74. " private key, or None."
  75. )
  76. if cert is not None and not isinstance(cert, PKCS12Certificate):
  77. raise TypeError("cert must be a PKCS12Certificate object or None")
  78. if not all(
  79. isinstance(add_cert, PKCS12Certificate)
  80. for add_cert in additional_certs
  81. ):
  82. raise TypeError(
  83. "all values in additional_certs must be PKCS12Certificate"
  84. " objects"
  85. )
  86. self._key = key
  87. self._cert = cert
  88. self._additional_certs = additional_certs
  89. @property
  90. def key(self) -> typing.Optional[PRIVATE_KEY_TYPES]:
  91. return self._key
  92. @property
  93. def cert(self) -> typing.Optional[PKCS12Certificate]:
  94. return self._cert
  95. @property
  96. def additional_certs(self) -> typing.List[PKCS12Certificate]:
  97. return self._additional_certs
  98. def __eq__(self, other: object) -> bool:
  99. if not isinstance(other, PKCS12KeyAndCertificates):
  100. return NotImplemented
  101. return (
  102. self.key == other.key
  103. and self.cert == other.cert
  104. and self.additional_certs == other.additional_certs
  105. )
  106. def __hash__(self) -> int:
  107. return hash((self.key, self.cert, tuple(self.additional_certs)))
  108. def __repr__(self) -> str:
  109. fmt = (
  110. "<PKCS12KeyAndCertificates(key={}, cert={}, additional_certs={})>"
  111. )
  112. return fmt.format(self.key, self.cert, self.additional_certs)
  113. def load_key_and_certificates(
  114. data: bytes,
  115. password: typing.Optional[bytes],
  116. backend: typing.Any = None,
  117. ) -> typing.Tuple[
  118. typing.Optional[PRIVATE_KEY_TYPES],
  119. typing.Optional[x509.Certificate],
  120. typing.List[x509.Certificate],
  121. ]:
  122. from cryptography.hazmat.backends.openssl.backend import backend as ossl
  123. return ossl.load_key_and_certificates_from_pkcs12(data, password)
  124. def load_pkcs12(
  125. data: bytes,
  126. password: typing.Optional[bytes],
  127. backend: typing.Any = None,
  128. ) -> PKCS12KeyAndCertificates:
  129. from cryptography.hazmat.backends.openssl.backend import backend as ossl
  130. return ossl.load_pkcs12(data, password)
  131. _PKCS12_CAS_TYPES = typing.Union[
  132. x509.Certificate,
  133. PKCS12Certificate,
  134. ]
  135. def serialize_key_and_certificates(
  136. name: typing.Optional[bytes],
  137. key: typing.Optional[_ALLOWED_PKCS12_TYPES],
  138. cert: typing.Optional[x509.Certificate],
  139. cas: typing.Optional[typing.Iterable[_PKCS12_CAS_TYPES]],
  140. encryption_algorithm: serialization.KeySerializationEncryption,
  141. ) -> bytes:
  142. if key is not None and not isinstance(
  143. key,
  144. (
  145. rsa.RSAPrivateKey,
  146. dsa.DSAPrivateKey,
  147. ec.EllipticCurvePrivateKey,
  148. ed25519.Ed25519PrivateKey,
  149. ed448.Ed448PrivateKey,
  150. ),
  151. ):
  152. raise TypeError(
  153. "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448"
  154. " private key, or None."
  155. )
  156. if cert is not None and not isinstance(cert, x509.Certificate):
  157. raise TypeError("cert must be a certificate or None")
  158. if cas is not None:
  159. cas = list(cas)
  160. if not all(
  161. isinstance(
  162. val,
  163. (
  164. x509.Certificate,
  165. PKCS12Certificate,
  166. ),
  167. )
  168. for val in cas
  169. ):
  170. raise TypeError("all values in cas must be certificates")
  171. if not isinstance(
  172. encryption_algorithm, serialization.KeySerializationEncryption
  173. ):
  174. raise TypeError(
  175. "Key encryption algorithm must be a "
  176. "KeySerializationEncryption instance"
  177. )
  178. if key is None and cert is None and not cas:
  179. raise ValueError("You must supply at least one of key, cert, or cas")
  180. from cryptography.hazmat.backends.openssl.backend import backend
  181. return backend.serialize_key_and_certificates_to_pkcs12(
  182. name, key, cert, cas, encryption_algorithm
  183. )