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