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