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