xref: /netbsd-src/crypto/external/bsd/openssh/dist/ssh-dss.c (revision 95b39c65ca575fb40c6bb7083e0eb7ec28eabef1)
1 /*	$NetBSD: ssh-dss.c,v 1.7 2015/04/03 23:58:19 christos Exp $	*/
2 /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
3 /*
4  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "includes.h"
28 __RCSID("$NetBSD: ssh-dss.c,v 1.7 2015/04/03 23:58:19 christos Exp $");
29 #include <sys/types.h>
30 
31 #include <openssl/bn.h>
32 #include <openssl/evp.h>
33 
34 #include <string.h>
35 
36 #include "sshbuf.h"
37 #include "compat.h"
38 #include "ssherr.h"
39 #include "digest.h"
40 #define SSHKEY_INTERNAL
41 #include "sshkey.h"
42 
43 #define INTBLOB_LEN	20
44 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
45 
46 int
47 ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
48     const u_char *data, size_t datalen, u_int compat)
49 {
50 	DSA_SIG *sig = NULL;
51 	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
52 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
53 	struct sshbuf *b = NULL;
54 	int ret = SSH_ERR_INVALID_ARGUMENT;
55 
56 	if (lenp != NULL)
57 		*lenp = 0;
58 	if (sigp != NULL)
59 		*sigp = NULL;
60 
61 	if (key == NULL || key->dsa == NULL ||
62 	    sshkey_type_plain(key->type) != KEY_DSA)
63 		return SSH_ERR_INVALID_ARGUMENT;
64 	if (dlen == 0)
65 		return SSH_ERR_INTERNAL_ERROR;
66 
67 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
68 	    digest, sizeof(digest))) != 0)
69 		goto out;
70 
71 	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
72 		ret = SSH_ERR_LIBCRYPTO_ERROR;
73 		goto out;
74 	}
75 
76 	rlen = BN_num_bytes(sig->r);
77 	slen = BN_num_bytes(sig->s);
78 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
79 		ret = SSH_ERR_INTERNAL_ERROR;
80 		goto out;
81 	}
82 	explicit_bzero(sigblob, SIGBLOB_LEN);
83 	BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
84 	BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
85 
86 	if (compat & SSH_BUG_SIGBLOB) {
87 		if (sigp != NULL) {
88 			if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
89 				ret = SSH_ERR_ALLOC_FAIL;
90 				goto out;
91 			}
92 			memcpy(*sigp, sigblob, SIGBLOB_LEN);
93 		}
94 		if (lenp != NULL)
95 			*lenp = SIGBLOB_LEN;
96 		ret = 0;
97 	} else {
98 		/* ietf-drafts */
99 		if ((b = sshbuf_new()) == NULL) {
100 			ret = SSH_ERR_ALLOC_FAIL;
101 			goto out;
102 		}
103 		if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
104 		    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
105 			goto out;
106 		len = sshbuf_len(b);
107 		if (sigp != NULL) {
108 			if ((*sigp = malloc(len)) == NULL) {
109 				ret = SSH_ERR_ALLOC_FAIL;
110 				goto out;
111 			}
112 			memcpy(*sigp, sshbuf_ptr(b), len);
113 		}
114 		if (lenp != NULL)
115 			*lenp = len;
116 		ret = 0;
117 	}
118  out:
119 	explicit_bzero(digest, sizeof(digest));
120 	if (sig != NULL)
121 		DSA_SIG_free(sig);
122 	if (b != NULL)
123 		sshbuf_free(b);
124 	return ret;
125 }
126 
127 int
128 ssh_dss_verify(const struct sshkey *key,
129     const u_char *signature, size_t signaturelen,
130     const u_char *data, size_t datalen, u_int compat)
131 {
132 	DSA_SIG *sig = NULL;
133 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
134 	size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
135 	int ret = SSH_ERR_INTERNAL_ERROR;
136 	struct sshbuf *b = NULL;
137 	char *ktype = NULL;
138 
139 	if (key == NULL || key->dsa == NULL ||
140 	    sshkey_type_plain(key->type) != KEY_DSA)
141 		return SSH_ERR_INVALID_ARGUMENT;
142 	if (dlen == 0)
143 		return SSH_ERR_INTERNAL_ERROR;
144 
145 	/* fetch signature */
146 	if (compat & SSH_BUG_SIGBLOB) {
147 		if ((sigblob = malloc(signaturelen)) == NULL)
148 			return SSH_ERR_ALLOC_FAIL;
149 		memcpy(sigblob, signature, signaturelen);
150 		len = signaturelen;
151 	} else {
152 		/* ietf-drafts */
153 		if ((b = sshbuf_from(signature, signaturelen)) == NULL)
154 			return SSH_ERR_ALLOC_FAIL;
155 		if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
156 		    sshbuf_get_string(b, &sigblob, &len) != 0) {
157 			ret = SSH_ERR_INVALID_FORMAT;
158 			goto out;
159 		}
160 		if (strcmp("ssh-dss", ktype) != 0) {
161 			ret = SSH_ERR_KEY_TYPE_MISMATCH;
162 			goto out;
163 		}
164 		if (sshbuf_len(b) != 0) {
165 			ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
166 			goto out;
167 		}
168 	}
169 
170 	if (len != SIGBLOB_LEN) {
171 		ret = SSH_ERR_INVALID_FORMAT;
172 		goto out;
173 	}
174 
175 	/* parse signature */
176 	if ((sig = DSA_SIG_new()) == NULL ||
177 	    (sig->r = BN_new()) == NULL ||
178 	    (sig->s = BN_new()) == NULL) {
179 		ret = SSH_ERR_ALLOC_FAIL;
180 		goto out;
181 	}
182 	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
183 	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
184 		ret = SSH_ERR_LIBCRYPTO_ERROR;
185 		goto out;
186 	}
187 
188 	/* sha1 the data */
189 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
190 	    digest, sizeof(digest))) != 0)
191 		goto out;
192 
193 	switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
194 	case 1:
195 		ret = 0;
196 		break;
197 	case 0:
198 		ret = SSH_ERR_SIGNATURE_INVALID;
199 		goto out;
200 	default:
201 		ret = SSH_ERR_LIBCRYPTO_ERROR;
202 		goto out;
203 	}
204 
205  out:
206 	explicit_bzero(digest, sizeof(digest));
207 	if (sig != NULL)
208 		DSA_SIG_free(sig);
209 	if (b != NULL)
210 		sshbuf_free(b);
211 	if (ktype != NULL)
212 		free(ktype);
213 	if (sigblob != NULL) {
214 		explicit_bzero(sigblob, len);
215 		free(sigblob);
216 	}
217 	return ret;
218 }
219