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