summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2000-10-14 16:23:11 +1100
committerDamien Miller <djm@mindrot.org>2000-10-14 16:23:11 +1100
commit874d77bb134a21a5cf625956b60173376a993ba8 (patch)
tree93dd73b2ff1fbf0ad5f3978a2c4e0d8438a0bf7c /sshconnect2.c
parent89d9796fbedef4eed6956a2c095c7cc25330c28d (diff)
- (djm) Big OpenBSD sync:
- markus@cvs.openbsd.org 2000/09/30 10:27:44 [log.c] allow loglevel debug - markus@cvs.openbsd.org 2000/10/03 11:59:57 [packet.c] hmac->mac - markus@cvs.openbsd.org 2000/10/03 12:03:03 [auth-krb4.c auth-passwd.c auth-rh-rsa.c auth-rhosts.c auth-rsa.c auth1.c] move fake-auth from auth1.c to individual auth methods, disables s/key in debug-msg - markus@cvs.openbsd.org 2000/10/03 12:16:48 ssh.c do not resolve canonname, i have no idea why this was added oin ossh - markus@cvs.openbsd.org 2000/10/09 15:30:44 ssh-keygen.1 ssh-keygen.c -X now reads private ssh.com DSA keys, too. - markus@cvs.openbsd.org 2000/10/09 15:32:34 auth-options.c clear options on every call. - markus@cvs.openbsd.org 2000/10/09 15:51:00 authfd.c authfd.h interop with ssh-agent2, from <res@shore.net> - markus@cvs.openbsd.org 2000/10/10 14:20:45 compat.c use rexexp for version string matching - provos@cvs.openbsd.org 2000/10/10 22:02:18 [kex.c kex.h myproposal.h ssh.h ssh2.h sshconnect2.c sshd.c dh.c dh.h] First rough implementation of the diffie-hellman group exchange. The client can ask the server for bigger groups to perform the diffie-hellman in, thus increasing the attack complexity when using ciphers with longer keys. University of Windsor provided network, T the company. - markus@cvs.openbsd.org 2000/10/11 13:59:52 [auth-rsa.c auth2.c] clear auth options unless auth sucessfull - markus@cvs.openbsd.org 2000/10/11 14:00:27 [auth-options.h] clear auth options unless auth sucessfull - markus@cvs.openbsd.org 2000/10/11 14:03:27 [scp.1 scp.c] support 'scp -o' with help from mouring@pconline.com - markus@cvs.openbsd.org 2000/10/11 14:11:35 [dh.c] Wall - markus@cvs.openbsd.org 2000/10/11 14:14:40 [auth.h auth2.c readconf.c readconf.h readpass.c servconf.c servconf.h] [ssh.h sshconnect2.c sshd_config auth2-skey.c cli.c cli.h] add support for s/key (kbd-interactive) to ssh2, based on work by mkiernan@avantgo.com and me - markus@cvs.openbsd.org 2000/10/11 14:27:24 [auth.c auth1.c auth2.c authfile.c cipher.c cipher.h kex.c kex.h] [myproposal.h packet.c readconf.c session.c ssh.c ssh.h sshconnect1.c] [sshconnect2.c sshd.c] new cipher framework - markus@cvs.openbsd.org 2000/10/11 14:45:21 [cipher.c] remove DES - markus@cvs.openbsd.org 2000/10/12 03:59:20 [cipher.c cipher.h sshconnect1.c sshconnect2.c sshd.c] enable DES in SSH-1 clients only - markus@cvs.openbsd.org 2000/10/12 08:21:13 [kex.h packet.c] remove unused - markus@cvs.openbsd.org 2000/10/13 12:34:46 [sshd.c] Kludge for F-Secure Macintosh < 1.0.2; appro@fy.chalmers.se - markus@cvs.openbsd.org 2000/10/13 12:59:15 [cipher.c cipher.h myproposal.h rijndael.c rijndael.h] rijndael/aes support - markus@cvs.openbsd.org 2000/10/13 13:10:54 [sshd.8] more info about -V - markus@cvs.openbsd.org 2000/10/13 13:12:02 [myproposal.h] prefer no compression
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c461
1 files changed, 381 insertions, 80 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index eee09a19c..ca459f62c 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $"); 26RCSID("$OpenBSD: sshconnect2.c,v 1.25 2000/10/12 09:59:19 markus Exp $");
27 27
28#include <openssl/bn.h> 28#include <openssl/bn.h>
29#include <openssl/rsa.h> 29#include <openssl/rsa.h>
@@ -37,7 +37,6 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
37#include "rsa.h" 37#include "rsa.h"
38#include "buffer.h" 38#include "buffer.h"
39#include "packet.h" 39#include "packet.h"
40#include "cipher.h"
41#include "uidswap.h" 40#include "uidswap.h"
42#include "compat.h" 41#include "compat.h"
43#include "readconf.h" 42#include "readconf.h"
@@ -49,9 +48,13 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.21 2000/09/27 21:41:34 markus Exp $");
49#include "dsa.h" 48#include "dsa.h"
50#include "sshconnect.h" 49#include "sshconnect.h"
51#include "authfile.h" 50#include "authfile.h"
51#include "cli.h"
52#include "dispatch.h" 52#include "dispatch.h"
53#include "authfd.h" 53#include "authfd.h"
54 54
55void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
56void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
57
55/* import */ 58/* import */
56extern char *client_version_string; 59extern char *client_version_string;
57extern char *server_version_string; 60extern char *server_version_string;
@@ -65,8 +68,90 @@ unsigned char *session_id2 = NULL;
65int session_id2_len = 0; 68int session_id2_len = 0;
66 69
67void 70void
68ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, 71ssh_kex2(char *host, struct sockaddr *hostaddr)
69 Buffer *client_kexinit, Buffer *server_kexinit) 72{
73 int i, plen;
74 Kex *kex;
75 Buffer *client_kexinit, *server_kexinit;
76 char *sprop[PROPOSAL_MAX];
77
78 if (options.ciphers == NULL) {
79 if (options.cipher == SSH_CIPHER_3DES) {
80 options.ciphers = "3des-cbc";
81 } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
82 options.ciphers = "blowfish-cbc";
83 } else if (options.cipher == SSH_CIPHER_DES) {
84 fatal("cipher DES not supported for protocol version 2");
85 }
86 }
87 if (options.ciphers != NULL) {
88 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
89 myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
90 }
91 if (options.compression) {
92 myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
93 myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
94 } else {
95 myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
96 myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
97 }
98
99 /* buffers with raw kexinit messages */
100 server_kexinit = xmalloc(sizeof(*server_kexinit));
101 buffer_init(server_kexinit);
102 client_kexinit = kex_init(myproposal);
103
104 /* algorithm negotiation */
105 kex_exchange_kexinit(client_kexinit, server_kexinit, sprop);
106 kex = kex_choose_conf(myproposal, sprop, 0);
107 for (i = 0; i < PROPOSAL_MAX; i++)
108 xfree(sprop[i]);
109
110 /* server authentication and session key agreement */
111 switch(kex->kex_type) {
112 case DH_GRP1_SHA1:
113 ssh_dh1_client(kex, host, hostaddr,
114 client_kexinit, server_kexinit);
115 break;
116 case DH_GEX_SHA1:
117 ssh_dhgex_client(kex, host, hostaddr, client_kexinit,
118 server_kexinit);
119 break;
120 default:
121 fatal("Unsupported key exchange %d", kex->kex_type);
122 }
123
124 buffer_free(client_kexinit);
125 buffer_free(server_kexinit);
126 xfree(client_kexinit);
127 xfree(server_kexinit);
128
129 debug("Wait SSH2_MSG_NEWKEYS.");
130 packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
131 packet_done();
132 debug("GOT SSH2_MSG_NEWKEYS.");
133
134 debug("send SSH2_MSG_NEWKEYS.");
135 packet_start(SSH2_MSG_NEWKEYS);
136 packet_send();
137 packet_write_wait();
138 debug("done: send SSH2_MSG_NEWKEYS.");
139
140#ifdef DEBUG_KEXDH
141 /* send 1st encrypted/maced/compressed message */
142 packet_start(SSH2_MSG_IGNORE);
143 packet_put_cstring("markus");
144 packet_send();
145 packet_write_wait();
146#endif
147 debug("done: KEX2.");
148}
149
150/* diffie-hellman-group1-sha1 */
151
152void
153ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr,
154 Buffer *client_kexinit, Buffer *server_kexinit)
70{ 155{
71#ifdef DEBUG_KEXDH 156#ifdef DEBUG_KEXDH
72 int i; 157 int i;
@@ -116,7 +201,7 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
116 fatal("cannot decode server_host_key_blob"); 201 fatal("cannot decode server_host_key_blob");
117 202
118 check_host_key(host, hostaddr, server_host_key, 203 check_host_key(host, hostaddr, server_host_key,
119 options.user_hostfile2, options.system_hostfile2); 204 options.user_hostfile2, options.system_hostfile2);
120 205
121 /* DH paramter f, server public DH key */ 206 /* DH paramter f, server public DH key */
122 dh_server_pub = BN_new(); 207 dh_server_pub = BN_new();
@@ -186,72 +271,175 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr,
186 memcpy(session_id2, hash, session_id2_len); 271 memcpy(session_id2, hash, session_id2_len);
187} 272}
188 273
274/* diffie-hellman-group-exchange-sha1 */
275
276/*
277 * Estimates the group order for a Diffie-Hellman group that has an
278 * attack complexity approximately the same as O(2**bits). Estimate
279 * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3)))
280 */
281
282int
283dh_estimate(int bits)
284{
285
286 if (bits < 64)
287 return (512); /* O(2**63) */
288 if (bits < 128)
289 return (1024); /* O(2**86) */
290 if (bits < 192)
291 return (2048); /* O(2**116) */
292 return (4096); /* O(2**156) */
293}
294
189void 295void
190ssh_kex2(char *host, struct sockaddr *hostaddr) 296ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr,
297 Buffer *client_kexinit, Buffer *server_kexinit)
191{ 298{
192 int i, plen; 299#ifdef DEBUG_KEXDH
193 Kex *kex; 300 int i;
194 Buffer *client_kexinit, *server_kexinit; 301#endif
195 char *sprop[PROPOSAL_MAX]; 302 int plen, dlen;
303 unsigned int klen, kout;
304 char *signature = NULL;
305 unsigned int slen, nbits;
306 char *server_host_key_blob = NULL;
307 Key *server_host_key;
308 unsigned int sbloblen;
309 DH *dh;
310 BIGNUM *dh_server_pub = 0;
311 BIGNUM *shared_secret = 0;
312 BIGNUM *p = 0, *g = 0;
313 unsigned char *kbuf;
314 unsigned char *hash;
196 315
197 if (options.ciphers != NULL) { 316 nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8);
198 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
199 myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
200 } else if (options.cipher == SSH_CIPHER_3DES) {
201 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
202 myproposal[PROPOSAL_ENC_ALGS_STOC] =
203 (char *) cipher_name(SSH_CIPHER_3DES_CBC);
204 } else if (options.cipher == SSH_CIPHER_BLOWFISH) {
205 myproposal[PROPOSAL_ENC_ALGS_CTOS] =
206 myproposal[PROPOSAL_ENC_ALGS_STOC] =
207 (char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC);
208 }
209 if (options.compression) {
210 myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
211 myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
212 } else {
213 myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
214 myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
215 }
216 317
217 /* buffers with raw kexinit messages */ 318 debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
218 server_kexinit = xmalloc(sizeof(*server_kexinit)); 319 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
219 buffer_init(server_kexinit); 320 packet_put_int(nbits);
220 client_kexinit = kex_init(myproposal); 321 packet_send();
322 packet_write_wait();
221 323
222 /* algorithm negotiation */ 324#ifdef DEBUG_KEXDH
223 kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); 325 fprintf(stderr, "\nnbits = %d", nbits);
224 kex = kex_choose_conf(myproposal, sprop, 0); 326#endif
225 for (i = 0; i < PROPOSAL_MAX; i++)
226 xfree(sprop[i]);
227 327
228 /* server authentication and session key agreement */ 328 debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP.");
229 ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit);
230 329
231 buffer_free(client_kexinit); 330 packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP);
232 buffer_free(server_kexinit);
233 xfree(client_kexinit);
234 xfree(server_kexinit);
235 331
236 debug("Wait SSH2_MSG_NEWKEYS."); 332 debug("Got SSH2_MSG_KEX_DH_GEX_GROUP.");
237 packet_read_expect(&plen, SSH2_MSG_NEWKEYS);
238 packet_done();
239 debug("GOT SSH2_MSG_NEWKEYS.");
240 333
241 debug("send SSH2_MSG_NEWKEYS."); 334 if ((p = BN_new()) == NULL)
242 packet_start(SSH2_MSG_NEWKEYS); 335 fatal("BN_new");
243 packet_send(); 336 packet_get_bignum2(p, &dlen);
244 packet_write_wait(); 337 if ((g = BN_new()) == NULL)
245 debug("done: send SSH2_MSG_NEWKEYS."); 338 fatal("BN_new");
339 packet_get_bignum2(g, &dlen);
340 if ((dh = dh_new_group(g, p)) == NULL)
341 fatal("dh_new_group");
246 342
247#ifdef DEBUG_KEXDH 343#ifdef DEBUG_KEXDH
248 /* send 1st encrypted/maced/compressed message */ 344 fprintf(stderr, "\np= ");
249 packet_start(SSH2_MSG_IGNORE); 345 BN_print_fp(stderr, dh->p);
250 packet_put_cstring("markus"); 346 fprintf(stderr, "\ng= ");
347 BN_print_fp(stderr, dh->g);
348 fprintf(stderr, "\npub= ");
349 BN_print_fp(stderr, dh->pub_key);
350 fprintf(stderr, "\n");
351 DHparams_print_fp(stderr, dh);
352#endif
353
354 debug("Sending SSH2_MSG_KEX_DH_GEX_INIT.");
355 /* generate and send 'e', client DH public key */
356 packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
357 packet_put_bignum2(dh->pub_key);
251 packet_send(); 358 packet_send();
252 packet_write_wait(); 359 packet_write_wait();
360
361 debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY.");
362
363 packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY);
364
365 debug("Got SSH2_MSG_KEXDH_REPLY.");
366
367 /* key, cert */
368 server_host_key_blob = packet_get_string(&sbloblen);
369 server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
370 if (server_host_key == NULL)
371 fatal("cannot decode server_host_key_blob");
372
373 check_host_key(host, hostaddr, server_host_key,
374 options.user_hostfile2, options.system_hostfile2);
375
376 /* DH paramter f, server public DH key */
377 dh_server_pub = BN_new();
378 if (dh_server_pub == NULL)
379 fatal("dh_server_pub == NULL");
380 packet_get_bignum2(dh_server_pub, &dlen);
381
382#ifdef DEBUG_KEXDH
383 fprintf(stderr, "\ndh_server_pub= ");
384 BN_print_fp(stderr, dh_server_pub);
385 fprintf(stderr, "\n");
386 debug("bits %d", BN_num_bits(dh_server_pub));
253#endif 387#endif
254 debug("done: KEX2."); 388
389 /* signed H */
390 signature = packet_get_string(&slen);
391 packet_done();
392
393 if (!dh_pub_is_valid(dh, dh_server_pub))
394 packet_disconnect("bad server public DH value");
395
396 klen = DH_size(dh);
397 kbuf = xmalloc(klen);
398 kout = DH_compute_key(kbuf, dh_server_pub, dh);
399#ifdef DEBUG_KEXDH
400 debug("shared secret: len %d/%d", klen, kout);
401 fprintf(stderr, "shared secret == ");
402 for (i = 0; i< kout; i++)
403 fprintf(stderr, "%02x", (kbuf[i])&0xff);
404 fprintf(stderr, "\n");
405#endif
406 shared_secret = BN_new();
407
408 BN_bin2bn(kbuf, kout, shared_secret);
409 memset(kbuf, 0, klen);
410 xfree(kbuf);
411
412 /* calc and verify H */
413 hash = kex_hash_gex(
414 client_version_string,
415 server_version_string,
416 buffer_ptr(client_kexinit), buffer_len(client_kexinit),
417 buffer_ptr(server_kexinit), buffer_len(server_kexinit),
418 server_host_key_blob, sbloblen,
419 nbits, dh->p, dh->g,
420 dh->pub_key,
421 dh_server_pub,
422 shared_secret
423 );
424 xfree(server_host_key_blob);
425 DH_free(dh);
426#ifdef DEBUG_KEXDH
427 fprintf(stderr, "hash == ");
428 for (i = 0; i< 20; i++)
429 fprintf(stderr, "%02x", (hash[i])&0xff);
430 fprintf(stderr, "\n");
431#endif
432 if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
433 fatal("dsa_verify failed for server_host_key");
434 key_free(server_host_key);
435
436 kex_derive_keys(kex, hash, shared_secret);
437 packet_set_kex(kex);
438
439 /* save session id */
440 session_id2_len = 20;
441 session_id2 = xmalloc(session_id2_len);
442 memcpy(session_id2, hash, session_id2_len);
255} 443}
256 444
257/* 445/*
@@ -270,8 +458,8 @@ struct Authctxt {
270 const char *host; 458 const char *host;
271 const char *service; 459 const char *service;
272 AuthenticationConnection *agent; 460 AuthenticationConnection *agent;
273 int success;
274 Authmethod *method; 461 Authmethod *method;
462 int success;
275}; 463};
276struct Authmethod { 464struct Authmethod {
277 char *name; /* string to compare against server's list */ 465 char *name; /* string to compare against server's list */
@@ -283,11 +471,16 @@ struct Authmethod {
283void input_userauth_success(int type, int plen, void *ctxt); 471void input_userauth_success(int type, int plen, void *ctxt);
284void input_userauth_failure(int type, int plen, void *ctxt); 472void input_userauth_failure(int type, int plen, void *ctxt);
285void input_userauth_error(int type, int plen, void *ctxt); 473void input_userauth_error(int type, int plen, void *ctxt);
474void input_userauth_info_req(int type, int plen, void *ctxt);
475
476int userauth_none(Authctxt *authctxt);
286int userauth_pubkey(Authctxt *authctxt); 477int userauth_pubkey(Authctxt *authctxt);
287int userauth_passwd(Authctxt *authctxt); 478int userauth_passwd(Authctxt *authctxt);
479int userauth_kbdint(Authctxt *authctxt);
288 480
289void authmethod_clear(); 481void authmethod_clear();
290Authmethod *authmethod_get(char *auth_list); 482Authmethod *authmethod_get(char *authlist);
483Authmethod *authmethod_lookup(const char *name);
291 484
292Authmethod authmethods[] = { 485Authmethod authmethods[] = {
293 {"publickey", 486 {"publickey",
@@ -298,6 +491,14 @@ Authmethod authmethods[] = {
298 userauth_passwd, 491 userauth_passwd,
299 &options.password_authentication, 492 &options.password_authentication,
300 &options.batch_mode}, 493 &options.batch_mode},
494 {"keyboard-interactive",
495 userauth_kbdint,
496 &options.kbd_interactive_authentication,
497 &options.batch_mode},
498 {"none",
499 userauth_none,
500 NULL,
501 NULL},
301 {NULL, NULL, NULL, NULL} 502 {NULL, NULL, NULL, NULL}
302}; 503};
303 504
@@ -334,17 +535,13 @@ ssh_userauth2(const char *server_user, char *host)
334 authctxt.host = host; 535 authctxt.host = host;
335 authctxt.service = "ssh-connection"; /* service name */ 536 authctxt.service = "ssh-connection"; /* service name */
336 authctxt.success = 0; 537 authctxt.success = 0;
337 authctxt.method = NULL; 538 authctxt.method = authmethod_lookup("none");
539 if (authctxt.method == NULL)
540 fatal("ssh_userauth2: internal error: cannot send userauth none request");
541 authmethod_clear();
338 542
339 /* initial userauth request */ 543 /* initial userauth request */
340 packet_start(SSH2_MSG_USERAUTH_REQUEST); 544 userauth_none(&authctxt);
341 packet_put_cstring(authctxt.server_user);
342 packet_put_cstring(authctxt.service);
343 packet_put_cstring("none");
344 packet_send();
345 packet_write_wait();
346
347 authmethod_clear();
348 545
349 dispatch_init(&input_userauth_error); 546 dispatch_init(&input_userauth_error);
350 dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 547 dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
@@ -354,7 +551,7 @@ ssh_userauth2(const char *server_user, char *host)
354 if (authctxt.agent != NULL) 551 if (authctxt.agent != NULL)
355 ssh_close_authentication_connection(authctxt.agent); 552 ssh_close_authentication_connection(authctxt.agent);
356 553
357 debug("ssh-userauth2 successfull"); 554 debug("ssh-userauth2 successfull: method %s", authctxt.method->name);
358} 555}
359void 556void
360input_userauth_error(int type, int plen, void *ctxt) 557input_userauth_error(int type, int plen, void *ctxt)
@@ -376,12 +573,11 @@ input_userauth_failure(int type, int plen, void *ctxt)
376 Authctxt *authctxt = ctxt; 573 Authctxt *authctxt = ctxt;
377 char *authlist = NULL; 574 char *authlist = NULL;
378 int partial; 575 int partial;
379 int dlen;
380 576
381 if (authctxt == NULL) 577 if (authctxt == NULL)
382 fatal("input_userauth_failure: no authentication context"); 578 fatal("input_userauth_failure: no authentication context");
383 579
384 authlist = packet_get_string(&dlen); 580 authlist = packet_get_string(NULL);
385 partial = packet_get_char(); 581 partial = packet_get_char();
386 packet_done(); 582 packet_done();
387 583
@@ -390,12 +586,12 @@ input_userauth_failure(int type, int plen, void *ctxt)
390 debug("authentications that can continue: %s", authlist); 586 debug("authentications that can continue: %s", authlist);
391 587
392 for (;;) { 588 for (;;) {
393 /* try old method or get next method */
394 method = authmethod_get(authlist); 589 method = authmethod_get(authlist);
395 if (method == NULL) 590 if (method == NULL)
396 fatal("Unable to find an authentication method"); 591 fatal("Unable to find an authentication method");
592 authctxt->method = method;
397 if (method->userauth(authctxt) != 0) { 593 if (method->userauth(authctxt) != 0) {
398 debug2("we sent a packet, wait for reply"); 594 debug2("we sent a %s packet, wait for reply", method->name);
399 break; 595 break;
400 } else { 596 } else {
401 debug2("we did not send a packet, disable method"); 597 debug2("we did not send a packet, disable method");
@@ -406,6 +602,19 @@ input_userauth_failure(int type, int plen, void *ctxt)
406} 602}
407 603
408int 604int
605userauth_none(Authctxt *authctxt)
606{
607 /* initial userauth request */
608 packet_start(SSH2_MSG_USERAUTH_REQUEST);
609 packet_put_cstring(authctxt->server_user);
610 packet_put_cstring(authctxt->service);
611 packet_put_cstring(authctxt->method->name);
612 packet_send();
613 packet_write_wait();
614 return 1;
615}
616
617int
409userauth_passwd(Authctxt *authctxt) 618userauth_passwd(Authctxt *authctxt)
410{ 619{
411 static int attempt = 0; 620 static int attempt = 0;
@@ -424,7 +633,7 @@ userauth_passwd(Authctxt *authctxt)
424 packet_start(SSH2_MSG_USERAUTH_REQUEST); 633 packet_start(SSH2_MSG_USERAUTH_REQUEST);
425 packet_put_cstring(authctxt->server_user); 634 packet_put_cstring(authctxt->server_user);
426 packet_put_cstring(authctxt->service); 635 packet_put_cstring(authctxt->service);
427 packet_put_cstring("password"); 636 packet_put_cstring(authctxt->method->name);
428 packet_put_char(0); 637 packet_put_char(0);
429 packet_put_cstring(password); 638 packet_put_cstring(password);
430 memset(password, 0, strlen(password)); 639 memset(password, 0, strlen(password));
@@ -442,6 +651,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
442 int bloblen, slen; 651 int bloblen, slen;
443 int skip = 0; 652 int skip = 0;
444 int ret = -1; 653 int ret = -1;
654 int have_sig = 1;
445 655
446 dsa_make_key_blob(k, &blob, &bloblen); 656 dsa_make_key_blob(k, &blob, &bloblen);
447 657
@@ -460,8 +670,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
460 datafellows & SSH_BUG_PUBKEYAUTH ? 670 datafellows & SSH_BUG_PUBKEYAUTH ?
461 "ssh-userauth" : 671 "ssh-userauth" :
462 authctxt->service); 672 authctxt->service);
463 buffer_put_cstring(&b, "publickey"); 673 buffer_put_cstring(&b, authctxt->method->name);
464 buffer_put_char(&b, 1); 674 buffer_put_char(&b, have_sig);
465 buffer_put_cstring(&b, KEX_DSS); 675 buffer_put_cstring(&b, KEX_DSS);
466 buffer_put_string(&b, blob, bloblen); 676 buffer_put_string(&b, blob, bloblen);
467 677
@@ -481,8 +691,8 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
481 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 691 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
482 buffer_put_cstring(&b, authctxt->server_user); 692 buffer_put_cstring(&b, authctxt->server_user);
483 buffer_put_cstring(&b, authctxt->service); 693 buffer_put_cstring(&b, authctxt->service);
484 buffer_put_cstring(&b, "publickey"); 694 buffer_put_cstring(&b, authctxt->method->name);
485 buffer_put_char(&b, 1); 695 buffer_put_char(&b, have_sig);
486 buffer_put_cstring(&b, KEX_DSS); 696 buffer_put_cstring(&b, KEX_DSS);
487 buffer_put_string(&b, blob, bloblen); 697 buffer_put_string(&b, blob, bloblen);
488 } 698 }
@@ -606,6 +816,92 @@ userauth_pubkey(Authctxt *authctxt)
606 return sent; 816 return sent;
607} 817}
608 818
819/*
820 * Send userauth request message specifying keyboard-interactive method.
821 */
822int
823userauth_kbdint(Authctxt *authctxt)
824{
825 static int attempt = 0;
826
827 if (attempt++ >= options.number_of_password_prompts)
828 return 0;
829
830 debug2("userauth_kbdint");
831 packet_start(SSH2_MSG_USERAUTH_REQUEST);
832 packet_put_cstring(authctxt->server_user);
833 packet_put_cstring(authctxt->service);
834 packet_put_cstring(authctxt->method->name);
835 packet_put_cstring(""); /* lang */
836 packet_put_cstring(options.kbd_interactive_devices ?
837 options.kbd_interactive_devices : "");
838 packet_send();
839 packet_write_wait();
840
841 dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
842 return 1;
843}
844
845/*
846 * parse SSH2_MSG_USERAUTH_INFO_REQUEST, prompt user and send
847 * SSH2_MSG_USERAUTH_INFO_RESPONSE
848 */
849void
850input_userauth_info_req(int type, int plen, void *ctxt)
851{
852 Authctxt *authctxt = ctxt;
853 char *name = NULL;
854 char *inst = NULL;
855 char *lang = NULL;
856 char *prompt = NULL;
857 char *response = NULL;
858 unsigned int num_prompts, i;
859 int echo = 0;
860
861 debug2("input_userauth_info_req");
862
863 if (authctxt == NULL)
864 fatal("input_userauth_info_req: no authentication context");
865
866 name = packet_get_string(NULL);
867 inst = packet_get_string(NULL);
868 lang = packet_get_string(NULL);
869
870 if (strlen(name) > 0)
871 cli_mesg(name);
872 xfree(name);
873
874 if (strlen(inst) > 0)
875 cli_mesg(inst);
876 xfree(inst);
877 xfree(lang); /* unused */
878
879 num_prompts = packet_get_int();
880 /*
881 * Begin to build info response packet based on prompts requested.
882 * We commit to providing the correct number of responses, so if
883 * further on we run into a problem that prevents this, we have to
884 * be sure and clean this up and send a correct error response.
885 */
886 packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE);
887 packet_put_int(num_prompts);
888
889 for (i = 0; i < num_prompts; i++) {
890 prompt = packet_get_string(NULL);
891 echo = packet_get_char();
892
893 response = cli_prompt(prompt, echo);
894
895 packet_put_cstring(response);
896 memset(response, 0, strlen(response));
897 xfree(response);
898 xfree(prompt);
899 }
900 packet_done(); /* done with parsing incoming message. */
901
902 packet_send();
903 packet_write_wait();
904}
609 905
610/* find auth method */ 906/* find auth method */
611 907
@@ -692,6 +988,7 @@ authmethod_get(char *authlist)
692 988
693 if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) { 989 if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {
694 /* start over if passed a different list */ 990 /* start over if passed a different list */
991 debug3("start over, passed a different list");
695 authmethod_clear(); 992 authmethod_clear();
696 authlist_current = xstrdup(authlist); 993 authlist_current = xstrdup(authlist);
697 authlist_working = xstrdup(authlist); 994 authlist_working = xstrdup(authlist);
@@ -706,16 +1003,20 @@ authmethod_get(char *authlist)
706 } 1003 }
707 1004
708 while (name != NULL) { 1005 while (name != NULL) {
1006 debug3("authmethod_lookup %s", name);
709 method = authmethod_lookup(name); 1007 method = authmethod_lookup(name);
710 if (method != NULL && authmethod_is_enabled(method)) 1008 if (method != NULL && authmethod_is_enabled(method)) {
1009 debug3("authmethod_is_enabled %s", name);
711 break; 1010 break;
1011 }
712 name = strtok_r(NULL, DELIM, &authlist_state); 1012 name = strtok_r(NULL, DELIM, &authlist_state);
1013 method = NULL;
713 } 1014 }
714 1015
715 if (authname_current != NULL) 1016 if (authname_current != NULL)
716 xfree(authname_current); 1017 xfree(authname_current);
717 1018
718 if (name != NULL) { 1019 if (method != NULL) {
719 debug("next auth method to try is %s", name); 1020 debug("next auth method to try is %s", name);
720 authname_current = xstrdup(name); 1021 authname_current = xstrdup(name);
721 return method; 1022 return method;