xref: /freebsd/crypto/openssh/ssh-dss.c (revision f374ba41f55c1a127303d92d830dd58eef2f5243)
1*f374ba41SEd Maste /* $OpenBSD: ssh-dss.c,v 1.48 2022/10/28 00:44:44 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 
28bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL
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"
401e8db6e2SBrian Feldman #include "compat.h"
41a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
42f7167e0eSDag-Erling Smørgrav #include "digest.h"
43a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL
44a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h"
451e8db6e2SBrian Feldman 
462a01feabSEd Maste #include "openbsd-compat/openssl-compat.h"
472a01feabSEd Maste 
481e8db6e2SBrian Feldman #define INTBLOB_LEN	20
491e8db6e2SBrian Feldman #define SIGBLOB_LEN	(2*INTBLOB_LEN)
501e8db6e2SBrian Feldman 
51*f374ba41SEd Maste static u_int
52*f374ba41SEd Maste ssh_dss_size(const struct sshkey *key)
53*f374ba41SEd Maste {
54*f374ba41SEd Maste 	const BIGNUM *dsa_p;
55*f374ba41SEd Maste 
56*f374ba41SEd Maste 	if (key->dsa == NULL)
57*f374ba41SEd Maste 		return 0;
58*f374ba41SEd Maste 	DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL);
59*f374ba41SEd Maste 	return BN_num_bits(dsa_p);
60*f374ba41SEd Maste }
61*f374ba41SEd Maste 
62*f374ba41SEd Maste static int
63*f374ba41SEd Maste ssh_dss_alloc(struct sshkey *k)
64*f374ba41SEd Maste {
65*f374ba41SEd Maste 	if ((k->dsa = DSA_new()) == NULL)
66*f374ba41SEd Maste 		return SSH_ERR_ALLOC_FAIL;
67*f374ba41SEd Maste 	return 0;
68*f374ba41SEd Maste }
69*f374ba41SEd Maste 
70*f374ba41SEd Maste static void
71*f374ba41SEd Maste ssh_dss_cleanup(struct sshkey *k)
72*f374ba41SEd Maste {
73*f374ba41SEd Maste 	DSA_free(k->dsa);
74*f374ba41SEd Maste 	k->dsa = NULL;
75*f374ba41SEd Maste }
76*f374ba41SEd Maste 
77*f374ba41SEd Maste static int
78*f374ba41SEd Maste ssh_dss_equal(const struct sshkey *a, const struct sshkey *b)
79*f374ba41SEd Maste {
80*f374ba41SEd Maste 	const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a;
81*f374ba41SEd Maste 	const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b;
82*f374ba41SEd Maste 
83*f374ba41SEd Maste 	if (a->dsa == NULL || b->dsa == NULL)
84*f374ba41SEd Maste 		return 0;
85*f374ba41SEd Maste 	DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a);
86*f374ba41SEd Maste 	DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b);
87*f374ba41SEd Maste 	DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL);
88*f374ba41SEd Maste 	DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL);
89*f374ba41SEd Maste 	if (dsa_p_a == NULL || dsa_p_b == NULL ||
90*f374ba41SEd Maste 	    dsa_q_a == NULL || dsa_q_b == NULL ||
91*f374ba41SEd Maste 	    dsa_g_a == NULL || dsa_g_b == NULL ||
92*f374ba41SEd Maste 	    dsa_pub_key_a == NULL || dsa_pub_key_b == NULL)
93*f374ba41SEd Maste 		return 0;
94*f374ba41SEd Maste 	if (BN_cmp(dsa_p_a, dsa_p_b) != 0)
95*f374ba41SEd Maste 		return 0;
96*f374ba41SEd Maste 	if (BN_cmp(dsa_q_a, dsa_q_b) != 0)
97*f374ba41SEd Maste 		return 0;
98*f374ba41SEd Maste 	if (BN_cmp(dsa_g_a, dsa_g_b) != 0)
99*f374ba41SEd Maste 		return 0;
100*f374ba41SEd Maste 	if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0)
101*f374ba41SEd Maste 		return 0;
102*f374ba41SEd Maste 	return 1;
103*f374ba41SEd Maste }
104*f374ba41SEd Maste 
105*f374ba41SEd Maste static int
106*f374ba41SEd Maste ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
107*f374ba41SEd Maste     enum sshkey_serialize_rep opts)
108*f374ba41SEd Maste {
109*f374ba41SEd Maste 	int r;
110*f374ba41SEd Maste 	const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
111*f374ba41SEd Maste 
112*f374ba41SEd Maste 	if (key->dsa == NULL)
113*f374ba41SEd Maste 		return SSH_ERR_INVALID_ARGUMENT;
114*f374ba41SEd Maste 	DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
115*f374ba41SEd Maste 	DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
116*f374ba41SEd Maste 	if (dsa_p == NULL || dsa_q == NULL ||
117*f374ba41SEd Maste 	    dsa_g == NULL || dsa_pub_key == NULL)
118*f374ba41SEd Maste 		return SSH_ERR_INTERNAL_ERROR;
119*f374ba41SEd Maste 	if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
120*f374ba41SEd Maste 	    (r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
121*f374ba41SEd Maste 	    (r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
122*f374ba41SEd Maste 	    (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
123*f374ba41SEd Maste 		return r;
124*f374ba41SEd Maste 
125*f374ba41SEd Maste 	return 0;
126*f374ba41SEd Maste }
127*f374ba41SEd Maste 
128*f374ba41SEd Maste static int
129*f374ba41SEd Maste ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b,
130*f374ba41SEd Maste     enum sshkey_serialize_rep opts)
131*f374ba41SEd Maste {
132*f374ba41SEd Maste 	int r;
133*f374ba41SEd Maste 	const BIGNUM *dsa_priv_key;
134*f374ba41SEd Maste 
135*f374ba41SEd Maste 	DSA_get0_key(key->dsa, NULL, &dsa_priv_key);
136*f374ba41SEd Maste 	if (!sshkey_is_cert(key)) {
137*f374ba41SEd Maste 		if ((r = ssh_dss_serialize_public(key, b, opts)) != 0)
138*f374ba41SEd Maste 			return r;
139*f374ba41SEd Maste 	}
140*f374ba41SEd Maste 	if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
141*f374ba41SEd Maste 		return r;
142*f374ba41SEd Maste 
143*f374ba41SEd Maste 	return 0;
144*f374ba41SEd Maste }
145*f374ba41SEd Maste 
146*f374ba41SEd Maste static int
147*f374ba41SEd Maste ssh_dss_generate(struct sshkey *k, int bits)
148*f374ba41SEd Maste {
149*f374ba41SEd Maste 	DSA *private;
150*f374ba41SEd Maste 
151*f374ba41SEd Maste 	if (bits != 1024)
152*f374ba41SEd Maste 		return SSH_ERR_KEY_LENGTH;
153*f374ba41SEd Maste 	if ((private = DSA_new()) == NULL)
154*f374ba41SEd Maste 		return SSH_ERR_ALLOC_FAIL;
155*f374ba41SEd Maste 	if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
156*f374ba41SEd Maste 	    NULL, NULL) || !DSA_generate_key(private)) {
157*f374ba41SEd Maste 		DSA_free(private);
158*f374ba41SEd Maste 		return SSH_ERR_LIBCRYPTO_ERROR;
159*f374ba41SEd Maste 	}
160*f374ba41SEd Maste 	k->dsa = private;
161*f374ba41SEd Maste 	return 0;
162*f374ba41SEd Maste }
163*f374ba41SEd Maste 
164*f374ba41SEd Maste static int
165*f374ba41SEd Maste ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to)
166*f374ba41SEd Maste {
167*f374ba41SEd Maste 	const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
168*f374ba41SEd Maste 	BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
169*f374ba41SEd Maste 	BIGNUM *dsa_pub_key_dup = NULL;
170*f374ba41SEd Maste 	int r = SSH_ERR_INTERNAL_ERROR;
171*f374ba41SEd Maste 
172*f374ba41SEd Maste 	DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g);
173*f374ba41SEd Maste 	DSA_get0_key(from->dsa, &dsa_pub_key, NULL);
174*f374ba41SEd Maste 	if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
175*f374ba41SEd Maste 	    (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
176*f374ba41SEd Maste 	    (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
177*f374ba41SEd Maste 	    (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
178*f374ba41SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
179*f374ba41SEd Maste 		goto out;
180*f374ba41SEd Maste 	}
181*f374ba41SEd Maste 	if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
182*f374ba41SEd Maste 		r = SSH_ERR_LIBCRYPTO_ERROR;
183*f374ba41SEd Maste 		goto out;
184*f374ba41SEd Maste 	}
185*f374ba41SEd Maste 	dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
186*f374ba41SEd Maste 	if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) {
187*f374ba41SEd Maste 		r = SSH_ERR_LIBCRYPTO_ERROR;
188*f374ba41SEd Maste 		goto out;
189*f374ba41SEd Maste 	}
190*f374ba41SEd Maste 	dsa_pub_key_dup = NULL; /* transferred */
191*f374ba41SEd Maste 	/* success */
192*f374ba41SEd Maste 	r = 0;
193*f374ba41SEd Maste  out:
194*f374ba41SEd Maste 	BN_clear_free(dsa_p_dup);
195*f374ba41SEd Maste 	BN_clear_free(dsa_q_dup);
196*f374ba41SEd Maste 	BN_clear_free(dsa_g_dup);
197*f374ba41SEd Maste 	BN_clear_free(dsa_pub_key_dup);
198*f374ba41SEd Maste 	return r;
199*f374ba41SEd Maste }
200*f374ba41SEd Maste 
201*f374ba41SEd Maste static int
202*f374ba41SEd Maste ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b,
203*f374ba41SEd Maste     struct sshkey *key)
204*f374ba41SEd Maste {
205*f374ba41SEd Maste 	int ret = SSH_ERR_INTERNAL_ERROR;
206*f374ba41SEd Maste 	BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
207*f374ba41SEd Maste 
208*f374ba41SEd Maste 	if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
209*f374ba41SEd Maste 	    sshbuf_get_bignum2(b, &dsa_q) != 0 ||
210*f374ba41SEd Maste 	    sshbuf_get_bignum2(b, &dsa_g) != 0 ||
211*f374ba41SEd Maste 	    sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
212*f374ba41SEd Maste 		ret = SSH_ERR_INVALID_FORMAT;
213*f374ba41SEd Maste 		goto out;
214*f374ba41SEd Maste 	}
215*f374ba41SEd Maste 	if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
216*f374ba41SEd Maste 		ret = SSH_ERR_LIBCRYPTO_ERROR;
217*f374ba41SEd Maste 		goto out;
218*f374ba41SEd Maste 	}
219*f374ba41SEd Maste 	dsa_p = dsa_q = dsa_g = NULL; /* transferred */
220*f374ba41SEd Maste 	if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
221*f374ba41SEd Maste 		ret = SSH_ERR_LIBCRYPTO_ERROR;
222*f374ba41SEd Maste 		goto out;
223*f374ba41SEd Maste 	}
224*f374ba41SEd Maste 	dsa_pub_key = NULL; /* transferred */
225*f374ba41SEd Maste #ifdef DEBUG_PK
226*f374ba41SEd Maste 	DSA_print_fp(stderr, key->dsa, 8);
227*f374ba41SEd Maste #endif
228*f374ba41SEd Maste 	/* success */
229*f374ba41SEd Maste 	ret = 0;
230*f374ba41SEd Maste  out:
231*f374ba41SEd Maste 	BN_clear_free(dsa_p);
232*f374ba41SEd Maste 	BN_clear_free(dsa_q);
233*f374ba41SEd Maste 	BN_clear_free(dsa_g);
234*f374ba41SEd Maste 	BN_clear_free(dsa_pub_key);
235*f374ba41SEd Maste 	return ret;
236*f374ba41SEd Maste }
237*f374ba41SEd Maste 
238*f374ba41SEd Maste static int
239*f374ba41SEd Maste ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b,
240*f374ba41SEd Maste     struct sshkey *key)
241*f374ba41SEd Maste {
242*f374ba41SEd Maste 	int r;
243*f374ba41SEd Maste 	BIGNUM *dsa_priv_key = NULL;
244*f374ba41SEd Maste 
245*f374ba41SEd Maste 	if (!sshkey_is_cert(key)) {
246*f374ba41SEd Maste 		if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0)
247*f374ba41SEd Maste 			return r;
248*f374ba41SEd Maste 	}
249*f374ba41SEd Maste 
250*f374ba41SEd Maste 	if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0)
251*f374ba41SEd Maste 		return r;
252*f374ba41SEd Maste 	if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) {
253*f374ba41SEd Maste 		BN_clear_free(dsa_priv_key);
254*f374ba41SEd Maste 		return SSH_ERR_LIBCRYPTO_ERROR;
255*f374ba41SEd Maste 	}
256*f374ba41SEd Maste 	return 0;
257*f374ba41SEd Maste }
258*f374ba41SEd Maste 
259*f374ba41SEd Maste static int
260*f374ba41SEd Maste ssh_dss_sign(struct sshkey *key,
261*f374ba41SEd Maste     u_char **sigp, size_t *lenp,
262*f374ba41SEd Maste     const u_char *data, size_t datalen,
263*f374ba41SEd Maste     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
2641e8db6e2SBrian Feldman {
265a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG *sig = NULL;
2662a01feabSEd Maste 	const BIGNUM *sig_r, *sig_s;
267f7167e0eSDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
268a0ee8cc6SDag-Erling Smørgrav 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
269a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
270a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INVALID_ARGUMENT;
2711e8db6e2SBrian Feldman 
272a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
273a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
274a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL)
275a0ee8cc6SDag-Erling Smørgrav 		*sigp = NULL;
276f7167e0eSDag-Erling Smørgrav 
277a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
278a0ee8cc6SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA)
279a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
280a0ee8cc6SDag-Erling Smørgrav 	if (dlen == 0)
281a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
2821e8db6e2SBrian Feldman 
283a0ee8cc6SDag-Erling Smørgrav 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
284a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
285a0ee8cc6SDag-Erling Smørgrav 		goto out;
286ae1f160dSDag-Erling Smørgrav 
287a0ee8cc6SDag-Erling Smørgrav 	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
288a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
289a0ee8cc6SDag-Erling Smørgrav 		goto out;
2901e8db6e2SBrian Feldman 	}
2911e8db6e2SBrian Feldman 
2922a01feabSEd Maste 	DSA_SIG_get0(sig, &sig_r, &sig_s);
2932a01feabSEd Maste 	rlen = BN_num_bytes(sig_r);
2942a01feabSEd Maste 	slen = BN_num_bytes(sig_s);
2951e8db6e2SBrian Feldman 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
296a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INTERNAL_ERROR;
297a0ee8cc6SDag-Erling Smørgrav 		goto out;
2981e8db6e2SBrian Feldman 	}
299b83788ffSDag-Erling Smørgrav 	explicit_bzero(sigblob, SIGBLOB_LEN);
3002a01feabSEd Maste 	BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
3012a01feabSEd Maste 	BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen);
3021e8db6e2SBrian Feldman 
303a0ee8cc6SDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL) {
304a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
305a0ee8cc6SDag-Erling Smørgrav 		goto out;
306a0ee8cc6SDag-Erling Smørgrav 	}
307a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
308a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
309a0ee8cc6SDag-Erling Smørgrav 		goto out;
31047dd1d1bSDag-Erling Smørgrav 
311a0ee8cc6SDag-Erling Smørgrav 	len = sshbuf_len(b);
312a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL) {
313a0ee8cc6SDag-Erling Smørgrav 		if ((*sigp = malloc(len)) == NULL) {
314a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
315a0ee8cc6SDag-Erling Smørgrav 			goto out;
316a0ee8cc6SDag-Erling Smørgrav 		}
317a0ee8cc6SDag-Erling Smørgrav 		memcpy(*sigp, sshbuf_ptr(b), len);
318a0ee8cc6SDag-Erling Smørgrav 	}
3191e8db6e2SBrian Feldman 	if (lenp != NULL)
3201e8db6e2SBrian Feldman 		*lenp = len;
321a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
322a0ee8cc6SDag-Erling Smørgrav  out:
323a0ee8cc6SDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
324a0ee8cc6SDag-Erling Smørgrav 	DSA_SIG_free(sig);
325a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(b);
326a0ee8cc6SDag-Erling Smørgrav 	return ret;
3271e8db6e2SBrian Feldman }
3281e8db6e2SBrian Feldman 
329*f374ba41SEd Maste static int
330a0ee8cc6SDag-Erling Smørgrav ssh_dss_verify(const struct sshkey *key,
331*f374ba41SEd Maste     const u_char *sig, size_t siglen,
332*f374ba41SEd Maste     const u_char *data, size_t dlen, const char *alg, u_int compat,
333*f374ba41SEd Maste     struct sshkey_sig_details **detailsp)
334a0ee8cc6SDag-Erling Smørgrav {
335*f374ba41SEd Maste 	DSA_SIG *dsig = NULL;
3362a01feabSEd Maste 	BIGNUM *sig_r = NULL, *sig_s = NULL;
337a0ee8cc6SDag-Erling Smørgrav 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
338*f374ba41SEd Maste 	size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
339a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
340a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
341a0ee8cc6SDag-Erling Smørgrav 	char *ktype = NULL;
342a0ee8cc6SDag-Erling Smørgrav 
343a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL || key->dsa == NULL ||
344076ad2f8SDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_DSA ||
345*f374ba41SEd Maste 	    sig == NULL || siglen == 0)
346a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
347*f374ba41SEd Maste 	if (hlen == 0)
348a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
3491e8db6e2SBrian Feldman 
3501e8db6e2SBrian Feldman 	/* fetch signature */
351*f374ba41SEd Maste 	if ((b = sshbuf_from(sig, siglen)) == NULL)
352a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
353a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
354a0ee8cc6SDag-Erling Smørgrav 	    sshbuf_get_string(b, &sigblob, &len) != 0) {
355a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
356a0ee8cc6SDag-Erling Smørgrav 		goto out;
357ae1f160dSDag-Erling Smørgrav 	}
358a0ee8cc6SDag-Erling Smørgrav 	if (strcmp("ssh-dss", ktype) != 0) {
359a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_TYPE_MISMATCH;
360a0ee8cc6SDag-Erling Smørgrav 		goto out;
361a0ee8cc6SDag-Erling Smørgrav 	}
362a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(b) != 0) {
363a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
364a0ee8cc6SDag-Erling Smørgrav 		goto out;
365ae1f160dSDag-Erling Smørgrav 	}
3661e8db6e2SBrian Feldman 
3671e8db6e2SBrian Feldman 	if (len != SIGBLOB_LEN) {
368a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
369a0ee8cc6SDag-Erling Smørgrav 		goto out;
3701e8db6e2SBrian Feldman 	}
3711e8db6e2SBrian Feldman 
3721e8db6e2SBrian Feldman 	/* parse signature */
373*f374ba41SEd Maste 	if ((dsig = DSA_SIG_new()) == NULL ||
3742a01feabSEd Maste 	    (sig_r = BN_new()) == NULL ||
3752a01feabSEd Maste 	    (sig_s = BN_new()) == NULL) {
376a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
377a0ee8cc6SDag-Erling Smørgrav 		goto out;
378a0ee8cc6SDag-Erling Smørgrav 	}
3792a01feabSEd Maste 	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
3802a01feabSEd Maste 	    (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
381a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
382a0ee8cc6SDag-Erling Smørgrav 		goto out;
383f7167e0eSDag-Erling Smørgrav 	}
384*f374ba41SEd Maste 	if (!DSA_SIG_set0(dsig, sig_r, sig_s)) {
3852a01feabSEd Maste 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3862a01feabSEd Maste 		goto out;
3872a01feabSEd Maste 	}
3882a01feabSEd Maste 	sig_r = sig_s = NULL; /* transferred */
3891e8db6e2SBrian Feldman 
390a0ee8cc6SDag-Erling Smørgrav 	/* sha1 the data */
391*f374ba41SEd Maste 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen,
392a0ee8cc6SDag-Erling Smørgrav 	    digest, sizeof(digest))) != 0)
393a0ee8cc6SDag-Erling Smørgrav 		goto out;
394a0ee8cc6SDag-Erling Smørgrav 
395*f374ba41SEd Maste 	switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) {
396a0ee8cc6SDag-Erling Smørgrav 	case 1:
397a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
398a0ee8cc6SDag-Erling Smørgrav 		break;
399a0ee8cc6SDag-Erling Smørgrav 	case 0:
400a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_SIGNATURE_INVALID;
401a0ee8cc6SDag-Erling Smørgrav 		goto out;
402a0ee8cc6SDag-Erling Smørgrav 	default:
403a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
404a0ee8cc6SDag-Erling Smørgrav 		goto out;
405a0ee8cc6SDag-Erling Smørgrav 	}
406a0ee8cc6SDag-Erling Smørgrav 
407a0ee8cc6SDag-Erling Smørgrav  out:
408b83788ffSDag-Erling Smørgrav 	explicit_bzero(digest, sizeof(digest));
409*f374ba41SEd Maste 	DSA_SIG_free(dsig);
4102a01feabSEd Maste 	BN_clear_free(sig_r);
4112a01feabSEd Maste 	BN_clear_free(sig_s);
412a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(b);
413a0ee8cc6SDag-Erling Smørgrav 	free(ktype);
41419261079SEd Maste 	if (sigblob != NULL)
41519261079SEd Maste 		freezero(sigblob, len);
4161e8db6e2SBrian Feldman 	return ret;
4171e8db6e2SBrian Feldman }
418*f374ba41SEd Maste 
419*f374ba41SEd Maste static const struct sshkey_impl_funcs sshkey_dss_funcs = {
420*f374ba41SEd Maste 	/* .size = */		ssh_dss_size,
421*f374ba41SEd Maste 	/* .alloc = */		ssh_dss_alloc,
422*f374ba41SEd Maste 	/* .cleanup = */	ssh_dss_cleanup,
423*f374ba41SEd Maste 	/* .equal = */		ssh_dss_equal,
424*f374ba41SEd Maste 	/* .ssh_serialize_public = */ ssh_dss_serialize_public,
425*f374ba41SEd Maste 	/* .ssh_deserialize_public = */ ssh_dss_deserialize_public,
426*f374ba41SEd Maste 	/* .ssh_serialize_private = */ ssh_dss_serialize_private,
427*f374ba41SEd Maste 	/* .ssh_deserialize_private = */ ssh_dss_deserialize_private,
428*f374ba41SEd Maste 	/* .generate = */	ssh_dss_generate,
429*f374ba41SEd Maste 	/* .copy_public = */	ssh_dss_copy_public,
430*f374ba41SEd Maste 	/* .sign = */		ssh_dss_sign,
431*f374ba41SEd Maste 	/* .verify = */		ssh_dss_verify,
432*f374ba41SEd Maste };
433*f374ba41SEd Maste 
434*f374ba41SEd Maste const struct sshkey_impl sshkey_dss_impl = {
435*f374ba41SEd Maste 	/* .name = */		"ssh-dss",
436*f374ba41SEd Maste 	/* .shortname = */	"DSA",
437*f374ba41SEd Maste 	/* .sigalg = */		NULL,
438*f374ba41SEd Maste 	/* .type = */		KEY_DSA,
439*f374ba41SEd Maste 	/* .nid = */		0,
440*f374ba41SEd Maste 	/* .cert = */		0,
441*f374ba41SEd Maste 	/* .sigonly = */	0,
442*f374ba41SEd Maste 	/* .keybits = */	0,
443*f374ba41SEd Maste 	/* .funcs = */		&sshkey_dss_funcs,
444*f374ba41SEd Maste };
445*f374ba41SEd Maste 
446*f374ba41SEd Maste const struct sshkey_impl sshkey_dsa_cert_impl = {
447*f374ba41SEd Maste 	/* .name = */		"ssh-dss-cert-v01@openssh.com",
448*f374ba41SEd Maste 	/* .shortname = */	"DSA-CERT",
449*f374ba41SEd Maste 	/* .sigalg = */		NULL,
450*f374ba41SEd Maste 	/* .type = */		KEY_DSA_CERT,
451*f374ba41SEd Maste 	/* .nid = */		0,
452*f374ba41SEd Maste 	/* .cert = */		1,
453*f374ba41SEd Maste 	/* .sigonly = */	0,
454*f374ba41SEd Maste 	/* .keybits = */	0,
455*f374ba41SEd Maste 	/* .funcs = */		&sshkey_dss_funcs,
456*f374ba41SEd Maste };
457bc5531deSDag-Erling Smørgrav #endif /* WITH_OPENSSL */
458