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