Mercurial > dropbear
comparison svr-kex.c @ 4:fe6bca95afa7
Makefile.in contains updated files required
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 01 Jun 2004 02:46:09 +0000 |
parents | |
children | c1e5d9195402 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 4:fe6bca95afa7 |
---|---|
1 /* | |
2 * Dropbear - a SSH2 server | |
3 * | |
4 * Copyright (c) 2002,2003 Matt Johnston | |
5 * All rights reserved. | |
6 * | |
7 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 * of this software and associated documentation files (the "Software"), to deal | |
9 * in the Software without restriction, including without limitation the rights | |
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 * copies of the Software, and to permit persons to whom the Software is | |
12 * furnished to do so, subject to the following conditions: | |
13 * | |
14 * The above copyright notice and this permission notice shall be included in | |
15 * all copies or substantial portions of the Software. | |
16 * | |
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 * SOFTWARE. */ | |
24 | |
25 #include "includes.h" | |
26 #include "dbutil.h" | |
27 #include "algo.h" | |
28 #include "buffer.h" | |
29 #include "session.h" | |
30 #include "kex.h" | |
31 #include "ssh.h" | |
32 #include "packet.h" | |
33 #include "bignum.h" | |
34 #include "random.h" | |
35 | |
36 | |
37 static void send_msg_kexdh_reply(mp_int *dh_e); | |
38 | |
39 /* Handle a diffie-hellman key exchange initialisation. This involves | |
40 * calculating a session key reply value, and corresponding hash. These | |
41 * are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls | |
42 * that function, then brings the new keys into use */ | |
43 void recv_msg_kexdh_init() { | |
44 | |
45 mp_int dh_e; | |
46 | |
47 TRACE(("enter recv_msg_kexdh_init")); | |
48 if (!ses.kexstate.recvkexinit) { | |
49 dropbear_exit("Premature kexdh_init message received"); | |
50 } | |
51 | |
52 m_mp_init(&dh_e); | |
53 buf_getmpint(ses.payload, &dh_e); | |
54 | |
55 send_msg_kexdh_reply(&dh_e); | |
56 | |
57 mp_clear(&dh_e); | |
58 | |
59 send_msg_newkeys(); | |
60 ses.expecting = SSH_MSG_NEWKEYS; | |
61 TRACE(("leave recv_msg_kexdh_init")); | |
62 } | |
63 | |
64 /* Generate our side of the diffie-hellman key exchange value (dh_f), and | |
65 * calculate the session key using the diffie-hellman algorithm. Following | |
66 * that, the session hash is calculated, and signed with RSA or DSS. The | |
67 * result is sent to the client. | |
68 * | |
69 * See the ietf-secsh-transport draft, section 6, for details */ | |
70 static void send_msg_kexdh_reply(mp_int *dh_e) { | |
71 | |
72 mp_int dh_p, dh_q, dh_g, dh_y, dh_f; | |
73 unsigned char randbuf[DH_P_LEN]; | |
74 int dh_q_len; | |
75 hash_state hs; | |
76 | |
77 TRACE(("enter send_msg_kexdh_reply")); | |
78 | |
79 m_mp_init_multi(&dh_g, &dh_p, &dh_q, &dh_y, &dh_f, NULL); | |
80 | |
81 /* read the prime and generator*/ | |
82 if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN) | |
83 != MP_OKAY) { | |
84 dropbear_exit("Diffie-Hellman error"); | |
85 } | |
86 | |
87 if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) { | |
88 dropbear_exit("Diffie-Hellman error"); | |
89 } | |
90 | |
91 /* calculate q = (p-1)/2 */ | |
92 if (mp_sub_d(&dh_p, 1, &dh_y) != MP_OKAY) { /*dh_y is just a temp var here*/ | |
93 dropbear_exit("Diffie-Hellman error"); | |
94 } | |
95 if (mp_div_2(&dh_y, &dh_q) != MP_OKAY) { | |
96 dropbear_exit("Diffie-Hellman error"); | |
97 } | |
98 | |
99 dh_q_len = mp_unsigned_bin_size(&dh_q); | |
100 | |
101 /* calculate our random value dh_y */ | |
102 do { | |
103 assert((unsigned int)dh_q_len <= sizeof(randbuf)); | |
104 genrandom(randbuf, dh_q_len); | |
105 if (mp_read_unsigned_bin(&dh_y, randbuf, dh_q_len) != MP_OKAY) { | |
106 dropbear_exit("Diffie-Hellman error"); | |
107 } | |
108 } while (mp_cmp(&dh_y, &dh_q) == MP_GT || mp_cmp_d(&dh_y, 0) != MP_GT); | |
109 | |
110 /* f = g^y mod p */ | |
111 if (mp_exptmod(&dh_g, &dh_y, &dh_p, &dh_f) != MP_OKAY) { | |
112 dropbear_exit("Diffie-Hellman error"); | |
113 } | |
114 mp_clear(&dh_g); | |
115 | |
116 /* K = e^y mod p */ | |
117 ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int)); | |
118 m_mp_init(ses.dh_K); | |
119 if (mp_exptmod(dh_e, &dh_y, &dh_p, ses.dh_K) != MP_OKAY) { | |
120 dropbear_exit("Diffie-Hellman error"); | |
121 } | |
122 | |
123 /* clear no longer needed vars */ | |
124 mp_clear_multi(&dh_y, &dh_p, &dh_q, NULL); | |
125 | |
126 /* Create the remainder of the hash buffer, to generate the exchange hash */ | |
127 /* K_S, the host key */ | |
128 buf_put_pub_key(ses.kexhashbuf, ses.opts->hostkey, | |
129 ses.newkeys->algo_hostkey); | |
130 /* e, exchange value sent by the client */ | |
131 buf_putmpint(ses.kexhashbuf, dh_e); | |
132 /* f, exchange value sent by the server */ | |
133 buf_putmpint(ses.kexhashbuf, &dh_f); | |
134 /* K, the shared secret */ | |
135 buf_putmpint(ses.kexhashbuf, ses.dh_K); | |
136 | |
137 /* calculate the hash H to sign */ | |
138 sha1_init(&hs); | |
139 buf_setpos(ses.kexhashbuf, 0); | |
140 sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len), | |
141 ses.kexhashbuf->len); | |
142 sha1_done(&hs, ses.hash); | |
143 buf_free(ses.kexhashbuf); | |
144 ses.kexhashbuf = NULL; | |
145 | |
146 /* first time around, we set the session_id to H */ | |
147 if (ses.session_id == NULL) { | |
148 /* create the session_id, this never needs freeing */ | |
149 ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE); | |
150 memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE); | |
151 } | |
152 | |
153 /* we can start creating the kexdh_reply packet */ | |
154 CHECKCLEARTOWRITE(); | |
155 buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY); | |
156 buf_put_pub_key(ses.writepayload, ses.opts->hostkey, | |
157 ses.newkeys->algo_hostkey); | |
158 | |
159 /* put f */ | |
160 buf_putmpint(ses.writepayload, &dh_f); | |
161 mp_clear(&dh_f); | |
162 | |
163 /* calc the signature */ | |
164 buf_put_sign(ses.writepayload, ses.opts->hostkey, | |
165 ses.newkeys->algo_hostkey, ses.hash, SHA1_HASH_SIZE); | |
166 | |
167 /* the SSH_MSG_KEXDH_REPLY is done */ | |
168 encrypt_packet(); | |
169 | |
170 TRACE(("leave send_msg_kexdh_reply")); | |
171 } | |
172 | |
173 /* read the client's choice of algorithms */ | |
174 void svr_read_kex() { | |
175 | |
176 algo_type * algo; | |
177 char * erralgo = NULL; | |
178 | |
179 int goodguess = 0; | |
180 int allgood = 1; /* we AND this with each goodguess and see if its still | |
181 true after */ | |
182 | |
183 buf_incrpos(ses.payload, 16); /* start after the cookie */ | |
184 | |
185 ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context)); | |
186 | |
187 /* kex_algorithms */ | |
188 algo = svr_buf_match_algo(ses.payload, sshkex, &goodguess); | |
189 allgood &= goodguess; | |
190 if (algo == NULL) { | |
191 erralgo = "kex"; | |
192 goto error; | |
193 } | |
194 ses.newkeys->algo_kex = algo->val; | |
195 | |
196 /* server_host_key_algorithms */ | |
197 algo = svr_buf_match_algo(ses.payload, sshhostkey, &goodguess); | |
198 allgood &= goodguess; | |
199 if (algo == NULL) { | |
200 erralgo = "hostkey"; | |
201 goto error; | |
202 } | |
203 ses.newkeys->algo_hostkey = algo->val; | |
204 | |
205 /* encryption_algorithms_client_to_server */ | |
206 algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess); | |
207 if (algo == NULL) { | |
208 erralgo = "enc c->s"; | |
209 goto error; | |
210 } | |
211 ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data; | |
212 | |
213 /* encryption_algorithms_server_to_client */ | |
214 algo = svr_buf_match_algo(ses.payload, sshciphers, &goodguess); | |
215 if (algo == NULL) { | |
216 erralgo = "enc s->c"; | |
217 goto error; | |
218 } | |
219 ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data; | |
220 | |
221 /* mac_algorithms_client_to_server */ | |
222 algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess); | |
223 if (algo == NULL) { | |
224 erralgo = "mac c->s"; | |
225 goto error; | |
226 } | |
227 ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data; | |
228 | |
229 /* mac_algorithms_server_to_client */ | |
230 algo = svr_buf_match_algo(ses.payload, sshhashes, &goodguess); | |
231 if (algo == NULL) { | |
232 erralgo = "mac s->c"; | |
233 goto error; | |
234 } | |
235 ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data; | |
236 | |
237 /* compression_algorithms_client_to_server */ | |
238 algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess); | |
239 if (algo == NULL) { | |
240 erralgo = "comp c->s"; | |
241 goto error; | |
242 } | |
243 ses.newkeys->recv_algo_comp = algo->val; | |
244 | |
245 /* compression_algorithms_server_to_client */ | |
246 algo = svr_buf_match_algo(ses.payload, sshcompress, &goodguess); | |
247 if (algo == NULL) { | |
248 erralgo = "comp s->c"; | |
249 goto error; | |
250 } | |
251 ses.newkeys->trans_algo_comp = algo->val; | |
252 | |
253 /* languages_client_to_server */ | |
254 buf_eatstring(ses.payload); | |
255 | |
256 /* languages_server_to_client */ | |
257 buf_eatstring(ses.payload); | |
258 | |
259 /* first_kex_packet_follows */ | |
260 if (buf_getbyte(ses.payload)) { | |
261 ses.kexstate.firstfollows = 1; | |
262 /* if the guess wasn't good, we ignore the packet sent */ | |
263 if (!allgood) { | |
264 ses.ignorenext = 1; | |
265 } | |
266 } | |
267 | |
268 /* reserved for future extensions */ | |
269 buf_getint(ses.payload); | |
270 return; | |
271 | |
272 error: | |
273 dropbear_exit("no matching algo %s", erralgo); | |
274 } |