xref: /freebsd/crypto/openssh/ssh-dss.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "includes.h"
26 RCSID("$OpenBSD: ssh-dss.c,v 1.6 2001/02/08 19:30:52 itojun Exp $");
27 
28 #include <openssl/bn.h>
29 #include <openssl/evp.h>
30 
31 #include "xmalloc.h"
32 #include "buffer.h"
33 #include "bufaux.h"
34 #include "compat.h"
35 #include "log.h"
36 #include "key.h"
37 #include "ssh-dss.h"
38 
39 #define INTBLOB_LEN	20
40 #define SIGBLOB_LEN	(2*INTBLOB_LEN)
41 
42 int
43 ssh_dss_sign(
44     Key *key,
45     u_char **sigp, int *lenp,
46     u_char *data, int datalen)
47 {
48 	u_char *digest;
49 	u_char *ret;
50 	DSA_SIG *sig;
51 	EVP_MD *evp_md = EVP_sha1();
52 	EVP_MD_CTX md;
53 	u_int rlen;
54 	u_int slen;
55 	u_int len, dlen;
56 	u_char sigblob[SIGBLOB_LEN];
57 	Buffer b;
58 
59 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
60 		error("ssh_dss_sign: no DSA key");
61 		return -1;
62 	}
63 	dlen = evp_md->md_size;
64 	digest = xmalloc(dlen);
65 	EVP_DigestInit(&md, evp_md);
66 	EVP_DigestUpdate(&md, data, datalen);
67 	EVP_DigestFinal(&md, digest, NULL);
68 
69 	sig = DSA_do_sign(digest, dlen, key->dsa);
70 	if (sig == NULL) {
71 		fatal("ssh_dss_sign: cannot sign");
72 	}
73 	memset(digest, 0, dlen);
74 	xfree(digest);
75 
76 	rlen = BN_num_bytes(sig->r);
77 	slen = BN_num_bytes(sig->s);
78 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
79 		error("bad sig size %d %d", rlen, slen);
80 		DSA_SIG_free(sig);
81 		return -1;
82 	}
83 	debug("sig size %d %d", rlen, slen);
84 
85 	memset(sigblob, 0, SIGBLOB_LEN);
86 	BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
87 	BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
88 	DSA_SIG_free(sig);
89 
90 	if (datafellows & SSH_BUG_SIGBLOB) {
91 		debug("datafellows");
92 		ret = xmalloc(SIGBLOB_LEN);
93 		memcpy(ret, sigblob, SIGBLOB_LEN);
94 		if (lenp != NULL)
95 			*lenp = SIGBLOB_LEN;
96 		if (sigp != NULL)
97 			*sigp = ret;
98 	} else {
99 		/* ietf-drafts */
100 		buffer_init(&b);
101 		buffer_put_cstring(&b, "ssh-dss");
102 		buffer_put_string(&b, sigblob, SIGBLOB_LEN);
103 		len = buffer_len(&b);
104 		ret = xmalloc(len);
105 		memcpy(ret, buffer_ptr(&b), len);
106 		buffer_free(&b);
107 		if (lenp != NULL)
108 			*lenp = len;
109 		if (sigp != NULL)
110 			*sigp = ret;
111 	}
112 	return 0;
113 }
114 int
115 ssh_dss_verify(
116     Key *key,
117     u_char *signature, int signaturelen,
118     u_char *data, int datalen)
119 {
120 	Buffer b;
121 	u_char *digest;
122 	DSA_SIG *sig;
123 	EVP_MD *evp_md = EVP_sha1();
124 	EVP_MD_CTX md;
125 	u_char *sigblob;
126 	char *txt;
127 	u_int len, dlen;
128 	int rlen;
129 	int ret;
130 
131 	if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
132 		error("ssh_dss_verify: no DSA key");
133 		return -1;
134 	}
135 
136 	if (!(datafellows & SSH_BUG_SIGBLOB) &&
137 	    signaturelen == SIGBLOB_LEN) {
138 		datafellows |= ~SSH_BUG_SIGBLOB;
139 		log("autodetect SSH_BUG_SIGBLOB");
140 	} else if ((datafellows & SSH_BUG_SIGBLOB) &&
141 	    signaturelen != SIGBLOB_LEN) {
142 		log("autoremove SSH_BUG_SIGBLOB");
143 		datafellows &= ~SSH_BUG_SIGBLOB;
144 	}
145 
146 	debug("len %d datafellows %d", signaturelen, datafellows);
147 
148 	/* fetch signature */
149 	if (datafellows & SSH_BUG_SIGBLOB) {
150 		sigblob = signature;
151 		len = signaturelen;
152 	} else {
153 		/* ietf-drafts */
154 		char *ktype;
155 		buffer_init(&b);
156 		buffer_append(&b, (char *) signature, signaturelen);
157 		ktype = buffer_get_string(&b, NULL);
158 		if (strcmp("ssh-dss", ktype) != 0) {
159 			error("ssh_dss_verify: cannot handle type %s", ktype);
160 			buffer_free(&b);
161 			return -1;
162 		}
163 		sigblob = (u_char *)buffer_get_string(&b, &len);
164 		rlen = buffer_len(&b);
165 		if(rlen != 0) {
166 			error("remaining bytes in signature %d", rlen);
167 			buffer_free(&b);
168 			return -1;
169 		}
170 		buffer_free(&b);
171 		xfree(ktype);
172 	}
173 
174 	if (len != SIGBLOB_LEN) {
175 		fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
176 	}
177 
178 	/* parse signature */
179 	sig = DSA_SIG_new();
180 	sig->r = BN_new();
181 	sig->s = BN_new();
182 	BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
183 	BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
184 
185 	if (!(datafellows & SSH_BUG_SIGBLOB)) {
186 		memset(sigblob, 0, len);
187 		xfree(sigblob);
188 	}
189 
190 	/* sha1 the data */
191 	dlen = evp_md->md_size;
192 	digest = xmalloc(dlen);
193 	EVP_DigestInit(&md, evp_md);
194 	EVP_DigestUpdate(&md, data, datalen);
195 	EVP_DigestFinal(&md, digest, NULL);
196 
197 	ret = DSA_do_verify(digest, dlen, sig, key->dsa);
198 
199 	memset(digest, 0, dlen);
200 	xfree(digest);
201 	DSA_SIG_free(sig);
202 
203 	switch (ret) {
204 	case 1:
205 		txt = "correct";
206 		break;
207 	case 0:
208 		txt = "incorrect";
209 		break;
210 	case -1:
211 	default:
212 		txt = "error";
213 		break;
214 	}
215 	debug("ssh_dss_verify: signature %s", txt);
216 	return ret;
217 }
218