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