dsa.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 utils
  6. from cryptography.exceptions import InvalidSignature
  7. from cryptography.hazmat.backends.openssl.utils import (
  8. _calculate_digest_and_algorithm,
  9. _check_not_prehashed,
  10. _warn_sign_verify_deprecated,
  11. )
  12. from cryptography.hazmat.primitives import hashes, serialization
  13. from cryptography.hazmat.primitives.asymmetric import (
  14. AsymmetricSignatureContext,
  15. AsymmetricVerificationContext,
  16. dsa,
  17. utils as asym_utils,
  18. )
  19. def _dsa_sig_sign(backend, private_key, data):
  20. sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata)
  21. sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len)
  22. buflen = backend._ffi.new("unsigned int *")
  23. # The first parameter passed to DSA_sign is unused by OpenSSL but
  24. # must be an integer.
  25. res = backend._lib.DSA_sign(
  26. 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata
  27. )
  28. backend.openssl_assert(res == 1)
  29. backend.openssl_assert(buflen[0])
  30. return backend._ffi.buffer(sig_buf)[: buflen[0]]
  31. def _dsa_sig_verify(backend, public_key, signature, data):
  32. # The first parameter passed to DSA_verify is unused by OpenSSL but
  33. # must be an integer.
  34. res = backend._lib.DSA_verify(
  35. 0, data, len(data), signature, len(signature), public_key._dsa_cdata
  36. )
  37. if res != 1:
  38. backend._consume_errors()
  39. raise InvalidSignature
  40. class _DSAVerificationContext(AsymmetricVerificationContext):
  41. def __init__(self, backend, public_key, signature, algorithm):
  42. self._backend = backend
  43. self._public_key = public_key
  44. self._signature = signature
  45. self._algorithm = algorithm
  46. self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
  47. def update(self, data: bytes):
  48. self._hash_ctx.update(data)
  49. def verify(self) -> None:
  50. data_to_verify = self._hash_ctx.finalize()
  51. _dsa_sig_verify(
  52. self._backend, self._public_key, self._signature, data_to_verify
  53. )
  54. class _DSASignatureContext(AsymmetricSignatureContext):
  55. def __init__(
  56. self,
  57. backend,
  58. private_key: dsa.DSAPrivateKey,
  59. algorithm: hashes.HashAlgorithm,
  60. ):
  61. self._backend = backend
  62. self._private_key = private_key
  63. self._algorithm = algorithm
  64. self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
  65. def update(self, data: bytes) -> None:
  66. self._hash_ctx.update(data)
  67. def finalize(self) -> bytes:
  68. data_to_sign = self._hash_ctx.finalize()
  69. return _dsa_sig_sign(self._backend, self._private_key, data_to_sign)
  70. class _DSAParameters(dsa.DSAParameters):
  71. def __init__(self, backend, dsa_cdata):
  72. self._backend = backend
  73. self._dsa_cdata = dsa_cdata
  74. def parameter_numbers(self) -> dsa.DSAParameterNumbers:
  75. p = self._backend._ffi.new("BIGNUM **")
  76. q = self._backend._ffi.new("BIGNUM **")
  77. g = self._backend._ffi.new("BIGNUM **")
  78. self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
  79. self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
  80. self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
  81. self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
  82. return dsa.DSAParameterNumbers(
  83. p=self._backend._bn_to_int(p[0]),
  84. q=self._backend._bn_to_int(q[0]),
  85. g=self._backend._bn_to_int(g[0]),
  86. )
  87. def generate_private_key(self) -> dsa.DSAPrivateKey:
  88. return self._backend.generate_dsa_private_key(self)
  89. class _DSAPrivateKey(dsa.DSAPrivateKey):
  90. def __init__(self, backend, dsa_cdata, evp_pkey):
  91. self._backend = backend
  92. self._dsa_cdata = dsa_cdata
  93. self._evp_pkey = evp_pkey
  94. p = self._backend._ffi.new("BIGNUM **")
  95. self._backend._lib.DSA_get0_pqg(
  96. dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
  97. )
  98. self._backend.openssl_assert(p[0] != backend._ffi.NULL)
  99. self._key_size = self._backend._lib.BN_num_bits(p[0])
  100. key_size = utils.read_only_property("_key_size")
  101. def signer(
  102. self, signature_algorithm: hashes.HashAlgorithm
  103. ) -> AsymmetricSignatureContext:
  104. _warn_sign_verify_deprecated()
  105. _check_not_prehashed(signature_algorithm)
  106. return _DSASignatureContext(self._backend, self, signature_algorithm)
  107. def private_numbers(self) -> dsa.DSAPrivateNumbers:
  108. p = self._backend._ffi.new("BIGNUM **")
  109. q = self._backend._ffi.new("BIGNUM **")
  110. g = self._backend._ffi.new("BIGNUM **")
  111. pub_key = self._backend._ffi.new("BIGNUM **")
  112. priv_key = self._backend._ffi.new("BIGNUM **")
  113. self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
  114. self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
  115. self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
  116. self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
  117. self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key)
  118. self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
  119. self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL)
  120. return dsa.DSAPrivateNumbers(
  121. public_numbers=dsa.DSAPublicNumbers(
  122. parameter_numbers=dsa.DSAParameterNumbers(
  123. p=self._backend._bn_to_int(p[0]),
  124. q=self._backend._bn_to_int(q[0]),
  125. g=self._backend._bn_to_int(g[0]),
  126. ),
  127. y=self._backend._bn_to_int(pub_key[0]),
  128. ),
  129. x=self._backend._bn_to_int(priv_key[0]),
  130. )
  131. def public_key(self) -> dsa.DSAPublicKey:
  132. dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
  133. self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
  134. dsa_cdata = self._backend._ffi.gc(
  135. dsa_cdata, self._backend._lib.DSA_free
  136. )
  137. pub_key = self._backend._ffi.new("BIGNUM **")
  138. self._backend._lib.DSA_get0_key(
  139. self._dsa_cdata, pub_key, self._backend._ffi.NULL
  140. )
  141. self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
  142. pub_key_dup = self._backend._lib.BN_dup(pub_key[0])
  143. res = self._backend._lib.DSA_set0_key(
  144. dsa_cdata, pub_key_dup, self._backend._ffi.NULL
  145. )
  146. self._backend.openssl_assert(res == 1)
  147. evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata)
  148. return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey)
  149. def parameters(self) -> dsa.DSAParameters:
  150. dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
  151. self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
  152. dsa_cdata = self._backend._ffi.gc(
  153. dsa_cdata, self._backend._lib.DSA_free
  154. )
  155. return _DSAParameters(self._backend, dsa_cdata)
  156. def private_bytes(
  157. self,
  158. encoding: serialization.Encoding,
  159. format: serialization.PrivateFormat,
  160. encryption_algorithm: serialization.KeySerializationEncryption,
  161. ) -> bytes:
  162. return self._backend._private_key_bytes(
  163. encoding,
  164. format,
  165. encryption_algorithm,
  166. self,
  167. self._evp_pkey,
  168. self._dsa_cdata,
  169. )
  170. def sign(
  171. self,
  172. data: bytes,
  173. algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
  174. ) -> bytes:
  175. data, algorithm = _calculate_digest_and_algorithm(
  176. self._backend, data, algorithm
  177. )
  178. return _dsa_sig_sign(self._backend, self, data)
  179. class _DSAPublicKey(dsa.DSAPublicKey):
  180. def __init__(self, backend, dsa_cdata, evp_pkey):
  181. self._backend = backend
  182. self._dsa_cdata = dsa_cdata
  183. self._evp_pkey = evp_pkey
  184. p = self._backend._ffi.new("BIGNUM **")
  185. self._backend._lib.DSA_get0_pqg(
  186. dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
  187. )
  188. self._backend.openssl_assert(p[0] != backend._ffi.NULL)
  189. self._key_size = self._backend._lib.BN_num_bits(p[0])
  190. key_size = utils.read_only_property("_key_size")
  191. def verifier(
  192. self,
  193. signature: bytes,
  194. signature_algorithm: hashes.HashAlgorithm,
  195. ) -> AsymmetricVerificationContext:
  196. _warn_sign_verify_deprecated()
  197. utils._check_bytes("signature", signature)
  198. _check_not_prehashed(signature_algorithm)
  199. return _DSAVerificationContext(
  200. self._backend, self, signature, signature_algorithm
  201. )
  202. def public_numbers(self) -> dsa.DSAPublicNumbers:
  203. p = self._backend._ffi.new("BIGNUM **")
  204. q = self._backend._ffi.new("BIGNUM **")
  205. g = self._backend._ffi.new("BIGNUM **")
  206. pub_key = self._backend._ffi.new("BIGNUM **")
  207. self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
  208. self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
  209. self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
  210. self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
  211. self._backend._lib.DSA_get0_key(
  212. self._dsa_cdata, pub_key, self._backend._ffi.NULL
  213. )
  214. self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
  215. return dsa.DSAPublicNumbers(
  216. parameter_numbers=dsa.DSAParameterNumbers(
  217. p=self._backend._bn_to_int(p[0]),
  218. q=self._backend._bn_to_int(q[0]),
  219. g=self._backend._bn_to_int(g[0]),
  220. ),
  221. y=self._backend._bn_to_int(pub_key[0]),
  222. )
  223. def parameters(self) -> dsa.DSAParameters:
  224. dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
  225. dsa_cdata = self._backend._ffi.gc(
  226. dsa_cdata, self._backend._lib.DSA_free
  227. )
  228. return _DSAParameters(self._backend, dsa_cdata)
  229. def public_bytes(
  230. self,
  231. encoding: serialization.Encoding,
  232. format: serialization.PublicFormat,
  233. ) -> bytes:
  234. return self._backend._public_key_bytes(
  235. encoding, format, self, self._evp_pkey, None
  236. )
  237. def verify(
  238. self,
  239. signature: bytes,
  240. data: bytes,
  241. algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
  242. ) -> None:
  243. data, algorithm = _calculate_digest_and_algorithm(
  244. self._backend, data, algorithm
  245. )
  246. return _dsa_sig_verify(self._backend, self, signature, data)