1*a91a2465SEd Maste /* $OpenBSD: ssh-dss.c,v 1.50 2024/01/11 01:45:36 djm Exp $ */
21e8db6e2SBrian Feldman /*
31e8db6e2SBrian Feldman * Copyright (c) 2000 Markus Friedl. All rights reserved.
41e8db6e2SBrian Feldman *
51e8db6e2SBrian Feldman * Redistribution and use in source and binary forms, with or without
61e8db6e2SBrian Feldman * modification, are permitted provided that the following conditions
71e8db6e2SBrian Feldman * are met:
81e8db6e2SBrian Feldman * 1. Redistributions of source code must retain the above copyright
91e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer.
101e8db6e2SBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright
111e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer in the
121e8db6e2SBrian Feldman * documentation and/or other materials provided with the distribution.
131e8db6e2SBrian Feldman *
141e8db6e2SBrian Feldman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
151e8db6e2SBrian Feldman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
161e8db6e2SBrian Feldman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
171e8db6e2SBrian Feldman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
181e8db6e2SBrian Feldman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
191e8db6e2SBrian Feldman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201e8db6e2SBrian Feldman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
211e8db6e2SBrian Feldman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
221e8db6e2SBrian Feldman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
231e8db6e2SBrian Feldman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
241e8db6e2SBrian Feldman */
251e8db6e2SBrian Feldman
261e8db6e2SBrian Feldman #include "includes.h"
27761efaa7SDag-Erling Smørgrav
28*a91a2465SEd Maste #if defined(WITH_OPENSSL) && defined(WITH_DSA)
29bc5531deSDag-Erling Smørgrav
30761efaa7SDag-Erling Smørgrav #include <sys/types.h>
311e8db6e2SBrian Feldman
321e8db6e2SBrian Feldman #include <openssl/bn.h>
33a0ee8cc6SDag-Erling Smørgrav #include <openssl/dsa.h>
341e8db6e2SBrian Feldman #include <openssl/evp.h>
351e8db6e2SBrian Feldman
36761efaa7SDag-Erling Smørgrav #include <stdarg.h>
37761efaa7SDag-Erling Smørgrav #include <string.h>
38761efaa7SDag-Erling Smørgrav
39a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
40a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
41f7167e0eSDag-Erling Smørgrav #include "digest.h"
42a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL
43a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h"
441e8db6e2SBrian Feldman
452a01feabSEd Maste #include "openbsd-compat/openssl-compat.h"
462a01feabSEd Maste
471e8db6e2SBrian Feldman #define INTBLOB_LEN 20
481e8db6e2SBrian Feldman #define SIGBLOB_LEN (2*INTBLOB_LEN)
491e8db6e2SBrian Feldman
50f374ba41SEd Maste static u_int
ssh_dss_size(const struct sshkey * key)51f374ba41SEd Maste ssh_dss_size(const struct sshkey *key)
52f374ba41SEd Maste {
53f374ba41SEd Maste const BIGNUM *dsa_p;
54f374ba41SEd Maste
55f374ba41SEd Maste if (key->dsa == NULL)
56f374ba41SEd Maste return 0;
57f374ba41SEd Maste DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL);
58f374ba41SEd Maste return BN_num_bits(dsa_p);
59f374ba41SEd Maste }
60f374ba41SEd Maste
61f374ba41SEd Maste static int
ssh_dss_alloc(struct sshkey * k)62f374ba41SEd Maste ssh_dss_alloc(struct sshkey *k)
63f374ba41SEd Maste {
64f374ba41SEd Maste if ((k->dsa = DSA_new()) == NULL)
65f374ba41SEd Maste return SSH_ERR_ALLOC_FAIL;
66f374ba41SEd Maste return 0;
67f374ba41SEd Maste }
68f374ba41SEd Maste
69f374ba41SEd Maste static void
ssh_dss_cleanup(struct sshkey * k)70f374ba41SEd Maste ssh_dss_cleanup(struct sshkey *k)
71f374ba41SEd Maste {
72f374ba41SEd Maste DSA_free(k->dsa);
73f374ba41SEd Maste k->dsa = NULL;
74f374ba41SEd Maste }
75f374ba41SEd Maste
76f374ba41SEd Maste static int
ssh_dss_equal(const struct sshkey * a,const struct sshkey * b)77f374ba41SEd Maste ssh_dss_equal(const struct sshkey *a, const struct sshkey *b)
78f374ba41SEd Maste {
79f374ba41SEd Maste const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a;
80f374ba41SEd Maste const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b;
81f374ba41SEd Maste
82f374ba41SEd Maste if (a->dsa == NULL || b->dsa == NULL)
83f374ba41SEd Maste return 0;
84f374ba41SEd Maste DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a);
85f374ba41SEd Maste DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b);
86f374ba41SEd Maste DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL);
87f374ba41SEd Maste DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL);
88f374ba41SEd Maste if (dsa_p_a == NULL || dsa_p_b == NULL ||
89f374ba41SEd Maste dsa_q_a == NULL || dsa_q_b == NULL ||
90f374ba41SEd Maste dsa_g_a == NULL || dsa_g_b == NULL ||
91f374ba41SEd Maste dsa_pub_key_a == NULL || dsa_pub_key_b == NULL)
92f374ba41SEd Maste return 0;
93f374ba41SEd Maste if (BN_cmp(dsa_p_a, dsa_p_b) != 0)
94f374ba41SEd Maste return 0;
95f374ba41SEd Maste if (BN_cmp(dsa_q_a, dsa_q_b) != 0)
96f374ba41SEd Maste return 0;
97f374ba41SEd Maste if (BN_cmp(dsa_g_a, dsa_g_b) != 0)
98f374ba41SEd Maste return 0;
99f374ba41SEd Maste if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0)
100f374ba41SEd Maste return 0;
101f374ba41SEd Maste return 1;
102f374ba41SEd Maste }
103f374ba41SEd Maste
104f374ba41SEd Maste static int
ssh_dss_serialize_public(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)105f374ba41SEd Maste ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
106f374ba41SEd Maste enum sshkey_serialize_rep opts)
107f374ba41SEd Maste {
108f374ba41SEd Maste int r;
109f374ba41SEd Maste const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
110f374ba41SEd Maste
111f374ba41SEd Maste if (key->dsa == NULL)
112f374ba41SEd Maste return SSH_ERR_INVALID_ARGUMENT;
113f374ba41SEd Maste DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
114f374ba41SEd Maste DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
115f374ba41SEd Maste if (dsa_p == NULL || dsa_q == NULL ||
116f374ba41SEd Maste dsa_g == NULL || dsa_pub_key == NULL)
117f374ba41SEd Maste return SSH_ERR_INTERNAL_ERROR;
118f374ba41SEd Maste if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
119f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
120f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
121f374ba41SEd Maste (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
122f374ba41SEd Maste return r;
123f374ba41SEd Maste
124f374ba41SEd Maste return 0;
125f374ba41SEd Maste }
126f374ba41SEd Maste
127f374ba41SEd Maste static int
ssh_dss_serialize_private(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)128f374ba41SEd Maste ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b,
129f374ba41SEd Maste enum sshkey_serialize_rep opts)
130f374ba41SEd Maste {
131f374ba41SEd Maste int r;
132f374ba41SEd Maste const BIGNUM *dsa_priv_key;
133f374ba41SEd Maste
134f374ba41SEd Maste DSA_get0_key(key->dsa, NULL, &dsa_priv_key);
135f374ba41SEd Maste if (!sshkey_is_cert(key)) {
136f374ba41SEd Maste if ((r = ssh_dss_serialize_public(key, b, opts)) != 0)
137f374ba41SEd Maste return r;
138f374ba41SEd Maste }
139f374ba41SEd Maste if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
140f374ba41SEd Maste return r;
141f374ba41SEd Maste
142f374ba41SEd Maste return 0;
143f374ba41SEd Maste }
144f374ba41SEd Maste
145f374ba41SEd Maste static int
ssh_dss_generate(struct sshkey * k,int bits)146f374ba41SEd Maste ssh_dss_generate(struct sshkey *k, int bits)
147f374ba41SEd Maste {
148f374ba41SEd Maste DSA *private;
149f374ba41SEd Maste
150f374ba41SEd Maste if (bits != 1024)
151f374ba41SEd Maste return SSH_ERR_KEY_LENGTH;
152f374ba41SEd Maste if ((private = DSA_new()) == NULL)
153f374ba41SEd Maste return SSH_ERR_ALLOC_FAIL;
154f374ba41SEd Maste if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
155f374ba41SEd Maste NULL, NULL) || !DSA_generate_key(private)) {
156f374ba41SEd Maste DSA_free(private);
157f374ba41SEd Maste return SSH_ERR_LIBCRYPTO_ERROR;
158f374ba41SEd Maste }
159f374ba41SEd Maste k->dsa = private;
160f374ba41SEd Maste return 0;
161f374ba41SEd Maste }
162f374ba41SEd Maste
163f374ba41SEd Maste static int
ssh_dss_copy_public(const struct sshkey * from,struct sshkey * to)164f374ba41SEd Maste ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to)
165f374ba41SEd Maste {
166f374ba41SEd Maste const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
167f374ba41SEd Maste BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
168f374ba41SEd Maste BIGNUM *dsa_pub_key_dup = NULL;
169f374ba41SEd Maste int r = SSH_ERR_INTERNAL_ERROR;
170f374ba41SEd Maste
171f374ba41SEd Maste DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g);
172f374ba41SEd Maste DSA_get0_key(from->dsa, &dsa_pub_key, NULL);
173f374ba41SEd Maste if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
174f374ba41SEd Maste (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
175f374ba41SEd Maste (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
176f374ba41SEd Maste (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
177f374ba41SEd Maste r = SSH_ERR_ALLOC_FAIL;
178f374ba41SEd Maste goto out;
179f374ba41SEd Maste }
180f374ba41SEd Maste if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
181f374ba41SEd Maste r = SSH_ERR_LIBCRYPTO_ERROR;
182f374ba41SEd Maste goto out;
183f374ba41SEd Maste }
184f374ba41SEd Maste dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
185f374ba41SEd Maste if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) {
186f374ba41SEd Maste r = SSH_ERR_LIBCRYPTO_ERROR;
187f374ba41SEd Maste goto out;
188f374ba41SEd Maste }
189f374ba41SEd Maste dsa_pub_key_dup = NULL; /* transferred */
190f374ba41SEd Maste /* success */
191f374ba41SEd Maste r = 0;
192f374ba41SEd Maste out:
193f374ba41SEd Maste BN_clear_free(dsa_p_dup);
194f374ba41SEd Maste BN_clear_free(dsa_q_dup);
195f374ba41SEd Maste BN_clear_free(dsa_g_dup);
196f374ba41SEd Maste BN_clear_free(dsa_pub_key_dup);
197f374ba41SEd Maste return r;
198f374ba41SEd Maste }
199f374ba41SEd Maste
200f374ba41SEd Maste static int
ssh_dss_deserialize_public(const char * ktype,struct sshbuf * b,struct sshkey * key)201f374ba41SEd Maste ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b,
202f374ba41SEd Maste struct sshkey *key)
203f374ba41SEd Maste {
204f374ba41SEd Maste int ret = SSH_ERR_INTERNAL_ERROR;
205f374ba41SEd Maste BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
206f374ba41SEd Maste
207f374ba41SEd Maste if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
208f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_q) != 0 ||
209f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_g) != 0 ||
210f374ba41SEd Maste sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
211f374ba41SEd Maste ret = SSH_ERR_INVALID_FORMAT;
212f374ba41SEd Maste goto out;
213f374ba41SEd Maste }
214f374ba41SEd Maste if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
215f374ba41SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR;
216f374ba41SEd Maste goto out;
217f374ba41SEd Maste }
218f374ba41SEd Maste dsa_p = dsa_q = dsa_g = NULL; /* transferred */
219f374ba41SEd Maste if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
220f374ba41SEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR;
221f374ba41SEd Maste goto out;
222f374ba41SEd Maste }
223f374ba41SEd Maste dsa_pub_key = NULL; /* transferred */
224f374ba41SEd Maste #ifdef DEBUG_PK
225f374ba41SEd Maste DSA_print_fp(stderr, key->dsa, 8);
226f374ba41SEd Maste #endif
227f374ba41SEd Maste /* success */
228f374ba41SEd Maste ret = 0;
229f374ba41SEd Maste out:
230f374ba41SEd Maste BN_clear_free(dsa_p);
231f374ba41SEd Maste BN_clear_free(dsa_q);
232f374ba41SEd Maste BN_clear_free(dsa_g);
233f374ba41SEd Maste BN_clear_free(dsa_pub_key);
234f374ba41SEd Maste return ret;
235f374ba41SEd Maste }
236f374ba41SEd Maste
237f374ba41SEd Maste static int
ssh_dss_deserialize_private(const char * ktype,struct sshbuf * b,struct sshkey * key)238f374ba41SEd Maste ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b,
239f374ba41SEd Maste struct sshkey *key)
240f374ba41SEd Maste {
241f374ba41SEd Maste int r;
242f374ba41SEd Maste BIGNUM *dsa_priv_key = NULL;
243f374ba41SEd Maste
244f374ba41SEd Maste if (!sshkey_is_cert(key)) {
245f374ba41SEd Maste if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0)
246f374ba41SEd Maste return r;
247f374ba41SEd Maste }
248f374ba41SEd Maste
249f374ba41SEd Maste if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0)
250f374ba41SEd Maste return r;
251f374ba41SEd Maste if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) {
252f374ba41SEd Maste BN_clear_free(dsa_priv_key);
253f374ba41SEd Maste return SSH_ERR_LIBCRYPTO_ERROR;
254f374ba41SEd Maste }
255f374ba41SEd Maste return 0;
256f374ba41SEd Maste }
257f374ba41SEd Maste
258f374ba41SEd Maste static int
ssh_dss_sign(struct sshkey * key,u_char ** sigp,size_t * lenp,const u_char * data,size_t datalen,const char * alg,const char * sk_provider,const char * sk_pin,u_int compat)259f374ba41SEd Maste ssh_dss_sign(struct sshkey *key,
260f374ba41SEd Maste u_char **sigp, size_t *lenp,
261f374ba41SEd Maste const u_char *data, size_t datalen,
262f374ba41SEd Maste const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
2631e8db6e2SBrian Feldman {
264a0ee8cc6SDag-Erling Smørgrav DSA_SIG *sig = NULL;
2652a01feabSEd Maste const BIGNUM *sig_r, *sig_s;
266f7167e0eSDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
267a0ee8cc6SDag-Erling Smørgrav size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
268a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL;
269a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INVALID_ARGUMENT;
2701e8db6e2SBrian Feldman
271a0ee8cc6SDag-Erling Smørgrav if (lenp != NULL)
272a0ee8cc6SDag-Erling Smørgrav *lenp = 0;
273a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL)
274a0ee8cc6SDag-Erling Smørgrav *sigp = NULL;
275f7167e0eSDag-Erling Smørgrav
276a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL ||
277a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA)
278a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT;
279a0ee8cc6SDag-Erling Smørgrav if (dlen == 0)
280a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR;
2811e8db6e2SBrian Feldman
282a0ee8cc6SDag-Erling Smørgrav if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
283a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0)
284a0ee8cc6SDag-Erling Smørgrav goto out;
285ae1f160dSDag-Erling Smørgrav
286a0ee8cc6SDag-Erling Smørgrav if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
287a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR;
288a0ee8cc6SDag-Erling Smørgrav goto out;
2891e8db6e2SBrian Feldman }
2901e8db6e2SBrian Feldman
2912a01feabSEd Maste DSA_SIG_get0(sig, &sig_r, &sig_s);
2922a01feabSEd Maste rlen = BN_num_bytes(sig_r);
2932a01feabSEd Maste slen = BN_num_bytes(sig_s);
2941e8db6e2SBrian Feldman if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
295a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INTERNAL_ERROR;
296a0ee8cc6SDag-Erling Smørgrav goto out;
2971e8db6e2SBrian Feldman }
298b83788ffSDag-Erling Smørgrav explicit_bzero(sigblob, SIGBLOB_LEN);
2992a01feabSEd Maste BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
3002a01feabSEd Maste BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen);
3011e8db6e2SBrian Feldman
302a0ee8cc6SDag-Erling Smørgrav if ((b = sshbuf_new()) == NULL) {
303a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL;
304a0ee8cc6SDag-Erling Smørgrav goto out;
305a0ee8cc6SDag-Erling Smørgrav }
306a0ee8cc6SDag-Erling Smørgrav if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
307a0ee8cc6SDag-Erling Smørgrav (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
308a0ee8cc6SDag-Erling Smørgrav goto out;
30947dd1d1bSDag-Erling Smørgrav
310a0ee8cc6SDag-Erling Smørgrav len = sshbuf_len(b);
311a0ee8cc6SDag-Erling Smørgrav if (sigp != NULL) {
312a0ee8cc6SDag-Erling Smørgrav if ((*sigp = malloc(len)) == NULL) {
313a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL;
314a0ee8cc6SDag-Erling Smørgrav goto out;
315a0ee8cc6SDag-Erling Smørgrav }
316a0ee8cc6SDag-Erling Smørgrav memcpy(*sigp, sshbuf_ptr(b), len);
317a0ee8cc6SDag-Erling Smørgrav }
3181e8db6e2SBrian Feldman if (lenp != NULL)
3191e8db6e2SBrian Feldman *lenp = len;
320a0ee8cc6SDag-Erling Smørgrav ret = 0;
321a0ee8cc6SDag-Erling Smørgrav out:
322a0ee8cc6SDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest));
323a0ee8cc6SDag-Erling Smørgrav DSA_SIG_free(sig);
324a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b);
325a0ee8cc6SDag-Erling Smørgrav return ret;
3261e8db6e2SBrian Feldman }
3271e8db6e2SBrian Feldman
328f374ba41SEd Maste static int
ssh_dss_verify(const struct sshkey * key,const u_char * sig,size_t siglen,const u_char * data,size_t dlen,const char * alg,u_int compat,struct sshkey_sig_details ** detailsp)329a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key,
330f374ba41SEd Maste const u_char *sig, size_t siglen,
331f374ba41SEd Maste const u_char *data, size_t dlen, const char *alg, u_int compat,
332f374ba41SEd Maste struct sshkey_sig_details **detailsp)
333a0ee8cc6SDag-Erling Smørgrav {
334f374ba41SEd Maste DSA_SIG *dsig = NULL;
3352a01feabSEd Maste BIGNUM *sig_r = NULL, *sig_s = NULL;
336a0ee8cc6SDag-Erling Smørgrav u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
337f374ba41SEd Maste size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
338a0ee8cc6SDag-Erling Smørgrav int ret = SSH_ERR_INTERNAL_ERROR;
339a0ee8cc6SDag-Erling Smørgrav struct sshbuf *b = NULL;
340a0ee8cc6SDag-Erling Smørgrav char *ktype = NULL;
341a0ee8cc6SDag-Erling Smørgrav
342a0ee8cc6SDag-Erling Smørgrav if (key == NULL || key->dsa == NULL ||
343076ad2f8SDag-Erling Smørgrav sshkey_type_plain(key->type) != KEY_DSA ||
344f374ba41SEd Maste sig == NULL || siglen == 0)
345a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INVALID_ARGUMENT;
346f374ba41SEd Maste if (hlen == 0)
347a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_INTERNAL_ERROR;
3481e8db6e2SBrian Feldman
3491e8db6e2SBrian Feldman /* fetch signature */
350f374ba41SEd Maste if ((b = sshbuf_from(sig, siglen)) == NULL)
351a0ee8cc6SDag-Erling Smørgrav return SSH_ERR_ALLOC_FAIL;
352a0ee8cc6SDag-Erling Smørgrav if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
353a0ee8cc6SDag-Erling Smørgrav sshbuf_get_string(b, &sigblob, &len) != 0) {
354a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT;
355a0ee8cc6SDag-Erling Smørgrav goto out;
356ae1f160dSDag-Erling Smørgrav }
357a0ee8cc6SDag-Erling Smørgrav if (strcmp("ssh-dss", ktype) != 0) {
358a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_KEY_TYPE_MISMATCH;
359a0ee8cc6SDag-Erling Smørgrav goto out;
360a0ee8cc6SDag-Erling Smørgrav }
361a0ee8cc6SDag-Erling Smørgrav if (sshbuf_len(b) != 0) {
362a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
363a0ee8cc6SDag-Erling Smørgrav goto out;
364ae1f160dSDag-Erling Smørgrav }
3651e8db6e2SBrian Feldman
3661e8db6e2SBrian Feldman if (len != SIGBLOB_LEN) {
367a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_INVALID_FORMAT;
368a0ee8cc6SDag-Erling Smørgrav goto out;
3691e8db6e2SBrian Feldman }
3701e8db6e2SBrian Feldman
3711e8db6e2SBrian Feldman /* parse signature */
372f374ba41SEd Maste if ((dsig = DSA_SIG_new()) == NULL ||
3732a01feabSEd Maste (sig_r = BN_new()) == NULL ||
3742a01feabSEd Maste (sig_s = BN_new()) == NULL) {
375a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_ALLOC_FAIL;
376a0ee8cc6SDag-Erling Smørgrav goto out;
377a0ee8cc6SDag-Erling Smørgrav }
3782a01feabSEd Maste if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
3792a01feabSEd Maste (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
380a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR;
381a0ee8cc6SDag-Erling Smørgrav goto out;
382f7167e0eSDag-Erling Smørgrav }
383f374ba41SEd Maste if (!DSA_SIG_set0(dsig, sig_r, sig_s)) {
3842a01feabSEd Maste ret = SSH_ERR_LIBCRYPTO_ERROR;
3852a01feabSEd Maste goto out;
3862a01feabSEd Maste }
3872a01feabSEd Maste sig_r = sig_s = NULL; /* transferred */
3881e8db6e2SBrian Feldman
389a0ee8cc6SDag-Erling Smørgrav /* sha1 the data */
390f374ba41SEd Maste if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen,
391a0ee8cc6SDag-Erling Smørgrav digest, sizeof(digest))) != 0)
392a0ee8cc6SDag-Erling Smørgrav goto out;
393a0ee8cc6SDag-Erling Smørgrav
394f374ba41SEd Maste switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) {
395a0ee8cc6SDag-Erling Smørgrav case 1:
396a0ee8cc6SDag-Erling Smørgrav ret = 0;
397a0ee8cc6SDag-Erling Smørgrav break;
398a0ee8cc6SDag-Erling Smørgrav case 0:
399a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_SIGNATURE_INVALID;
400a0ee8cc6SDag-Erling Smørgrav goto out;
401a0ee8cc6SDag-Erling Smørgrav default:
402a0ee8cc6SDag-Erling Smørgrav ret = SSH_ERR_LIBCRYPTO_ERROR;
403a0ee8cc6SDag-Erling Smørgrav goto out;
404a0ee8cc6SDag-Erling Smørgrav }
405a0ee8cc6SDag-Erling Smørgrav
406a0ee8cc6SDag-Erling Smørgrav out:
407b83788ffSDag-Erling Smørgrav explicit_bzero(digest, sizeof(digest));
408f374ba41SEd Maste DSA_SIG_free(dsig);
4092a01feabSEd Maste BN_clear_free(sig_r);
4102a01feabSEd Maste BN_clear_free(sig_s);
411a0ee8cc6SDag-Erling Smørgrav sshbuf_free(b);
412a0ee8cc6SDag-Erling Smørgrav free(ktype);
41319261079SEd Maste if (sigblob != NULL)
41419261079SEd Maste freezero(sigblob, len);
4151e8db6e2SBrian Feldman return ret;
4161e8db6e2SBrian Feldman }
417f374ba41SEd Maste
418f374ba41SEd Maste static const struct sshkey_impl_funcs sshkey_dss_funcs = {
419f374ba41SEd Maste /* .size = */ ssh_dss_size,
420f374ba41SEd Maste /* .alloc = */ ssh_dss_alloc,
421f374ba41SEd Maste /* .cleanup = */ ssh_dss_cleanup,
422f374ba41SEd Maste /* .equal = */ ssh_dss_equal,
423f374ba41SEd Maste /* .ssh_serialize_public = */ ssh_dss_serialize_public,
424f374ba41SEd Maste /* .ssh_deserialize_public = */ ssh_dss_deserialize_public,
425f374ba41SEd Maste /* .ssh_serialize_private = */ ssh_dss_serialize_private,
426f374ba41SEd Maste /* .ssh_deserialize_private = */ ssh_dss_deserialize_private,
427f374ba41SEd Maste /* .generate = */ ssh_dss_generate,
428f374ba41SEd Maste /* .copy_public = */ ssh_dss_copy_public,
429f374ba41SEd Maste /* .sign = */ ssh_dss_sign,
430f374ba41SEd Maste /* .verify = */ ssh_dss_verify,
431f374ba41SEd Maste };
432f374ba41SEd Maste
433f374ba41SEd Maste const struct sshkey_impl sshkey_dss_impl = {
434f374ba41SEd Maste /* .name = */ "ssh-dss",
435f374ba41SEd Maste /* .shortname = */ "DSA",
436f374ba41SEd Maste /* .sigalg = */ NULL,
437f374ba41SEd Maste /* .type = */ KEY_DSA,
438f374ba41SEd Maste /* .nid = */ 0,
439f374ba41SEd Maste /* .cert = */ 0,
440f374ba41SEd Maste /* .sigonly = */ 0,
441f374ba41SEd Maste /* .keybits = */ 0,
442f374ba41SEd Maste /* .funcs = */ &sshkey_dss_funcs,
443f374ba41SEd Maste };
444f374ba41SEd Maste
445f374ba41SEd Maste const struct sshkey_impl sshkey_dsa_cert_impl = {
446f374ba41SEd Maste /* .name = */ "ssh-dss-cert-v01@openssh.com",
447f374ba41SEd Maste /* .shortname = */ "DSA-CERT",
448f374ba41SEd Maste /* .sigalg = */ NULL,
449f374ba41SEd Maste /* .type = */ KEY_DSA_CERT,
450f374ba41SEd Maste /* .nid = */ 0,
451f374ba41SEd Maste /* .cert = */ 1,
452f374ba41SEd Maste /* .sigonly = */ 0,
453f374ba41SEd Maste /* .keybits = */ 0,
454f374ba41SEd Maste /* .funcs = */ &sshkey_dss_funcs,
455f374ba41SEd Maste };
456*a91a2465SEd Maste
457*a91a2465SEd Maste #endif /* WITH_OPENSSL && WITH_DSA */
458