summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dsa.c298
-rw-r--r--hmac.c59
-rw-r--r--kex.c424
3 files changed, 781 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}
diff --git a/hmac.c b/hmac.c
new file mode 100644
index 000000000..fe53aa47e
--- /dev/null
+++ b/hmac.c
@@ -0,0 +1,59 @@
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: hmac.c,v 1.2 2000/04/12 09:39:10 markus Exp $");
32
33#include "xmalloc.h"
34#include "ssh.h"
35#include "getput.h"
36
37#include <openssl/hmac.h>
38
39unsigned char *
40hmac(
41 EVP_MD *evp_md,
42 unsigned int seqno,
43 unsigned char *data, int datalen,
44 unsigned char *key, int keylen)
45{
46 HMAC_CTX c;
47 static unsigned char m[EVP_MAX_MD_SIZE];
48 unsigned char b[4];
49
50 if (key == NULL)
51 fatal("hmac: no key");
52 HMAC_Init(&c, key, keylen, evp_md);
53 PUT_32BIT(b, seqno);
54 HMAC_Update(&c, b, sizeof b);
55 HMAC_Update(&c, data, datalen);
56 HMAC_Final(&c, m, NULL);
57 HMAC_cleanup(&c);
58 return(m);
59}
diff --git a/kex.c b/kex.c
new file mode 100644
index 000000000..114df780e
--- /dev/null
+++ b/kex.c
@@ -0,0 +1,424 @@
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: kex.c,v 1.7 2000/04/16 01:52:47 damien Exp $");
32
33#include "ssh.h"
34#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
38#include "cipher.h"
39#include "compat.h"
40
41#include <openssl/bn.h>
42#include <openssl/dh.h>
43
44#include <openssl/crypto.h>
45#include <openssl/bio.h>
46#include <openssl/bn.h>
47#include <openssl/dh.h>
48#include <openssl/pem.h>
49
50#include "kex.h"
51
52Buffer *
53kex_init(char *myproposal[PROPOSAL_MAX])
54{
55 char c = 0;
56 unsigned char cookie[16];
57 u_int32_t rand = 0;
58 int i;
59 Buffer *ki = xmalloc(sizeof(*ki));
60 for (i = 0; i < 16; i++) {
61 if (i % 4 == 0)
62 rand = arc4random();
63 cookie[i] = rand & 0xff;
64 rand >>= 8;
65 }
66 buffer_init(ki);
67 buffer_append(ki, (char *)cookie, sizeof cookie);
68 for (i = 0; i < PROPOSAL_MAX; i++)
69 buffer_put_cstring(ki, myproposal[i]);
70 buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */
71 buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */
72 return ki;
73}
74
75/* diffie-hellman-group1-sha1 */
76
77int
78dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
79{
80 int i;
81 int n = BN_num_bits(dh_pub);
82 int bits_set = 0;
83
84 /* we only accept g==2 */
85 if (!BN_is_word(dh->g, 2)) {
86 log("invalid DH base != 2");
87 return 0;
88 }
89 if (dh_pub->neg) {
90 log("invalid public DH value: negativ");
91 return 0;
92 }
93 for (i = 0; i <= n; i++)
94 if (BN_is_bit_set(dh_pub, i))
95 bits_set++;
96 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
97
98 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
99 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
100 return 1;
101 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
102 return 0;
103}
104
105DH *
106dh_new_group1()
107{
108 static char *group1 =
109 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
110 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
111 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
112 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
113 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
114 "FFFFFFFF" "FFFFFFFF";
115 DH *dh;
116 int ret, tries = 0;
117 dh = DH_new();
118 if(dh == NULL)
119 fatal("DH_new");
120 ret = BN_hex2bn(&dh->p, group1);
121 if(ret<0)
122 fatal("BN_hex2bn");
123 dh->g = BN_new();
124 if(dh->g == NULL)
125 fatal("DH_new g");
126 BN_set_word(dh->g, 2);
127 do {
128 if (DH_generate_key(dh) == 0)
129 fatal("DH_generate_key");
130 if (tries++ > 10)
131 fatal("dh_new_group1: too many bad keys: giving up");
132 } while (!dh_pub_is_valid(dh, dh->pub_key));
133 return dh;
134}
135
136void
137bignum_print(BIGNUM *b)
138{
139 BN_print_fp(stderr,b);
140}
141
142void
143dump_digest(unsigned char *digest, int len)
144{
145 int i;
146 for (i = 0; i< len; i++){
147 fprintf(stderr, "%02x", digest[i]);
148 if(i%2!=0)
149 fprintf(stderr, " ");
150 }
151 fprintf(stderr, "\n");
152}
153
154unsigned char *
155kex_hash(
156 char *client_version_string,
157 char *server_version_string,
158 char *ckexinit, int ckexinitlen,
159 char *skexinit, int skexinitlen,
160 char *serverhostkeyblob, int sbloblen,
161 BIGNUM *client_dh_pub,
162 BIGNUM *server_dh_pub,
163 BIGNUM *shared_secret)
164{
165 Buffer b;
166 static unsigned char digest[EVP_MAX_MD_SIZE];
167 EVP_MD *evp_md = EVP_sha1();
168 EVP_MD_CTX md;
169
170 buffer_init(&b);
171 buffer_put_string(&b, client_version_string, strlen(client_version_string));
172 buffer_put_string(&b, server_version_string, strlen(server_version_string));
173
174 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
175 buffer_put_int(&b, ckexinitlen+1);
176 buffer_put_char(&b, SSH2_MSG_KEXINIT);
177 buffer_append(&b, ckexinit, ckexinitlen);
178 buffer_put_int(&b, skexinitlen+1);
179 buffer_put_char(&b, SSH2_MSG_KEXINIT);
180 buffer_append(&b, skexinit, skexinitlen);
181
182 buffer_put_string(&b, serverhostkeyblob, sbloblen);
183 buffer_put_bignum2(&b, client_dh_pub);
184 buffer_put_bignum2(&b, server_dh_pub);
185 buffer_put_bignum2(&b, shared_secret);
186
187#ifdef DEBUG_KEX
188 buffer_dump(&b);
189#endif
190
191 EVP_DigestInit(&md, evp_md);
192 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
193 EVP_DigestFinal(&md, digest, NULL);
194
195 buffer_free(&b);
196
197#ifdef DEBUG_KEX
198 dump_digest(digest, evp_md->md_size);
199#endif
200 return digest;
201}
202
203unsigned char *
204derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
205{
206 Buffer b;
207 EVP_MD *evp_md = EVP_sha1();
208 EVP_MD_CTX md;
209 char c = id;
210 int have;
211 int mdsz = evp_md->md_size;
212 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
213
214 buffer_init(&b);
215 buffer_put_bignum2(&b, shared_secret);
216
217 EVP_DigestInit(&md, evp_md);
218 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
219 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
220 EVP_DigestUpdate(&md, &c, 1); /* key id */
221 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
222 EVP_DigestFinal(&md, digest, NULL);
223
224 /* expand */
225 for (have = mdsz; need > have; have += mdsz) {
226 EVP_DigestInit(&md, evp_md);
227 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
228 EVP_DigestUpdate(&md, hash, mdsz);
229 EVP_DigestUpdate(&md, digest, have);
230 EVP_DigestFinal(&md, digest + have, NULL);
231 }
232 buffer_free(&b);
233#ifdef DEBUG_KEX
234 fprintf(stderr, "Digest '%c'== ", c);
235 dump_digest(digest, need);
236#endif
237 return digest;
238}
239
240#define NKEYS 6
241
242#define MAX_PROP 20
243#define SEP ","
244
245char *
246get_match(char *client, char *server)
247{
248 char *sproposals[MAX_PROP];
249 char *p;
250 int i, j, nproposals;
251
252 for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
253 if (i < MAX_PROP)
254 sproposals[i] = p;
255 else
256 break;
257 }
258 nproposals = i;
259
260 for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
261 for (j = 0; j < nproposals; j++)
262 if (strcmp(p, sproposals[j]) == 0)
263 return xstrdup(p);
264 }
265 return NULL;
266}
267void
268choose_enc(Enc *enc, char *client, char *server)
269{
270 char *name = get_match(client, server);
271 if (name == NULL)
272 fatal("no matching cipher found: client %s server %s", client, server);
273 enc->type = cipher_number(name);
274
275 switch (enc->type) {
276 case SSH_CIPHER_3DES_CBC:
277 enc->key_len = 24;
278 enc->iv_len = 8;
279 enc->block_size = 8;
280 break;
281 case SSH_CIPHER_BLOWFISH_CBC:
282 case SSH_CIPHER_CAST128_CBC:
283 enc->key_len = 16;
284 enc->iv_len = 8;
285 enc->block_size = 8;
286 break;
287 case SSH_CIPHER_ARCFOUR:
288 enc->key_len = 16;
289 enc->iv_len = 0;
290 enc->block_size = 8;
291 break;
292 default:
293 fatal("unsupported cipher %s", name);
294 }
295 enc->name = name;
296 enc->enabled = 0;
297 enc->iv = NULL;
298 enc->key = NULL;
299}
300void
301choose_mac(Mac *mac, char *client, char *server)
302{
303 char *name = get_match(client, server);
304 if (name == NULL)
305 fatal("no matching mac found: client %s server %s", client, server);
306 if (strcmp(name, "hmac-md5") == 0) {
307 mac->md = EVP_md5();
308 } else if (strcmp(name, "hmac-sha1") == 0) {
309 mac->md = EVP_sha1();
310 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
311 mac->md = EVP_ripemd160();
312 } else {
313 fatal("unsupported mac %s", name);
314 }
315 mac->name = name;
316 mac->mac_len = mac->md->md_size;
317 mac->key_len = datafellows ? 16 : mac->mac_len;
318 mac->key = NULL;
319 mac->enabled = 0;
320}
321void
322choose_comp(Comp *comp, char *client, char *server)
323{
324 char *name = get_match(client, server);
325 if (name == NULL)
326 fatal("no matching comp found: client %s server %s", client, server);
327 if (strcmp(name, "zlib") == 0) {
328 comp->type = 1;
329 } else if (strcmp(name, "none") == 0) {
330 comp->type = 0;
331 } else {
332 fatal("unsupported comp %s", name);
333 }
334 comp->name = name;
335}
336void
337choose_kex(Kex *k, char *client, char *server)
338{
339 k->name = get_match(client, server);
340 if (k->name == NULL)
341 fatal("no kex alg");
342 if (strcmp(k->name, KEX_DH1) != 0)
343 fatal("bad kex alg %s", k->name);
344}
345void
346choose_hostkeyalg(Kex *k, char *client, char *server)
347{
348 k->hostkeyalg = get_match(client, server);
349 if (k->hostkeyalg == NULL)
350 fatal("no hostkey alg");
351 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
352 fatal("bad hostkey alg %s", k->hostkeyalg);
353}
354
355Kex *
356kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
357{
358 int i;
359 int mode;
360 int ctos; /* direction: if true client-to-server */
361 int need;
362 Kex *k;
363
364 k = xmalloc(sizeof(*k));
365 memset(k, 0, sizeof(*k));
366 k->server = server;
367
368 for (mode = 0; mode < MODE_MAX; mode++) {
369 int nenc, nmac, ncomp;
370 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
371 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
372 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
373 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
374 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
375 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
376 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
377 debug("kex: %s %s %s %s",
378 ctos ? "client->server" : "server->client",
379 k->enc[mode].name,
380 k->mac[mode].name,
381 k->comp[mode].name);
382 }
383 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
384 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
385 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
386 for (i = 0; i < PROPOSAL_MAX; i++) {
387 xfree(cprop[i]);
388 xfree(sprop[i]);
389 }
390 need = 0;
391 for (mode = 0; mode < MODE_MAX; mode++) {
392 if (need < k->enc[mode].key_len)
393 need = k->enc[mode].key_len;
394 if (need < k->enc[mode].iv_len)
395 need = k->enc[mode].iv_len;
396 if (need < k->mac[mode].key_len)
397 need = k->mac[mode].key_len;
398 }
399 /* need runden? */
400#define WE_NEED 32
401 k->we_need = WE_NEED;
402 k->we_need = need;
403 return k;
404}
405
406int
407kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
408{
409 int i;
410 int mode;
411 int ctos;
412 unsigned char *keys[NKEYS];
413
414 for (i = 0; i < NKEYS; i++)
415 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
416
417 for (mode = 0; mode < MODE_MAX; mode++) {
418 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
419 k->enc[mode].iv = keys[ctos ? 0 : 1];
420 k->enc[mode].key = keys[ctos ? 2 : 3];
421 k->mac[mode].key = keys[ctos ? 4 : 5];
422 }
423 return 0;
424}