summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--sshconnect2.c336
2 files changed, 199 insertions, 147 deletions
diff --git a/ChangeLog b/ChangeLog
index 795bae3c4..f02114c01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,6 +45,14 @@
45 - markus@cvs.openbsd.org 2003/05/11 20:30:25 45 - markus@cvs.openbsd.org 2003/05/11 20:30:25
46 [channels.c clientloop.c serverloop.c session.c ssh.c] 46 [channels.c clientloop.c serverloop.c session.c ssh.c]
47 make channel_new() strdup the 'remote_name' (not the caller); ok theo 47 make channel_new() strdup the 'remote_name' (not the caller); ok theo
48 - markus@cvs.openbsd.org 2003/05/12 16:55:37
49 [sshconnect2.c]
50 for pubkey authentication try the user keys in the following order:
51 1. agent keys that are found in the config file
52 2. other agent keys
53 3. keys that are only listed in the config file
54 this helps when an agent has many keys, where the server might
55 close the connection before the correct key is used. report & ok pb@
48 56
4920030512 5720030512
50 - (djm) Redhat spec: Don't install profile.d scripts when not 58 - (djm) Redhat spec: Don't install profile.d scripts when not
@@ -1432,4 +1440,4 @@
1432 save auth method before monitor_reset_key_state(); bugzilla bug #284; 1440 save auth method before monitor_reset_key_state(); bugzilla bug #284;
1433 ok provos@ 1441 ok provos@
1434 1442
1435$Id: ChangeLog,v 1.2688 2003/05/14 03:45:42 djm Exp $ 1443$Id: ChangeLog,v 1.2689 2003/05/14 03:46:00 djm Exp $
diff --git a/sshconnect2.c b/sshconnect2.c
index d32960447..74d699ff2 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.116 2003/04/08 20:21:29 itojun Exp $"); 26RCSID("$OpenBSD: sshconnect2.c,v 1.117 2003/05/12 16:55:37 markus Exp $");
27 27
28#include "ssh.h" 28#include "ssh.h"
29#include "ssh2.h" 29#include "ssh2.h"
@@ -141,10 +141,18 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
141 141
142typedef struct Authctxt Authctxt; 142typedef struct Authctxt Authctxt;
143typedef struct Authmethod Authmethod; 143typedef struct Authmethod Authmethod;
144 144typedef struct identity Identity;
145typedef int sign_cb_fn( 145typedef struct idlist Idlist;
146 Authctxt *authctxt, Key *key, 146
147 u_char **sigp, u_int *lenp, u_char *data, u_int datalen); 147struct identity {
148 TAILQ_ENTRY(identity) next;
149 AuthenticationConnection *ac; /* set if agent supports key */
150 Key *key; /* public/private key */
151 char *filename; /* comment for agent-only keys */
152 int tried;
153 int isprivate; /* key points to the private key */
154};
155TAILQ_HEAD(idlist, identity);
148 156
149struct Authctxt { 157struct Authctxt {
150 const char *server_user; 158 const char *server_user;
@@ -155,9 +163,7 @@ struct Authctxt {
155 int success; 163 int success;
156 char *authlist; 164 char *authlist;
157 /* pubkey */ 165 /* pubkey */
158 Key *last_key; 166 Idlist keys;
159 sign_cb_fn *last_key_sign;
160 int last_key_hint;
161 AuthenticationConnection *agent; 167 AuthenticationConnection *agent;
162 /* hostbased */ 168 /* hostbased */
163 Sensitive *sensitive; 169 Sensitive *sensitive;
@@ -187,8 +193,11 @@ int userauth_hostbased(Authctxt *);
187 193
188void userauth(Authctxt *, char *); 194void userauth(Authctxt *, char *);
189 195
190static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *); 196static int sign_and_send_pubkey(Authctxt *, Identity *);
191static void clear_auth_state(Authctxt *); 197static void clear_auth_state(Authctxt *);
198static void pubkey_prepare(Authctxt *);
199static void pubkey_cleanup(Authctxt *);
200static Key *load_identity_file(char *);
192 201
193static Authmethod *authmethod_get(char *authlist); 202static Authmethod *authmethod_get(char *authlist);
194static Authmethod *authmethod_lookup(const char *name); 203static Authmethod *authmethod_lookup(const char *name);
@@ -251,7 +260,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
251 260
252 /* setup authentication context */ 261 /* setup authentication context */
253 memset(&authctxt, 0, sizeof(authctxt)); 262 memset(&authctxt, 0, sizeof(authctxt));
254 authctxt.agent = ssh_get_authentication_connection(); 263 pubkey_prepare(&authctxt);
255 authctxt.server_user = server_user; 264 authctxt.server_user = server_user;
256 authctxt.local_user = local_user; 265 authctxt.local_user = local_user;
257 authctxt.host = host; 266 authctxt.host = host;
@@ -273,9 +282,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
273 dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 282 dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
274 dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ 283 dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */
275 284
276 if (authctxt.agent != NULL) 285 pubkey_cleanup(&authctxt);
277 ssh_close_authentication_connection(authctxt.agent);
278
279 debug("Authentication succeeded (%s).", authctxt.method->name); 286 debug("Authentication succeeded (%s).", authctxt.method->name);
280} 287}
281void 288void
@@ -360,6 +367,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
360{ 367{
361 Authctxt *authctxt = ctxt; 368 Authctxt *authctxt = ctxt;
362 Key *key = NULL; 369 Key *key = NULL;
370 Identity *id = NULL;
363 Buffer b; 371 Buffer b;
364 int pktype, sent = 0; 372 int pktype, sent = 0;
365 u_int alen, blen; 373 u_int alen, blen;
@@ -382,40 +390,33 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
382 } 390 }
383 packet_check_eom(); 391 packet_check_eom();
384 392
385 debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d", 393 debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
386 pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
387 394
388 do { 395 if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
389 if (authctxt->last_key == NULL || 396 debug("unknown pkalg %s", pkalg);
390 authctxt->last_key_sign == NULL) { 397 goto done;
391 debug("no last key or no sign cb"); 398 }
392 break; 399 if ((key = key_from_blob(pkblob, blen)) == NULL) {
393 } 400 debug("no key from blob. pkalg %s", pkalg);
394 if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { 401 goto done;
395 debug("unknown pkalg %s", pkalg); 402 }
396 break; 403 if (key->type != pktype) {
397 } 404 error("input_userauth_pk_ok: type mismatch "
398 if ((key = key_from_blob(pkblob, blen)) == NULL) { 405 "for decoded key (received %d, expected %d)",
399 debug("no key from blob. pkalg %s", pkalg); 406 key->type, pktype);
400 break; 407 goto done;
401 } 408 }
402 if (key->type != pktype) { 409 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
403 error("input_userauth_pk_ok: type mismatch " 410 debug2("input_userauth_pk_ok: fp %s", fp);
404 "for decoded key (received %d, expected %d)", 411 xfree(fp);
405 key->type, pktype); 412
406 break; 413 TAILQ_FOREACH(id, &authctxt->keys, next) {
407 } 414 if (key_equal(key, id->key)) {
408 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 415 sent = sign_and_send_pubkey(authctxt, id);
409 debug2("input_userauth_pk_ok: fp %s", fp);
410 xfree(fp);
411 if (!key_equal(key, authctxt->last_key)) {
412 debug("key != last_key");
413 break; 416 break;
414 } 417 }
415 sent = sign_and_send_pubkey(authctxt, key, 418 }
416 authctxt->last_key_sign); 419done:
417 } while (0);
418
419 if (key != NULL) 420 if (key != NULL)
420 key_free(key); 421 key_free(key);
421 xfree(pkalg); 422 xfree(pkalg);
@@ -428,7 +429,6 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
428 /* try another method if we did not send a packet */ 429 /* try another method if we did not send a packet */
429 if (sent == 0) 430 if (sent == 0)
430 userauth(authctxt, NULL); 431 userauth(authctxt, NULL);
431
432} 432}
433 433
434int 434int
@@ -547,18 +547,35 @@ clear_auth_state(Authctxt *authctxt)
547{ 547{
548 /* XXX clear authentication state */ 548 /* XXX clear authentication state */
549 dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL); 549 dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
550}
550 551
551 if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) { 552static int
552 debug3("clear_auth_state: key_free %p", authctxt->last_key); 553identity_sign(Identity *id, u_char **sigp, u_int *lenp,
553 key_free(authctxt->last_key); 554 u_char *data, u_int datalen)
554 } 555{
555 authctxt->last_key = NULL; 556 Key *prv;
556 authctxt->last_key_hint = -2; 557 int ret;
557 authctxt->last_key_sign = NULL; 558
559 /* the agent supports this key */
560 if (id->ac)
561 return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
562 data, datalen));
563 /*
564 * we have already loaded the private key or
565 * the private key is stored in external hardware
566 */
567 if (id->isprivate || (id->key->flags & KEY_FLAG_EXT))
568 return (key_sign(id->key, sigp, lenp, data, datalen));
569 /* load the private key from the file */
570 if ((prv = load_identity_file(id->filename)) == NULL)
571 return (-1);
572 ret = key_sign(prv, sigp, lenp, data, datalen);
573 key_free(prv);
574 return (ret);
558} 575}
559 576
560static int 577static int
561sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) 578sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
562{ 579{
563 Buffer b; 580 Buffer b;
564 u_char *blob, *signature; 581 u_char *blob, *signature;
@@ -569,7 +586,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
569 586
570 debug3("sign_and_send_pubkey"); 587 debug3("sign_and_send_pubkey");
571 588
572 if (key_to_blob(k, &blob, &bloblen) == 0) { 589 if (key_to_blob(id->key, &blob, &bloblen) == 0) {
573 /* we cannot handle this key */ 590 /* we cannot handle this key */
574 debug3("sign_and_send_pubkey: cannot handle key"); 591 debug3("sign_and_send_pubkey: cannot handle key");
575 return 0; 592 return 0;
@@ -594,12 +611,12 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
594 } else { 611 } else {
595 buffer_put_cstring(&b, authctxt->method->name); 612 buffer_put_cstring(&b, authctxt->method->name);
596 buffer_put_char(&b, have_sig); 613 buffer_put_char(&b, have_sig);
597 buffer_put_cstring(&b, key_ssh_name(k)); 614 buffer_put_cstring(&b, key_ssh_name(id->key));
598 } 615 }
599 buffer_put_string(&b, blob, bloblen); 616 buffer_put_string(&b, blob, bloblen);
600 617
601 /* generate signature */ 618 /* generate signature */
602 ret = (*sign_callback)(authctxt, k, &signature, &slen, 619 ret = identity_sign(id, &signature, &slen,
603 buffer_ptr(&b), buffer_len(&b)); 620 buffer_ptr(&b), buffer_len(&b));
604 if (ret == -1) { 621 if (ret == -1) {
605 xfree(blob); 622 xfree(blob);
@@ -619,7 +636,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
619 buffer_put_cstring(&b, authctxt->method->name); 636 buffer_put_cstring(&b, authctxt->method->name);
620 buffer_put_char(&b, have_sig); 637 buffer_put_char(&b, have_sig);
621 if (!(datafellows & SSH_BUG_PKAUTH)) 638 if (!(datafellows & SSH_BUG_PKAUTH))
622 buffer_put_cstring(&b, key_ssh_name(k)); 639 buffer_put_cstring(&b, key_ssh_name(id->key));
623 buffer_put_string(&b, blob, bloblen); 640 buffer_put_string(&b, blob, bloblen);
624 } 641 }
625 xfree(blob); 642 xfree(blob);
@@ -643,23 +660,19 @@ sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
643} 660}
644 661
645static int 662static int
646send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback, 663send_pubkey_test(Authctxt *authctxt, Identity *id)
647 int hint)
648{ 664{
649 u_char *blob; 665 u_char *blob;
650 u_int bloblen, have_sig = 0; 666 u_int bloblen, have_sig = 0;
651 667
652 debug3("send_pubkey_test"); 668 debug3("send_pubkey_test");
653 669
654 if (key_to_blob(k, &blob, &bloblen) == 0) { 670 if (key_to_blob(id->key, &blob, &bloblen) == 0) {
655 /* we cannot handle this key */ 671 /* we cannot handle this key */
656 debug3("send_pubkey_test: cannot handle key"); 672 debug3("send_pubkey_test: cannot handle key");
657 return 0; 673 return 0;
658 } 674 }
659 /* register callback for USERAUTH_PK_OK message */ 675 /* register callback for USERAUTH_PK_OK message */
660 authctxt->last_key_sign = sign_callback;
661 authctxt->last_key_hint = hint;
662 authctxt->last_key = k;
663 dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 676 dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
664 677
665 packet_start(SSH2_MSG_USERAUTH_REQUEST); 678 packet_start(SSH2_MSG_USERAUTH_REQUEST);
@@ -668,7 +681,7 @@ send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
668 packet_put_cstring(authctxt->method->name); 681 packet_put_cstring(authctxt->method->name);
669 packet_put_char(have_sig); 682 packet_put_char(have_sig);
670 if (!(datafellows & SSH_BUG_PKAUTH)) 683 if (!(datafellows & SSH_BUG_PKAUTH))
671 packet_put_cstring(key_ssh_name(k)); 684 packet_put_cstring(key_ssh_name(id->key));
672 packet_put_string(blob, bloblen); 685 packet_put_string(blob, bloblen);
673 xfree(blob); 686 xfree(blob);
674 packet_send(); 687 packet_send();
@@ -713,103 +726,134 @@ load_identity_file(char *filename)
713 return private; 726 return private;
714} 727}
715 728
716static int 729/*
717identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp, 730 * try keys in the following order:
718 u_char *data, u_int datalen) 731 * 1. agent keys that are found in the config file
719{ 732 * 2. other agent keys
720 Key *private; 733 * 3. keys that are only listed in the config file
721 int idx, ret; 734 */
722 735static void
723 idx = authctxt->last_key_hint; 736pubkey_prepare(Authctxt *authctxt)
724 if (idx < 0)
725 return -1;
726
727 /* private key is stored in external hardware */
728 if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
729 return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
730
731 private = load_identity_file(options.identity_files[idx]);
732 if (private == NULL)
733 return -1;
734 ret = key_sign(private, sigp, lenp, data, datalen);
735 key_free(private);
736 return ret;
737}
738
739static int
740agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
741 u_char *data, u_int datalen)
742{
743 return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
744}
745
746static int
747key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
748 u_char *data, u_int datalen)
749{ 737{
750 return key_sign(key, sigp, lenp, data, datalen); 738 Identity *id;
739 Idlist agent, files, *preferred;
740 Key *key;
741 AuthenticationConnection *ac;
742 char *comment;
743 int i, found;
744
745 TAILQ_INIT(&agent); /* keys from the agent */
746 TAILQ_INIT(&files); /* keys from the config file */
747 preferred = &authctxt->keys;
748 TAILQ_INIT(preferred); /* preferred order of keys */
749
750 /* list of keys stored in the filesystem */
751 for (i = 0; i < options.num_identity_files; i++) {
752 key = options.identity_keys[i];
753 if (key && key->type == KEY_RSA1)
754 continue;
755 options.identity_keys[i] = NULL;
756 id = xmalloc(sizeof(*id));
757 memset(id, 0, sizeof(*id));
758 id->key = key;
759 id->filename = xstrdup(options.identity_files[i]);
760 TAILQ_INSERT_TAIL(&files, id, next);
761 }
762 /* list of keys supported by the agent */
763 if ((ac = ssh_get_authentication_connection())) {
764 for (key = ssh_get_first_identity(ac, &comment, 2);
765 key != NULL;
766 key = ssh_get_next_identity(ac, &comment, 2)) {
767 found = 0;
768 TAILQ_FOREACH(id, &files, next) {
769 /* agent keys from the config file are preferred */
770 if (key_equal(key, id->key)) {
771 key_free(key);
772 xfree(comment);
773 TAILQ_REMOVE(&files, id, next);
774 TAILQ_INSERT_TAIL(preferred, id, next);
775 id->ac = ac;
776 found = 1;
777 break;
778 }
779 }
780 if (!found) {
781 id = xmalloc(sizeof(*id));
782 memset(id, 0, sizeof(*id));
783 id->key = key;
784 id->filename = comment;
785 id->ac = ac;
786 TAILQ_INSERT_TAIL(&agent, id, next);
787 }
788 }
789 /* append remaining agent keys */
790 for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
791 TAILQ_REMOVE(&agent, id, next);
792 TAILQ_INSERT_TAIL(preferred, id, next);
793 }
794 authctxt->agent = ac;
795 }
796 /* append remaining keys from the config file */
797 for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
798 TAILQ_REMOVE(&files, id, next);
799 TAILQ_INSERT_TAIL(preferred, id, next);
800 }
801 TAILQ_FOREACH(id, preferred, next) {
802 debug2("key: %s (%p)", id->filename, id->key);
803 }
751} 804}
752 805
753static int 806static void
754userauth_pubkey_agent(Authctxt *authctxt) 807pubkey_cleanup(Authctxt *authctxt)
755{ 808{
756 static int called = 0; 809 Identity *id;
757 int ret = 0; 810
758 char *comment; 811 if (authctxt->agent != NULL)
759 Key *k; 812 ssh_close_authentication_connection(authctxt->agent);
760 813 for (id = TAILQ_FIRST(&authctxt->keys); id;
761 if (called == 0) { 814 id = TAILQ_FIRST(&authctxt->keys)) {
762 if (ssh_get_num_identities(authctxt->agent, 2) == 0) 815 TAILQ_REMOVE(&authctxt->keys, id, next);
763 debug2("userauth_pubkey_agent: no keys at all"); 816 if (id->key)
764 called = 1; 817 key_free(id->key);
818 if (id->filename)
819 xfree(id->filename);
820 xfree(id);
765 } 821 }
766 k = ssh_get_next_identity(authctxt->agent, &comment, 2);
767 if (k == NULL) {
768 debug2("userauth_pubkey_agent: no more keys");
769 } else {
770 debug("Offering agent key: %s", comment);
771 xfree(comment);
772 ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
773 if (ret == 0)
774 key_free(k);
775 }
776 if (ret == 0)
777 debug2("userauth_pubkey_agent: no message sent");
778 return ret;
779} 822}
780 823
781int 824int
782userauth_pubkey(Authctxt *authctxt) 825userauth_pubkey(Authctxt *authctxt)
783{ 826{
784 static int idx = 0; 827 Identity *id;
785 int sent = 0; 828 int sent = 0;
786 Key *key;
787 char *filename;
788 829
789 if (authctxt->agent != NULL) { 830 while ((id = TAILQ_FIRST(&authctxt->keys))) {
790 do { 831 if (id->tried++)
791 sent = userauth_pubkey_agent(authctxt); 832 return (0);
792 } while (!sent && authctxt->agent->howmany > 0); 833 TAILQ_REMOVE(&authctxt->keys, id, next);
793 } 834 TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
794 while (!sent && idx < options.num_identity_files) { 835 /*
795 key = options.identity_keys[idx]; 836 * send a test message if we have the public key. for
796 filename = options.identity_files[idx]; 837 * encrypted keys we cannot do this and have to load the
797 if (key == NULL) { 838 * private key instead
798 debug("Trying private key: %s", filename); 839 */
799 key = load_identity_file(filename); 840 if (id->key && id->key->type != KEY_RSA1) {
800 if (key != NULL) { 841 debug("Offering public key: %s", id->filename);
801 sent = sign_and_send_pubkey(authctxt, key, 842 sent = send_pubkey_test(authctxt, id);
802 key_sign_cb); 843 } else if (id->key == NULL) {
803 key_free(key); 844 debug("Trying private key: %s", id->filename);
845 id->key = load_identity_file(id->filename);
846 if (id->key != NULL) {
847 id->isprivate = 1;
848 sent = sign_and_send_pubkey(authctxt, id);
849 key_free(id->key);
850 id->key = NULL;
804 } 851 }
805 } else if (key->type != KEY_RSA1) {
806 debug("Offering public key: %s", filename);
807 sent = send_pubkey_test(authctxt, key,
808 identity_sign_cb, idx);
809 } 852 }
810 idx++; 853 if (sent)
854 return (sent);
811 } 855 }
812 return sent; 856 return (0);
813} 857}
814 858
815/* 859/*