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