comparison cli-kex.c @ 51:095d689fed16

- Hostkey checking is mostly there, just aren't appending yet. - Rearranged various bits of the fingerprint/base64 type code, so it can be shared between versions
author Matt Johnston <matt@ucc.asn.au>
date Sun, 08 Aug 2004 16:17:05 +0000
parents e2a1eaa19f22
children bdc97a5719f4
comparison
equal deleted inserted replaced
49:cc59bfcdee17 51:095d689fed16
35 #include "random.h" 35 #include "random.h"
36 #include "runopts.h" 36 #include "runopts.h"
37 #include "signkey.h" 37 #include "signkey.h"
38 38
39 39
40 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
41 #define MAX_KNOWNHOSTS_LINE 4500
40 42
41 void send_msg_kexdh_init() { 43 void send_msg_kexdh_init() {
42 44
43 cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int)); 45 cli_ses.dh_e = (mp_int*)m_malloc(sizeof(mp_int));
44 cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int)); 46 cli_ses.dh_x = (mp_int*)m_malloc(sizeof(mp_int));
56 /* Handle a diffie-hellman key exchange reply. */ 58 /* Handle a diffie-hellman key exchange reply. */
57 void recv_msg_kexdh_reply() { 59 void recv_msg_kexdh_reply() {
58 60
59 mp_int dh_f; 61 mp_int dh_f;
60 sign_key *hostkey = NULL; 62 sign_key *hostkey = NULL;
61 int type, keylen; 63 unsigned int type, keybloblen;
64 unsigned char* keyblob = NULL;
65
62 66
63 TRACE(("enter recv_msg_kexdh_reply")); 67 TRACE(("enter recv_msg_kexdh_reply"));
64 type = ses.newkeys->algo_hostkey; 68 type = ses.newkeys->algo_hostkey;
65 TRACE(("type is %d", type)); 69 TRACE(("type is %d", type));
66 70
67 hostkey = new_sign_key(); 71 hostkey = new_sign_key();
68 keylen = buf_getint(ses.payload); 72 keybloblen = buf_getint(ses.payload);
73
74 keyblob = buf_getptr(ses.payload, keybloblen);
75 if (!ses.kexstate.donefirstkex) {
76 /* Only makes sense the first time */
77 checkhostkey(keyblob, keybloblen);
78 }
69 79
70 if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) { 80 if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
71 TRACE(("failed getting pubkey")); 81 TRACE(("failed getting pubkey"));
72 dropbear_exit("Bad KEX packet"); 82 dropbear_exit("Bad KEX packet");
73 } 83 }
84 if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE) 94 if (buf_verify(ses.payload, hostkey, ses.hash, SHA1_HASH_SIZE)
85 != DROPBEAR_SUCCESS) { 95 != DROPBEAR_SUCCESS) {
86 dropbear_exit("Bad hostkey signature"); 96 dropbear_exit("Bad hostkey signature");
87 } 97 }
88 98
89 /* XXX TODO */
90 dropbear_log(LOG_WARNING,"Not checking hostkey fingerprint for the moment");
91
92 sign_key_free(hostkey); 99 sign_key_free(hostkey);
93 hostkey = NULL; 100 hostkey = NULL;
94 101
95 send_msg_newkeys(); 102 send_msg_newkeys();
96 ses.requirenext = SSH_MSG_NEWKEYS; 103 ses.requirenext = SSH_MSG_NEWKEYS;
97 TRACE(("leave recv_msg_kexdh_init")); 104 TRACE(("leave recv_msg_kexdh_init"));
98 } 105 }
106
107 static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
108
109 char* fp = NULL;
110
111 fp = sign_key_fingerprint(keyblob, keybloblen);
112 fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n",
113 cli_opts.remotehost,
114 fp);
115
116 if (getc(stdin) == 'y') {
117 m_free(fp);
118 return;
119 }
120
121 dropbear_exit("Didn't validate host key");
122 }
123
124 static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
125
126 char * filename = NULL;
127 FILE *hostsfile = NULL;
128 struct passwd *pw = NULL;
129 unsigned int len, hostlen;
130 const char *algoname = NULL;
131 buffer * line = NULL;
132 int ret;
133
134 pw = getpwuid(getuid());
135
136 if (pw == NULL) {
137 dropbear_exit("Failed to get homedir");
138 }
139
140 len = strlen(pw->pw_dir);
141 filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/
142
143 snprintf(filename, len+18, "%s/.ssh", pw->pw_dir);
144 /* Check that ~/.ssh exists - easiest way is just to mkdir */
145 if (mkdir(filename, S_IRWXU) != 0) {
146 if (errno != EEXIST) {
147 ask_to_confirm(keyblob, keybloblen);
148 goto out; /* only get here on success */
149 }
150 }
151
152 snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir);
153 hostsfile = fopen(filename, "r+");
154 if (hostsfile == NULL) {
155 ask_to_confirm(keyblob, keybloblen);
156 goto out; /* We only get here on success */
157 }
158
159 line = buf_new(MAX_KNOWNHOSTS_LINE);
160 hostlen = strlen(cli_opts.remotehost);
161
162 do {
163 if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
164 TRACE(("failed reading line: prob EOF"));
165 break;
166 }
167
168 /* The line is too short to be sensible */
169 /* "30" is 'enough to hold ssh-dss plus the spaces, ie so we don't
170 * buf_getfoo() past the end and die horribly - the base64 parsing
171 * code is what tiptoes up to the end nicely */
172 if (line->len < (hostlen+30) ) {
173 TRACE(("line is too short to be sensible"));
174 continue;
175 }
176
177 /* Compare hostnames */
178 if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
179 hostlen) != 0) {
180 TRACE(("hosts don't match"));
181 continue;
182 }
183
184 buf_incrpos(line, hostlen);
185 if (buf_getbyte(line) != ' ') {
186 /* there wasn't a space after the hostname, something dodgy */
187 TRACE(("missing space afte matching hostname"));
188 continue;
189 }
190
191 algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &len);
192 if ( strncmp(buf_getptr(line, len), algoname, len) != 0) {
193 TRACE(("algo doesn't match"));
194 continue;
195 }
196
197 buf_incrpos(line, len);
198 if (buf_getbyte(line) != ' ') {
199 TRACE(("missing space after algo"));
200 continue;
201 }
202
203 /* Now we're at the interesting hostkey */
204 ret = cmp_base64_key(keyblob, keybloblen, algoname, len, line);
205
206 if (ret == DROPBEAR_SUCCESS) {
207 /* Good matching key */
208 TRACE(("good matching key"));
209 goto out;
210 }
211
212 /* The keys didn't match. eep. */
213 } while (1); /* keep going 'til something happens */
214
215 /* Key doesn't exist yet */
216 ask_to_confirm(keyblob, keybloblen);
217 /* If we get here, they said yes */
218
219 out:
220 if (hostsfile != NULL) {
221 fclose(hostsfile);
222 }
223 m_free(filename);
224 buf_free(line);
225 }