summaryrefslogtreecommitdiff
path: root/dsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'dsa.c')
-rw-r--r--dsa.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/dsa.c b/dsa.c
new file mode 100644
index 000000000..1594c14f5
--- /dev/null
+++ b/dsa.c
@@ -0,0 +1,298 @@
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 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id: dsa.c,v 1.4 2000/04/14 10:30:31 markus Exp $");
32
33#include "ssh.h"
34#include "xmalloc.h"
35#include "buffer.h"
36#include "bufaux.h"
37#include "compat.h"
38
39#include <openssl/bn.h>
40#include <openssl/dh.h>
41#include <openssl/rsa.h>
42#include <openssl/dsa.h>
43#include <openssl/evp.h>
44#include <openssl/bio.h>
45#include <openssl/pem.h>
46
47#include <openssl/hmac.h>
48#include "kex.h"
49#include "key.h"
50
51#define INTBLOB_LEN 20
52#define SIGBLOB_LEN (2*INTBLOB_LEN)
53
54Key *
55dsa_serverkey_from_blob(
56 char *serverhostkey, int serverhostkeylen)
57{
58 Buffer b;
59 char *ktype;
60 int rlen;
61 DSA *dsa;
62 Key *key;
63
64 /* fetch & parse DSA/DSS pubkey */
65 key = key_new(KEY_DSA);
66 dsa = key->dsa;
67 buffer_init(&b);
68 buffer_append(&b, serverhostkey, serverhostkeylen);
69 ktype = buffer_get_string(&b, NULL);
70 if (strcmp(KEX_DSS, ktype) != 0) {
71 error("dsa_serverkey_from_blob: cannot handle type %s", ktype);
72 key_free(key);
73 return NULL;
74 }
75 buffer_get_bignum2(&b, dsa->p);
76 buffer_get_bignum2(&b, dsa->q);
77 buffer_get_bignum2(&b, dsa->g);
78 buffer_get_bignum2(&b, dsa->pub_key);
79 rlen = buffer_len(&b);
80 if(rlen != 0)
81 error("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen);
82 buffer_free(&b);
83
84 debug("keytype %s", ktype);
85#ifdef DEBUG_DSS
86 DSA_print_fp(stderr, dsa, 8);
87#endif
88 return key;
89}
90DSA *
91dsa_load_private(char *filename)
92{
93 DSA *dsa;
94 BIO *in;
95
96 in = BIO_new(BIO_s_file());
97 if (in == NULL)
98 fatal("BIO_new failed");
99 if (BIO_read_filename(in, filename) <= 0)
100 fatal("BIO_read failed %s: %s", filename, strerror(errno));
101 fprintf(stderr, "read DSA private key\n");
102 dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
103 if (dsa == NULL)
104 fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
105 BIO_free(in);
106 return dsa;
107}
108Key *
109dsa_get_serverkey(char *filename)
110{
111 Key *k = key_new(KEY_EMPTY);
112 k->type = KEY_DSA;
113 k->dsa = dsa_load_private(filename);
114#ifdef DEBUG_DSS
115 DSA_print_fp(stderr, dsa, 8);
116#endif
117 return k;
118}
119int
120dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
121{
122 Buffer b;
123 int len;
124 unsigned char *buf;
125
126 if (key == NULL || key->type != KEY_DSA)
127 return 0;
128 buffer_init(&b);
129 buffer_put_cstring(&b, KEX_DSS);
130 buffer_put_bignum2(&b, key->dsa->p);
131 buffer_put_bignum2(&b, key->dsa->q);
132 buffer_put_bignum2(&b, key->dsa->g);
133 buffer_put_bignum2(&b, key->dsa->pub_key);
134 len = buffer_len(&b);
135 buf = xmalloc(len);
136 memcpy(buf, buffer_ptr(&b), len);
137 memset(buffer_ptr(&b), 0, len);
138 buffer_free(&b);
139 if (lenp != NULL)
140 *lenp = len;
141 if (blobp != NULL)
142 *blobp = buf;
143 return len;
144}
145int
146dsa_sign(
147 Key *key,
148 unsigned char **sigp, int *lenp,
149 unsigned char *hash, int hlen)
150{
151 unsigned char *digest;
152 unsigned char *ret;
153 DSA_SIG *sig;
154 EVP_MD *evp_md = EVP_sha1();
155 EVP_MD_CTX md;
156 unsigned int rlen;
157 unsigned int slen;
158 unsigned int len;
159 unsigned char sigblob[SIGBLOB_LEN];
160 Buffer b;
161
162 if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
163 error("dsa_sign: no DSA key");
164 return -1;
165 }
166 digest = xmalloc(evp_md->md_size);
167 EVP_DigestInit(&md, evp_md);
168 EVP_DigestUpdate(&md, hash, hlen);
169 EVP_DigestFinal(&md, digest, NULL);
170
171 sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
172
173 rlen = BN_num_bytes(sig->r);
174 slen = BN_num_bytes(sig->s);
175 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
176 error("bad sig size %d %d", rlen, slen);
177 DSA_SIG_free(sig);
178 return -1;
179 }
180 debug("sig size %d %d", rlen, slen);
181
182 memset(sigblob, 0, SIGBLOB_LEN);
183 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
184 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
185 DSA_SIG_free(sig);
186
187 if (datafellows) {
188 debug("datafellows");
189 ret = xmalloc(SIGBLOB_LEN);
190 memcpy(ret, sigblob, SIGBLOB_LEN);
191 if (lenp != NULL)
192 *lenp = SIGBLOB_LEN;
193 if (sigp != NULL)
194 *sigp = ret;
195 } else {
196 /* ietf-drafts */
197 buffer_init(&b);
198 buffer_put_cstring(&b, KEX_DSS);
199 buffer_put_string(&b, sigblob, SIGBLOB_LEN);
200 len = buffer_len(&b);
201 ret = xmalloc(len);
202 memcpy(ret, buffer_ptr(&b), len);
203 buffer_free(&b);
204 if (lenp != NULL)
205 *lenp = len;
206 if (sigp != NULL)
207 *sigp = ret;
208 }
209 return 0;
210}
211int
212dsa_verify(
213 Key *key,
214 unsigned char *signature, int signaturelen,
215 unsigned char *hash, int hlen)
216{
217 Buffer b;
218 unsigned char *digest;
219 DSA_SIG *sig;
220 EVP_MD *evp_md = EVP_sha1();
221 EVP_MD_CTX md;
222 char *ktype;
223 unsigned char *sigblob;
224 char *txt;
225 unsigned int len;
226 int rlen;
227 int ret;
228
229 if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
230 error("dsa_verify: no DSA key");
231 return -1;
232 }
233
234 if (datafellows && signaturelen != SIGBLOB_LEN) {
235 log("heh? datafellows ssh2 complies with ietf-drafts????");
236 datafellows = 0;
237 }
238
239 debug("len %d datafellows %d", signaturelen, datafellows);
240
241 /* fetch signature */
242 if (datafellows) {
243 sigblob = signature;
244 len = signaturelen;
245 } else {
246 /* ietf-drafts */
247 buffer_init(&b);
248 buffer_append(&b, (char *) signature, signaturelen);
249 ktype = buffer_get_string(&b, NULL);
250 sigblob = (unsigned char *)buffer_get_string(&b, &len);
251 rlen = buffer_len(&b);
252 if(rlen != 0)
253 error("remaining bytes in signature %d", rlen);
254 buffer_free(&b);
255 }
256
257 if (len != SIGBLOB_LEN) {
258 fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
259 }
260
261 /* parse signature */
262 sig = DSA_SIG_new();
263 sig->r = BN_new();
264 sig->s = BN_new();
265 BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
266 BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
267 if (!datafellows) {
268 memset(sigblob, 0, len);
269 xfree(sigblob);
270 }
271
272 /* sha1 the signed data (== session_id == hash) */
273 digest = xmalloc(evp_md->md_size);
274 EVP_DigestInit(&md, evp_md);
275 EVP_DigestUpdate(&md, hash, hlen);
276 EVP_DigestFinal(&md, digest, NULL);
277
278 ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
279
280 memset(digest, 0, evp_md->md_size);
281 xfree(digest);
282 DSA_SIG_free(sig);
283
284 switch (ret) {
285 case 1:
286 txt = "correct";
287 break;
288 case 0:
289 txt = "incorrect";
290 break;
291 case -1:
292 default:
293 txt = "error";
294 break;
295 }
296 debug("dsa_verify: signature %s", txt);
297 return ret;
298}