xref: /netbsd-src/crypto/external/bsd/openssh/dist/ssh-dss.c (revision fdd524d4ccd2bb0c6f67401e938dabf773eb0372)
1 /*	$NetBSD: ssh-dss.c,v 1.8 2016/03/11 01:55:00 christos Exp $	*/
2 /* $OpenBSD: ssh-dss.c,v 1.34 2015/12/11 04:21:12 mmcc Exp $ */
3 
4 /*
5  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "includes.h"
29 __RCSID("$NetBSD: ssh-dss.c,v 1.8 2016/03/11 01:55:00 christos Exp $");
30 #include <sys/types.h>
31 
32 #include <openssl/bn.h>
33 #include <openssl/evp.h>
34 
35 #include <string.h>
36 
37 #include "sshbuf.h"
38 #include "compat.h"
39 #include "ssherr.h"
40 #include "digest.h"
41 #define SSHKEY_INTERNAL
42 #include "sshkey.h"
43 
44 #define INTBLOB_LEN	20
45 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
46 
47 int
48 ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
49     const u_char *data, size_t datalen, u_int compat)
50 {
51 	DSA_SIG *sig = NULL;
52 	u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
53 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
54 	struct sshbuf *b = NULL;
55 	int ret = SSH_ERR_INVALID_ARGUMENT;
56 
57 	if (lenp != NULL)
58 		*lenp = 0;
59 	if (sigp != NULL)
60 		*sigp = NULL;
61 
62 	if (key == NULL || key->dsa == NULL ||
63 	    sshkey_type_plain(key->type) != KEY_DSA)
64 		return SSH_ERR_INVALID_ARGUMENT;
65 	if (dlen == 0)
66 		return SSH_ERR_INTERNAL_ERROR;
67 
68 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
69 	    digest, sizeof(digest))) != 0)
70 		goto out;
71 
72 	if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
73 		ret = SSH_ERR_LIBCRYPTO_ERROR;
74 		goto out;
75 	}
76 
77 	rlen = BN_num_bytes(sig->r);
78 	slen = BN_num_bytes(sig->s);
79 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
80 		ret = SSH_ERR_INTERNAL_ERROR;
81 		goto out;
82 	}
83 	explicit_bzero(sigblob, SIGBLOB_LEN);
84 	BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
85 	BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
86 
87 	if (compat & SSH_BUG_SIGBLOB) {
88 		if (sigp != NULL) {
89 			if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
90 				ret = SSH_ERR_ALLOC_FAIL;
91 				goto out;
92 			}
93 			memcpy(*sigp, sigblob, SIGBLOB_LEN);
94 		}
95 		if (lenp != NULL)
96 			*lenp = SIGBLOB_LEN;
97 		ret = 0;
98 	} else {
99 		/* ietf-drafts */
100 		if ((b = sshbuf_new()) == NULL) {
101 			ret = SSH_ERR_ALLOC_FAIL;
102 			goto out;
103 		}
104 		if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
105 		    (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
106 			goto out;
107 		len = sshbuf_len(b);
108 		if (sigp != NULL) {
109 			if ((*sigp = malloc(len)) == NULL) {
110 				ret = SSH_ERR_ALLOC_FAIL;
111 				goto out;
112 			}
113 			memcpy(*sigp, sshbuf_ptr(b), len);
114 		}
115 		if (lenp != NULL)
116 			*lenp = len;
117 		ret = 0;
118 	}
119  out:
120 	explicit_bzero(digest, sizeof(digest));
121 	if (sig != NULL)
122 		DSA_SIG_free(sig);
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 	sshbuf_free(b);
210 	free(ktype);
211 	if (sigblob != NULL) {
212 		explicit_bzero(sigblob, len);
213 		free(sigblob);
214 	}
215 	return ret;
216 }
217