xref: /dragonfly/crypto/openssh/ssh-dss.c (revision 279dd846)
1 /* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 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 #include <sys/types.h>
29 
30 #include <openssl/bn.h>
31 #include <openssl/dsa.h>
32 #include <openssl/evp.h>
33 
34 #include <stdarg.h>
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 	if (b != NULL)
124 		sshbuf_free(b);
125 	return ret;
126 }
127 
128 int
129 ssh_dss_verify(const struct sshkey *key,
130     const u_char *signature, size_t signaturelen,
131     const u_char *data, size_t datalen, u_int compat)
132 {
133 	DSA_SIG *sig = NULL;
134 	u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
135 	size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
136 	int ret = SSH_ERR_INTERNAL_ERROR;
137 	struct sshbuf *b = NULL;
138 	char *ktype = NULL;
139 
140 	if (key == NULL || key->dsa == NULL ||
141 	    sshkey_type_plain(key->type) != KEY_DSA)
142 		return SSH_ERR_INVALID_ARGUMENT;
143 	if (dlen == 0)
144 		return SSH_ERR_INTERNAL_ERROR;
145 
146 	/* fetch signature */
147 	if (compat & SSH_BUG_SIGBLOB) {
148 		if ((sigblob = malloc(signaturelen)) == NULL)
149 			return SSH_ERR_ALLOC_FAIL;
150 		memcpy(sigblob, signature, signaturelen);
151 		len = signaturelen;
152 	} else {
153 		/* ietf-drafts */
154 		if ((b = sshbuf_from(signature, signaturelen)) == NULL)
155 			return SSH_ERR_ALLOC_FAIL;
156 		if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
157 		    sshbuf_get_string(b, &sigblob, &len) != 0) {
158 			ret = SSH_ERR_INVALID_FORMAT;
159 			goto out;
160 		}
161 		if (strcmp("ssh-dss", ktype) != 0) {
162 			ret = SSH_ERR_KEY_TYPE_MISMATCH;
163 			goto out;
164 		}
165 		if (sshbuf_len(b) != 0) {
166 			ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
167 			goto out;
168 		}
169 	}
170 
171 	if (len != SIGBLOB_LEN) {
172 		ret = SSH_ERR_INVALID_FORMAT;
173 		goto out;
174 	}
175 
176 	/* parse signature */
177 	if ((sig = DSA_SIG_new()) == NULL ||
178 	    (sig->r = BN_new()) == NULL ||
179 	    (sig->s = BN_new()) == NULL) {
180 		ret = SSH_ERR_ALLOC_FAIL;
181 		goto out;
182 	}
183 	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
184 	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
185 		ret = SSH_ERR_LIBCRYPTO_ERROR;
186 		goto out;
187 	}
188 
189 	/* sha1 the data */
190 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
191 	    digest, sizeof(digest))) != 0)
192 		goto out;
193 
194 	switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
195 	case 1:
196 		ret = 0;
197 		break;
198 	case 0:
199 		ret = SSH_ERR_SIGNATURE_INVALID;
200 		goto out;
201 	default:
202 		ret = SSH_ERR_LIBCRYPTO_ERROR;
203 		goto out;
204 	}
205 
206  out:
207 	explicit_bzero(digest, sizeof(digest));
208 	if (sig != NULL)
209 		DSA_SIG_free(sig);
210 	if (b != NULL)
211 		sshbuf_free(b);
212 	if (ktype != NULL)
213 		free(ktype);
214 	if (sigblob != NULL) {
215 		explicit_bzero(sigblob, len);
216 		free(sigblob);
217 	}
218 	return ret;
219 }
220