summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c106
1 files changed, 91 insertions, 15 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 3e57e859d..9de52224d 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.214 2009/05/28 16:50:16 andreas Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -28,6 +28,7 @@
28 28
29#include <ctype.h> 29#include <ctype.h>
30#include <errno.h> 30#include <errno.h>
31#include <fcntl.h>
31#include <netdb.h> 32#include <netdb.h>
32#ifdef HAVE_PATHS_H 33#ifdef HAVE_PATHS_H
33#include <paths.h> 34#include <paths.h>
@@ -57,6 +58,7 @@
57#include "misc.h" 58#include "misc.h"
58#include "dns.h" 59#include "dns.h"
59#include "roaming.h" 60#include "roaming.h"
61#include "ssh2.h"
60#include "version.h" 62#include "version.h"
61 63
62char *client_version_string = NULL; 64char *client_version_string = NULL;
@@ -191,8 +193,11 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
191 return sock; 193 return sock;
192 } 194 }
193 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 195 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
194 if (sock < 0) 196 if (sock < 0) {
195 error("socket: %.100s", strerror(errno)); 197 error("socket: %.100s", strerror(errno));
198 return -1;
199 }
200 fcntl(sock, F_SETFD, FD_CLOEXEC);
196 201
197 /* Bind the socket to an alternative local IP address */ 202 /* Bind the socket to an alternative local IP address */
198 if (options.bind_address == NULL) 203 if (options.bind_address == NULL)
@@ -572,6 +577,23 @@ confirm(const char *prompt)
572 } 577 }
573} 578}
574 579
580static int
581check_host_cert(const char *host, const Key *host_key)
582{
583 const char *reason;
584
585 if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) {
586 error("%s", reason);
587 return 0;
588 }
589 if (buffer_len(&host_key->cert->constraints) != 0) {
590 error("Certificate for %s contains unsupported constraint(s)",
591 host);
592 return 0;
593 }
594 return 1;
595}
596
575/* 597/*
576 * check whether the supplied host key is valid, return -1 if the key 598 * check whether the supplied host key is valid, return -1 if the key
577 * is not valid. the user_hostfile will not be updated if 'readonly' is true. 599 * is not valid. the user_hostfile will not be updated if 'readonly' is true.
@@ -584,13 +606,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
584 Key *host_key, int readonly, const char *user_hostfile, 606 Key *host_key, int readonly, const char *user_hostfile,
585 const char *system_hostfile) 607 const char *system_hostfile)
586{ 608{
587 Key *file_key; 609 Key *file_key, *raw_key = NULL;
588 const char *type = key_type(host_key); 610 const char *type;
589 char *ip = NULL, *host = NULL; 611 char *ip = NULL, *host = NULL;
590 char hostline[1000], *hostp, *fp, *ra; 612 char hostline[1000], *hostp, *fp, *ra;
591 HostStatus host_status; 613 HostStatus host_status;
592 HostStatus ip_status; 614 HostStatus ip_status;
593 int r, local = 0, host_ip_differ = 0; 615 int r, want_cert, local = 0, host_ip_differ = 0;
594 int salen; 616 int salen;
595 char ntop[NI_MAXHOST]; 617 char ntop[NI_MAXHOST];
596 char msg[1024]; 618 char msg[1024];
@@ -663,11 +685,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
663 host = put_host_port(hostname, port); 685 host = put_host_port(hostname, port);
664 } 686 }
665 687
688 retry:
689 want_cert = key_is_cert(host_key);
690 type = key_type(host_key);
691
666 /* 692 /*
667 * Store the host key from the known host file in here so that we can 693 * Store the host key from the known host file in here so that we can
668 * compare it with the key for the IP address. 694 * compare it with the key for the IP address.
669 */ 695 */
670 file_key = key_new(host_key->type); 696 file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type);
671 697
672 /* 698 /*
673 * Check if the host key is present in the user's list of known 699 * Check if the host key is present in the user's list of known
@@ -683,9 +709,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
683 } 709 }
684 /* 710 /*
685 * Also perform check for the ip address, skip the check if we are 711 * Also perform check for the ip address, skip the check if we are
686 * localhost or the hostname was an ip address to begin with 712 * localhost, looking for a certificate, or the hostname was an ip
713 * address to begin with.
687 */ 714 */
688 if (options.check_host_ip) { 715 if (!want_cert && options.check_host_ip) {
689 Key *ip_key = key_new(host_key->type); 716 Key *ip_key = key_new(host_key->type);
690 717
691 ip_file = user_hostfile; 718 ip_file = user_hostfile;
@@ -709,11 +736,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
709 switch (host_status) { 736 switch (host_status) {
710 case HOST_OK: 737 case HOST_OK:
711 /* The host is known and the key matches. */ 738 /* The host is known and the key matches. */
712 debug("Host '%.200s' is known and matches the %s host key.", 739 debug("Host '%.200s' is known and matches the %s host %s.",
713 host, type); 740 host, type, want_cert ? "certificate" : "key");
714 debug("Found key in %s:%d", host_file, host_line); 741 debug("Found %s in %s:%d",
742 want_cert ? "certificate" : "key", host_file, host_line);
743 if (want_cert && !check_host_cert(hostname, host_key))
744 goto fail;
715 if (options.check_host_ip && ip_status == HOST_NEW) { 745 if (options.check_host_ip && ip_status == HOST_NEW) {
716 if (readonly) 746 if (readonly || want_cert)
717 logit("%s host key for IP address " 747 logit("%s host key for IP address "
718 "'%.128s' not in list of known hosts.", 748 "'%.128s' not in list of known hosts.",
719 type, ip); 749 type, ip);
@@ -745,7 +775,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
745 break; 775 break;
746 } 776 }
747 } 777 }
748 if (readonly) 778 if (readonly || want_cert)
749 goto fail; 779 goto fail;
750 /* The host is new. */ 780 /* The host is new. */
751 if (options.strict_host_key_checking == 1) { 781 if (options.strict_host_key_checking == 1) {
@@ -829,7 +859,37 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
829 logit("Warning: Permanently added '%.200s' (%s) to the " 859 logit("Warning: Permanently added '%.200s' (%s) to the "
830 "list of known hosts.", hostp, type); 860 "list of known hosts.", hostp, type);
831 break; 861 break;
862 case HOST_REVOKED:
863 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
864 error("@ WARNING: REVOKED HOST KEY DETECTED! @");
865 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
866 error("The %s host key for %s is marked as revoked.", type, host);
867 error("This could mean that a stolen key is being used to");
868 error("impersonate this host.");
869
870 /*
871 * If strict host key checking is in use, the user will have
872 * to edit the key manually and we can only abort.
873 */
874 if (options.strict_host_key_checking) {
875 error("%s host key for %.200s was revoked and you have "
876 "requested strict checking.", type, host);
877 goto fail;
878 }
879 goto continue_unsafe;
880
832 case HOST_CHANGED: 881 case HOST_CHANGED:
882 if (want_cert) {
883 /*
884 * This is only a debug() since it is valid to have
885 * CAs with wildcard DNS matches that don't match
886 * all hosts that one might visit.
887 */
888 debug("Host certificate authority does not "
889 "match %s in %s:%d", CA_MARKER,
890 host_file, host_line);
891 goto fail;
892 }
833 if (readonly == ROQUIET) 893 if (readonly == ROQUIET)
834 goto fail; 894 goto fail;
835 if (options.check_host_ip && host_ip_differ) { 895 if (options.check_host_ip && host_ip_differ) {
@@ -867,6 +927,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
867 goto fail; 927 goto fail;
868 } 928 }
869 929
930 continue_unsafe:
870 /* 931 /*
871 * If strict host key checking has not been requested, allow 932 * If strict host key checking has not been requested, allow
872 * the connection but without MITM-able authentication or 933 * the connection but without MITM-able authentication or
@@ -925,7 +986,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
925 * XXX Should permit the user to change to use the new id. 986 * XXX Should permit the user to change to use the new id.
926 * This could be done by converting the host key to an 987 * This could be done by converting the host key to an
927 * identifying sentence, tell that the host identifies itself 988 * identifying sentence, tell that the host identifies itself
928 * by that sentence, and ask the user if he/she whishes to 989 * by that sentence, and ask the user if he/she wishes to
929 * accept the authentication. 990 * accept the authentication.
930 */ 991 */
931 break; 992 break;
@@ -966,6 +1027,20 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
966 return 0; 1027 return 0;
967 1028
968fail: 1029fail:
1030 if (want_cert && host_status != HOST_REVOKED) {
1031 /*
1032 * No matching certificate. Downgrade cert to raw key and
1033 * search normally.
1034 */
1035 debug("No matching CA found. Retry with plain key");
1036 raw_key = key_from_private(host_key);
1037 if (key_drop_cert(raw_key) != 0)
1038 fatal("Couldn't drop certificate");
1039 host_key = raw_key;
1040 goto retry;
1041 }
1042 if (raw_key != NULL)
1043 key_free(raw_key);
969 xfree(ip); 1044 xfree(ip);
970 xfree(host); 1045 xfree(host);
971 return -1; 1046 return -1;
@@ -978,7 +1053,8 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
978 struct stat st; 1053 struct stat st;
979 int flags = 0; 1054 int flags = 0;
980 1055
981 if (options.verify_host_key_dns && 1056 /* XXX certs are not yet supported for DNS */
1057 if (!key_is_cert(host_key) && options.verify_host_key_dns &&
982 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { 1058 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
983 1059
984 if (flags & DNS_VERIFY_FOUND) { 1060 if (flags & DNS_VERIFY_FOUND) {