xref: /freebsd/crypto/openssh/ssh-dss.c (revision a91a246563dffa876a52f53a98de4af9fa364c52)
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