1*c5555919Schristos /* $NetBSD: ssh-dss.c,v 1.19 2024/06/25 16:36:54 christos Exp $ */
2*c5555919Schristos /* $OpenBSD: ssh-dss.c,v 1.50 2024/01/11 01:45:36 djm Exp $ */
3*c5555919Schristos
4ca32bd8dSchristos /*
5ca32bd8dSchristos * Copyright (c) 2000 Markus Friedl. All rights reserved.
6ca32bd8dSchristos *
7ca32bd8dSchristos * Redistribution and use in source and binary forms, with or without
8ca32bd8dSchristos * modification, are permitted provided that the following conditions
9ca32bd8dSchristos * are met:
10ca32bd8dSchristos * 1. Redistributions of source code must retain the above copyright
11ca32bd8dSchristos * notice, this list of conditions and the following disclaimer.
12ca32bd8dSchristos * 2. Redistributions in binary form must reproduce the above copyright
13ca32bd8dSchristos * notice, this list of conditions and the following disclaimer in the
14ca32bd8dSchristos * documentation and/or other materials provided with the distribution.
15ca32bd8dSchristos *
16ca32bd8dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17ca32bd8dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ca32bd8dSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ca32bd8dSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ca32bd8dSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21ca32bd8dSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22ca32bd8dSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23ca32bd8dSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24ca32bd8dSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25ca32bd8dSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26ca32bd8dSchristos */
27ca32bd8dSchristos
28313c6c94Schristos #include "includes.h"
29*c5555919Schristos __RCSID("$NetBSD: ssh-dss.c,v 1.19 2024/06/25 16:36:54 christos Exp $");
30ca32bd8dSchristos #include <sys/types.h>
31ca32bd8dSchristos
32ca32bd8dSchristos #include <openssl/bn.h>
33ca32bd8dSchristos #include <openssl/evp.h>
34ca32bd8dSchristos
35ca32bd8dSchristos #include <string.h>
36ca32bd8dSchristos
378a4530f9Schristos #include "sshbuf.h"
388a4530f9Schristos #include "ssherr.h"
398a4530f9Schristos #include "digest.h"
408a4530f9Schristos #define SSHKEY_INTERNAL
418a4530f9Schristos #include "sshkey.h"
42ca32bd8dSchristos
43*c5555919Schristos #ifdef WITH_DSA
44*c5555919Schristos
45ca32bd8dSchristos #define INTBLOB_LEN 20
46ca32bd8dSchristos #define SIGBLOB_LEN (2*INTBLOB_LEN)
47ca32bd8dSchristos
48b1066cf3Schristos static u_int
ssh_dss_size(const struct sshkey * key)49b1066cf3Schristos ssh_dss_size(const struct sshkey *key)
50b1066cf3Schristos {
51b1066cf3Schristos const BIGNUM *dsa_p;
52b1066cf3Schristos
53b1066cf3Schristos if (key->dsa == NULL)
54b1066cf3Schristos return 0;
55b1066cf3Schristos DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL);
56b1066cf3Schristos return BN_num_bits(dsa_p);
57b1066cf3Schristos }
58b1066cf3Schristos
59b1066cf3Schristos static int
ssh_dss_alloc(struct sshkey * k)60b1066cf3Schristos ssh_dss_alloc(struct sshkey *k)
61b1066cf3Schristos {
62b1066cf3Schristos if ((k->dsa = DSA_new()) == NULL)
63b1066cf3Schristos return SSH_ERR_ALLOC_FAIL;
64b1066cf3Schristos return 0;
65b1066cf3Schristos }
66b1066cf3Schristos
67b1066cf3Schristos static void
ssh_dss_cleanup(struct sshkey * k)68b1066cf3Schristos ssh_dss_cleanup(struct sshkey *k)
69b1066cf3Schristos {
70b1066cf3Schristos DSA_free(k->dsa);
71b1066cf3Schristos k->dsa = NULL;
72b1066cf3Schristos }
73b1066cf3Schristos
74b1066cf3Schristos static int
ssh_dss_equal(const struct sshkey * a,const struct sshkey * b)75b1066cf3Schristos ssh_dss_equal(const struct sshkey *a, const struct sshkey *b)
76b1066cf3Schristos {
77b1066cf3Schristos const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a;
78b1066cf3Schristos const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b;
79b1066cf3Schristos
80b1066cf3Schristos if (a->dsa == NULL || b->dsa == NULL)
81b1066cf3Schristos return 0;
82b1066cf3Schristos DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a);
83b1066cf3Schristos DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b);
84b1066cf3Schristos DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL);
85b1066cf3Schristos DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL);
86b1066cf3Schristos if (dsa_p_a == NULL || dsa_p_b == NULL ||
87b1066cf3Schristos dsa_q_a == NULL || dsa_q_b == NULL ||
88b1066cf3Schristos dsa_g_a == NULL || dsa_g_b == NULL ||
89b1066cf3Schristos dsa_pub_key_a == NULL || dsa_pub_key_b == NULL)
90b1066cf3Schristos return 0;
91b1066cf3Schristos if (BN_cmp(dsa_p_a, dsa_p_b) != 0)
92b1066cf3Schristos return 0;
93b1066cf3Schristos if (BN_cmp(dsa_q_a, dsa_q_b) != 0)
94b1066cf3Schristos return 0;
95b1066cf3Schristos if (BN_cmp(dsa_g_a, dsa_g_b) != 0)
96b1066cf3Schristos return 0;
97b1066cf3Schristos if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0)
98b1066cf3Schristos return 0;
99b1066cf3Schristos return 1;
100b1066cf3Schristos }
101b1066cf3Schristos
102b1066cf3Schristos static int
ssh_dss_serialize_public(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)103b1066cf3Schristos ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b,
104b1066cf3Schristos enum sshkey_serialize_rep opts)
105b1066cf3Schristos {
106b1066cf3Schristos int r;
107b1066cf3Schristos const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
108b1066cf3Schristos
109b1066cf3Schristos if (key->dsa == NULL)
110b1066cf3Schristos return SSH_ERR_INVALID_ARGUMENT;
111b1066cf3Schristos DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
112b1066cf3Schristos DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
113b1066cf3Schristos if (dsa_p == NULL || dsa_q == NULL ||
114b1066cf3Schristos dsa_g == NULL || dsa_pub_key == NULL)
115b1066cf3Schristos return SSH_ERR_INTERNAL_ERROR;
116b1066cf3Schristos if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
117b1066cf3Schristos (r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
118b1066cf3Schristos (r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
119b1066cf3Schristos (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
120b1066cf3Schristos return r;
121b1066cf3Schristos
122b1066cf3Schristos return 0;
123b1066cf3Schristos }
124b1066cf3Schristos
125b1066cf3Schristos static int
ssh_dss_serialize_private(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)126b1066cf3Schristos ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b,
127b1066cf3Schristos enum sshkey_serialize_rep opts)
128b1066cf3Schristos {
129b1066cf3Schristos int r;
130b1066cf3Schristos const BIGNUM *dsa_priv_key;
131b1066cf3Schristos
132b1066cf3Schristos DSA_get0_key(key->dsa, NULL, &dsa_priv_key);
133b1066cf3Schristos if (!sshkey_is_cert(key)) {
134b1066cf3Schristos if ((r = ssh_dss_serialize_public(key, b, opts)) != 0)
135b1066cf3Schristos return r;
136b1066cf3Schristos }
137b1066cf3Schristos if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
138b1066cf3Schristos return r;
139b1066cf3Schristos
140b1066cf3Schristos return 0;
141b1066cf3Schristos }
142b1066cf3Schristos
143b1066cf3Schristos static int
ssh_dss_generate(struct sshkey * k,int bits)144b1066cf3Schristos ssh_dss_generate(struct sshkey *k, int bits)
145b1066cf3Schristos {
146b1066cf3Schristos DSA *private;
147b1066cf3Schristos
148b1066cf3Schristos if (bits != 1024)
149b1066cf3Schristos return SSH_ERR_KEY_LENGTH;
150b1066cf3Schristos if ((private = DSA_new()) == NULL)
151b1066cf3Schristos return SSH_ERR_ALLOC_FAIL;
152b1066cf3Schristos if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
153b1066cf3Schristos NULL, NULL) || !DSA_generate_key(private)) {
154b1066cf3Schristos DSA_free(private);
155b1066cf3Schristos return SSH_ERR_LIBCRYPTO_ERROR;
156b1066cf3Schristos }
157b1066cf3Schristos k->dsa = private;
158b1066cf3Schristos return 0;
159b1066cf3Schristos }
160b1066cf3Schristos
161b1066cf3Schristos static int
ssh_dss_copy_public(const struct sshkey * from,struct sshkey * to)162b1066cf3Schristos ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to)
163b1066cf3Schristos {
164b1066cf3Schristos const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
165b1066cf3Schristos BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
166b1066cf3Schristos BIGNUM *dsa_pub_key_dup = NULL;
167b1066cf3Schristos int r = SSH_ERR_INTERNAL_ERROR;
168b1066cf3Schristos
169b1066cf3Schristos DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g);
170b1066cf3Schristos DSA_get0_key(from->dsa, &dsa_pub_key, NULL);
171b1066cf3Schristos if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
172b1066cf3Schristos (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
173b1066cf3Schristos (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
174b1066cf3Schristos (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
175b1066cf3Schristos r = SSH_ERR_ALLOC_FAIL;
176b1066cf3Schristos goto out;
177b1066cf3Schristos }
178b1066cf3Schristos if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
179b1066cf3Schristos r = SSH_ERR_LIBCRYPTO_ERROR;
180b1066cf3Schristos goto out;
181b1066cf3Schristos }
182b1066cf3Schristos dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
183b1066cf3Schristos if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) {
184b1066cf3Schristos r = SSH_ERR_LIBCRYPTO_ERROR;
185b1066cf3Schristos goto out;
186b1066cf3Schristos }
187b1066cf3Schristos dsa_pub_key_dup = NULL; /* transferred */
188b1066cf3Schristos /* success */
189b1066cf3Schristos r = 0;
190b1066cf3Schristos out:
191b1066cf3Schristos BN_clear_free(dsa_p_dup);
192b1066cf3Schristos BN_clear_free(dsa_q_dup);
193b1066cf3Schristos BN_clear_free(dsa_g_dup);
194b1066cf3Schristos BN_clear_free(dsa_pub_key_dup);
195b1066cf3Schristos return r;
196b1066cf3Schristos }
197b1066cf3Schristos
198b1066cf3Schristos static int
ssh_dss_deserialize_public(const char * ktype,struct sshbuf * b,struct sshkey * key)199b1066cf3Schristos ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b,
200b1066cf3Schristos struct sshkey *key)
201b1066cf3Schristos {
202b1066cf3Schristos int ret = SSH_ERR_INTERNAL_ERROR;
203b1066cf3Schristos BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
204b1066cf3Schristos
205b1066cf3Schristos if (sshbuf_get_bignum2(b, &dsa_p) != 0 ||
206b1066cf3Schristos sshbuf_get_bignum2(b, &dsa_q) != 0 ||
207b1066cf3Schristos sshbuf_get_bignum2(b, &dsa_g) != 0 ||
208b1066cf3Schristos sshbuf_get_bignum2(b, &dsa_pub_key) != 0) {
209b1066cf3Schristos ret = SSH_ERR_INVALID_FORMAT;
210b1066cf3Schristos goto out;
211b1066cf3Schristos }
212b1066cf3Schristos if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
213b1066cf3Schristos ret = SSH_ERR_LIBCRYPTO_ERROR;
214b1066cf3Schristos goto out;
215b1066cf3Schristos }
216b1066cf3Schristos dsa_p = dsa_q = dsa_g = NULL; /* transferred */
217b1066cf3Schristos if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
218b1066cf3Schristos ret = SSH_ERR_LIBCRYPTO_ERROR;
219b1066cf3Schristos goto out;
220b1066cf3Schristos }
221b1066cf3Schristos dsa_pub_key = NULL; /* transferred */
222b1066cf3Schristos #ifdef DEBUG_PK
223b1066cf3Schristos DSA_print_fp(stderr, key->dsa, 8);
224b1066cf3Schristos #endif
225b1066cf3Schristos /* success */
226b1066cf3Schristos ret = 0;
227b1066cf3Schristos out:
228b1066cf3Schristos BN_clear_free(dsa_p);
229b1066cf3Schristos BN_clear_free(dsa_q);
230b1066cf3Schristos BN_clear_free(dsa_g);
231b1066cf3Schristos BN_clear_free(dsa_pub_key);
232b1066cf3Schristos return ret;
233b1066cf3Schristos }
234b1066cf3Schristos
235b1066cf3Schristos static int
ssh_dss_deserialize_private(const char * ktype,struct sshbuf * b,struct sshkey * key)236b1066cf3Schristos ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b,
237b1066cf3Schristos struct sshkey *key)
238b1066cf3Schristos {
239b1066cf3Schristos int r;
240b1066cf3Schristos BIGNUM *dsa_priv_key = NULL;
241b1066cf3Schristos
242b1066cf3Schristos if (!sshkey_is_cert(key)) {
243b1066cf3Schristos if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0)
244b1066cf3Schristos return r;
245b1066cf3Schristos }
246b1066cf3Schristos
247b1066cf3Schristos if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0)
248b1066cf3Schristos return r;
249b1066cf3Schristos if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) {
250b1066cf3Schristos BN_clear_free(dsa_priv_key);
251b1066cf3Schristos return SSH_ERR_LIBCRYPTO_ERROR;
252b1066cf3Schristos }
253b1066cf3Schristos return 0;
254b1066cf3Schristos }
255b1066cf3Schristos
256b1066cf3Schristos 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)257b1066cf3Schristos ssh_dss_sign(struct sshkey *key,
258b1066cf3Schristos u_char **sigp, size_t *lenp,
259b1066cf3Schristos const u_char *data, size_t datalen,
260b1066cf3Schristos const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
261ca32bd8dSchristos {
2628a4530f9Schristos DSA_SIG *sig = NULL;
263aa36fcacSchristos const BIGNUM *sig_r, *sig_s;
2648a4530f9Schristos u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
2658a4530f9Schristos size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
2668a4530f9Schristos struct sshbuf *b = NULL;
2678a4530f9Schristos int ret = SSH_ERR_INVALID_ARGUMENT;
268ca32bd8dSchristos
2698a4530f9Schristos if (lenp != NULL)
2708a4530f9Schristos *lenp = 0;
2718a4530f9Schristos if (sigp != NULL)
2728a4530f9Schristos *sigp = NULL;
273ca32bd8dSchristos
2748a4530f9Schristos if (key == NULL || key->dsa == NULL ||
2758a4530f9Schristos sshkey_type_plain(key->type) != KEY_DSA)
2768a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT;
2778a4530f9Schristos if (dlen == 0)
2788a4530f9Schristos return SSH_ERR_INTERNAL_ERROR;
279ca32bd8dSchristos
2808a4530f9Schristos if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
2818a4530f9Schristos digest, sizeof(digest))) != 0)
2828a4530f9Schristos goto out;
2838a4530f9Schristos
2848a4530f9Schristos if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
2858a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR;
2868a4530f9Schristos goto out;
287ca32bd8dSchristos }
288ca32bd8dSchristos
289aa36fcacSchristos DSA_SIG_get0(sig, &sig_r, &sig_s);
290aa36fcacSchristos rlen = BN_num_bytes(sig_r);
291aa36fcacSchristos slen = BN_num_bytes(sig_s);
292ca32bd8dSchristos if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
2938a4530f9Schristos ret = SSH_ERR_INTERNAL_ERROR;
2948a4530f9Schristos goto out;
295ca32bd8dSchristos }
2968a4530f9Schristos explicit_bzero(sigblob, SIGBLOB_LEN);
297aa36fcacSchristos BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
298aa36fcacSchristos BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen);
299ca32bd8dSchristos
3008a4530f9Schristos if ((b = sshbuf_new()) == NULL) {
3018a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL;
3028a4530f9Schristos goto out;
3038a4530f9Schristos }
3048a4530f9Schristos if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
3058a4530f9Schristos (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
3068a4530f9Schristos goto out;
307ffae97bbSchristos
3088a4530f9Schristos len = sshbuf_len(b);
3098a4530f9Schristos if (sigp != NULL) {
3108a4530f9Schristos if ((*sigp = malloc(len)) == NULL) {
3118a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL;
3128a4530f9Schristos goto out;
3138a4530f9Schristos }
3148a4530f9Schristos memcpy(*sigp, sshbuf_ptr(b), len);
3158a4530f9Schristos }
316ca32bd8dSchristos if (lenp != NULL)
317ca32bd8dSchristos *lenp = len;
3188a4530f9Schristos ret = 0;
3198a4530f9Schristos out:
3208a4530f9Schristos explicit_bzero(digest, sizeof(digest));
3218a4530f9Schristos DSA_SIG_free(sig);
3228a4530f9Schristos sshbuf_free(b);
3238a4530f9Schristos return ret;
324ca32bd8dSchristos }
325ca32bd8dSchristos
326b1066cf3Schristos 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)3278a4530f9Schristos ssh_dss_verify(const struct sshkey *key,
328b1066cf3Schristos const u_char *sig, size_t siglen,
329b1066cf3Schristos const u_char *data, size_t dlen, const char *alg, u_int compat,
330b1066cf3Schristos struct sshkey_sig_details **detailsp)
3318a4530f9Schristos {
332b1066cf3Schristos DSA_SIG *dsig = NULL;
333aa36fcacSchristos BIGNUM *sig_r = NULL, *sig_s = NULL;
3348a4530f9Schristos u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
335b1066cf3Schristos size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
3368a4530f9Schristos int ret = SSH_ERR_INTERNAL_ERROR;
3378a4530f9Schristos struct sshbuf *b = NULL;
3388a4530f9Schristos char *ktype = NULL;
3398a4530f9Schristos
3408a4530f9Schristos if (key == NULL || key->dsa == NULL ||
3415101d403Schristos sshkey_type_plain(key->type) != KEY_DSA ||
342b1066cf3Schristos sig == NULL || siglen == 0)
3438a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT;
344b1066cf3Schristos if (hlen == 0)
3458a4530f9Schristos return SSH_ERR_INTERNAL_ERROR;
346ca32bd8dSchristos
347ca32bd8dSchristos /* fetch signature */
348b1066cf3Schristos if ((b = sshbuf_from(sig, siglen)) == NULL)
3498a4530f9Schristos return SSH_ERR_ALLOC_FAIL;
3508a4530f9Schristos if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
3518a4530f9Schristos sshbuf_get_string(b, &sigblob, &len) != 0) {
3528a4530f9Schristos ret = SSH_ERR_INVALID_FORMAT;
3538a4530f9Schristos goto out;
354ca32bd8dSchristos }
3558a4530f9Schristos if (strcmp("ssh-dss", ktype) != 0) {
3568a4530f9Schristos ret = SSH_ERR_KEY_TYPE_MISMATCH;
3578a4530f9Schristos goto out;
3588a4530f9Schristos }
3598a4530f9Schristos if (sshbuf_len(b) != 0) {
3608a4530f9Schristos ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
3618a4530f9Schristos goto out;
362ca32bd8dSchristos }
363ca32bd8dSchristos
364ca32bd8dSchristos if (len != SIGBLOB_LEN) {
3658a4530f9Schristos ret = SSH_ERR_INVALID_FORMAT;
3668a4530f9Schristos goto out;
367ca32bd8dSchristos }
368ca32bd8dSchristos
369ca32bd8dSchristos /* parse signature */
370b1066cf3Schristos if ((dsig = DSA_SIG_new()) == NULL ||
371aa36fcacSchristos (sig_r = BN_new()) == NULL ||
372aa36fcacSchristos (sig_s = BN_new()) == NULL) {
3738a4530f9Schristos ret = SSH_ERR_ALLOC_FAIL;
3748a4530f9Schristos goto out;
3758a4530f9Schristos }
376aa36fcacSchristos if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) ||
377aa36fcacSchristos (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) {
3788a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR;
3798a4530f9Schristos goto out;
3808a4530f9Schristos }
381b1066cf3Schristos if (!DSA_SIG_set0(dsig, sig_r, sig_s)) {
382aa36fcacSchristos ret = SSH_ERR_LIBCRYPTO_ERROR;
383aa36fcacSchristos goto out;
384aa36fcacSchristos }
385aa36fcacSchristos sig_r = sig_s = NULL; /* transferred */
386ca32bd8dSchristos
387ca32bd8dSchristos /* sha1 the data */
388b1066cf3Schristos if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen,
3898a4530f9Schristos digest, sizeof(digest))) != 0)
3908a4530f9Schristos goto out;
391ca32bd8dSchristos
392b1066cf3Schristos switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) {
3938a4530f9Schristos case 1:
3948a4530f9Schristos ret = 0;
3958a4530f9Schristos break;
3968a4530f9Schristos case 0:
3978a4530f9Schristos ret = SSH_ERR_SIGNATURE_INVALID;
3988a4530f9Schristos goto out;
3998a4530f9Schristos default:
4008a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR;
4018a4530f9Schristos goto out;
4028a4530f9Schristos }
403ca32bd8dSchristos
4048a4530f9Schristos out:
4058a4530f9Schristos explicit_bzero(digest, sizeof(digest));
406b1066cf3Schristos DSA_SIG_free(dsig);
407aa36fcacSchristos BN_clear_free(sig_r);
408aa36fcacSchristos BN_clear_free(sig_s);
4098a4530f9Schristos sshbuf_free(b);
4108a4530f9Schristos free(ktype);
4118db691beSchristos if (sigblob != NULL)
4128db691beSchristos freezero(sigblob, len);
413ca32bd8dSchristos return ret;
414ca32bd8dSchristos }
415b1066cf3Schristos
416b1066cf3Schristos static const struct sshkey_impl_funcs sshkey_dss_funcs = {
417b1066cf3Schristos /* .size = */ ssh_dss_size,
418b1066cf3Schristos /* .alloc = */ ssh_dss_alloc,
419b1066cf3Schristos /* .cleanup = */ ssh_dss_cleanup,
420b1066cf3Schristos /* .equal = */ ssh_dss_equal,
421b1066cf3Schristos /* .ssh_serialize_public = */ ssh_dss_serialize_public,
422b1066cf3Schristos /* .ssh_deserialize_public = */ ssh_dss_deserialize_public,
423b1066cf3Schristos /* .ssh_serialize_private = */ ssh_dss_serialize_private,
424b1066cf3Schristos /* .ssh_deserialize_private = */ ssh_dss_deserialize_private,
425b1066cf3Schristos /* .generate = */ ssh_dss_generate,
426b1066cf3Schristos /* .copy_public = */ ssh_dss_copy_public,
427b1066cf3Schristos /* .sign = */ ssh_dss_sign,
428b1066cf3Schristos /* .verify = */ ssh_dss_verify,
429b1066cf3Schristos };
430b1066cf3Schristos
431b1066cf3Schristos const struct sshkey_impl sshkey_dss_impl = {
432b1066cf3Schristos /* .name = */ "ssh-dss",
433b1066cf3Schristos /* .shortname = */ "DSA",
434b1066cf3Schristos /* .sigalg = */ NULL,
435b1066cf3Schristos /* .type = */ KEY_DSA,
436b1066cf3Schristos /* .nid = */ 0,
437b1066cf3Schristos /* .cert = */ 0,
438b1066cf3Schristos /* .sigonly = */ 0,
439b1066cf3Schristos /* .keybits = */ 0,
440b1066cf3Schristos /* .funcs = */ &sshkey_dss_funcs,
441b1066cf3Schristos };
442b1066cf3Schristos
443b1066cf3Schristos const struct sshkey_impl sshkey_dsa_cert_impl = {
444b1066cf3Schristos /* .name = */ "ssh-dss-cert-v01@openssh.com",
445b1066cf3Schristos /* .shortname = */ "DSA-CERT",
446b1066cf3Schristos /* .sigalg = */ NULL,
447b1066cf3Schristos /* .type = */ KEY_DSA_CERT,
448b1066cf3Schristos /* .nid = */ 0,
449b1066cf3Schristos /* .cert = */ 1,
450b1066cf3Schristos /* .sigonly = */ 0,
451b1066cf3Schristos /* .keybits = */ 0,
452b1066cf3Schristos /* .funcs = */ &sshkey_dss_funcs,
453b1066cf3Schristos };
454*c5555919Schristos
455*c5555919Schristos #endif /* WITH_DSA */
456