dropbear: update to 2013.62
[tomato.git] / release / src / router / dropbear / svr-kex.c
blobe42a67cd65e57892457e3ddbc4e54bf9a4b082c8
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * Copyright (c) 2004 by Mihnea Stoenescu
6 * All rights reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE. */
26 #include "includes.h"
27 #include "dbutil.h"
28 #include "algo.h"
29 #include "buffer.h"
30 #include "session.h"
31 #include "kex.h"
32 #include "ssh.h"
33 #include "packet.h"
34 #include "bignum.h"
35 #include "dbrandom.h"
36 #include "runopts.h"
37 #include "ecc.h"
38 #include "gensignkey.h"
40 static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs);
42 /* Handle a diffie-hellman key exchange initialisation. This involves
43 * calculating a session key reply value, and corresponding hash. These
44 * are carried out by send_msg_kexdh_reply(). recv_msg_kexdh_init() calls
45 * that function, then brings the new keys into use */
46 void recv_msg_kexdh_init() {
48 DEF_MP_INT(dh_e);
49 buffer *ecdh_qs = NULL;
51 TRACE(("enter recv_msg_kexdh_init"))
52 if (!ses.kexstate.recvkexinit) {
53 dropbear_exit("Premature kexdh_init message received");
56 switch (ses.newkeys->algo_kex->mode) {
57 case DROPBEAR_KEX_NORMAL_DH:
58 m_mp_init(&dh_e);
59 if (buf_getmpint(ses.payload, &dh_e) != DROPBEAR_SUCCESS) {
60 dropbear_exit("Bad kex value");
62 break;
63 case DROPBEAR_KEX_ECDH:
64 case DROPBEAR_KEX_CURVE25519:
65 #if defined(DROPBEAR_ECDH) || defined(DROPBEAR_CURVE25519)
66 ecdh_qs = buf_getstringbuf(ses.payload);
67 #endif
68 break;
70 if (ses.payload->pos != ses.payload->len) {
71 dropbear_exit("Bad kex value");
74 send_msg_kexdh_reply(&dh_e, ecdh_qs);
76 mp_clear(&dh_e);
77 if (ecdh_qs) {
78 buf_free(ecdh_qs);
79 ecdh_qs = NULL;
82 send_msg_newkeys();
83 ses.requirenext[0] = SSH_MSG_NEWKEYS;
84 ses.requirenext[1] = 0;
85 TRACE(("leave recv_msg_kexdh_init"))
88 #ifdef DROPBEAR_DELAY_HOSTKEY
89 static void svr_ensure_hostkey() {
91 const char* fn = NULL;
92 char *fn_temp = NULL;
93 enum signkey_type type = ses.newkeys->algo_hostkey;
94 void **hostkey = signkey_key_ptr(svr_opts.hostkey, type);
95 int ret = DROPBEAR_FAILURE;
97 if (hostkey && *hostkey) {
98 return;
101 switch (type)
103 #ifdef DROPBEAR_RSA
104 case DROPBEAR_SIGNKEY_RSA:
105 fn = RSA_PRIV_FILENAME;
106 break;
107 #endif
108 #ifdef DROPBEAR_DSS
109 case DROPBEAR_SIGNKEY_DSS:
110 fn = DSS_PRIV_FILENAME;
111 break;
112 #endif
113 #ifdef DROPBEAR_ECDSA
114 case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
115 case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
116 case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
117 fn = ECDSA_PRIV_FILENAME;
118 break;
119 #endif
120 default:
121 (void)0;
124 if (readhostkey(fn, svr_opts.hostkey, &type) == DROPBEAR_SUCCESS) {
125 return;
128 fn_temp = m_malloc(strlen(fn) + 20);
129 snprintf(fn_temp, strlen(fn)+20, "%s.tmp%d", fn, getpid());
131 if (signkey_generate(type, 0, fn_temp) == DROPBEAR_FAILURE) {
132 goto out;
135 if (link(fn_temp, fn) < 0) {
136 /* It's OK to get EEXIST - we probably just lost a race
137 with another connection to generate the key */
138 if (errno != EEXIST) {
139 dropbear_log(LOG_ERR, "Failed moving key file to %s: %s", fn,
140 strerror(errno));
141 /* XXX fallback to non-atomic copy for some filesystems? */
142 goto out;
146 ret = readhostkey(fn, svr_opts.hostkey, &type);
148 if (ret == DROPBEAR_SUCCESS) {
149 char *fp = NULL;
150 unsigned int len;
151 buffer *key_buf = buf_new(MAX_PUBKEY_SIZE);
152 buf_put_pub_key(key_buf, svr_opts.hostkey, type);
153 buf_setpos(key_buf, 4);
154 len = key_buf->len - key_buf->pos;
155 fp = sign_key_fingerprint(buf_getptr(key_buf, len), len);
156 dropbear_log(LOG_INFO, "Generated hostkey %s, fingerprint is %s",
157 fn, fp);
158 m_free(fp);
159 buf_free(key_buf);
162 out:
163 if (fn_temp) {
164 unlink(fn_temp);
165 m_free(fn_temp);
168 if (ret == DROPBEAR_FAILURE)
170 dropbear_exit("Couldn't read or generate hostkey %s", fn);
173 #endif
175 /* Generate our side of the diffie-hellman key exchange value (dh_f), and
176 * calculate the session key using the diffie-hellman algorithm. Following
177 * that, the session hash is calculated, and signed with RSA or DSS. The
178 * result is sent to the client.
180 * See the transport RFC4253 section 8 for details
181 * or RFC5656 section 4 for elliptic curve variant. */
182 static void send_msg_kexdh_reply(mp_int *dh_e, buffer *ecdh_qs) {
183 TRACE(("enter send_msg_kexdh_reply"))
185 /* we can start creating the kexdh_reply packet */
186 CHECKCLEARTOWRITE();
188 #ifdef DROPBEAR_DELAY_HOSTKEY
189 if (svr_opts.delay_hostkey)
191 svr_ensure_hostkey();
193 #endif
195 buf_putbyte(ses.writepayload, SSH_MSG_KEXDH_REPLY);
196 buf_put_pub_key(ses.writepayload, svr_opts.hostkey,
197 ses.newkeys->algo_hostkey);
199 switch (ses.newkeys->algo_kex->mode) {
200 case DROPBEAR_KEX_NORMAL_DH:
202 struct kex_dh_param * dh_param = gen_kexdh_param();
203 kexdh_comb_key(dh_param, dh_e, svr_opts.hostkey);
205 /* put f */
206 buf_putmpint(ses.writepayload, &dh_param->pub);
207 free_kexdh_param(dh_param);
209 break;
210 case DROPBEAR_KEX_ECDH:
211 #ifdef DROPBEAR_ECDH
213 struct kex_ecdh_param *ecdh_param = gen_kexecdh_param();
214 kexecdh_comb_key(ecdh_param, ecdh_qs, svr_opts.hostkey);
216 buf_put_ecc_raw_pubkey_string(ses.writepayload, &ecdh_param->key);
217 free_kexecdh_param(ecdh_param);
219 #endif
220 break;
221 case DROPBEAR_KEX_CURVE25519:
222 #ifdef DROPBEAR_CURVE25519
224 struct kex_curve25519_param *param = gen_kexcurve25519_param();
225 kexcurve25519_comb_key(param, ecdh_qs, svr_opts.hostkey);
226 buf_putstring(ses.writepayload, param->pub, CURVE25519_LEN);
227 free_kexcurve25519_param(param);
229 #endif
230 break;
233 /* calc the signature */
234 buf_put_sign(ses.writepayload, svr_opts.hostkey,
235 ses.newkeys->algo_hostkey, ses.hash);
237 /* the SSH_MSG_KEXDH_REPLY is done */
238 encrypt_packet();
240 TRACE(("leave send_msg_kexdh_reply"))