summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect.c')
-rw-r--r--sshconnect.c78
1 files changed, 65 insertions, 13 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 63c4650f7..35c2f49be 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.218 2010/01/13 00:19:04 dtucker Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.219 2010/02/26 20:29:54 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
@@ -58,6 +58,7 @@
58#include "misc.h" 58#include "misc.h"
59#include "dns.h" 59#include "dns.h"
60#include "roaming.h" 60#include "roaming.h"
61#include "ssh2.h"
61#include "version.h" 62#include "version.h"
62 63
63char *client_version_string = NULL; 64char *client_version_string = NULL;
@@ -576,6 +577,23 @@ confirm(const char *prompt)
576 } 577 }
577} 578}
578 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
579/* 597/*
580 * 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
581 * 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.
@@ -588,13 +606,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
588 Key *host_key, int readonly, const char *user_hostfile, 606 Key *host_key, int readonly, const char *user_hostfile,
589 const char *system_hostfile) 607 const char *system_hostfile)
590{ 608{
591 Key *file_key; 609 Key *file_key, *raw_key = NULL;
592 const char *type = key_type(host_key); 610 const char *type;
593 char *ip = NULL, *host = NULL; 611 char *ip = NULL, *host = NULL;
594 char hostline[1000], *hostp, *fp, *ra; 612 char hostline[1000], *hostp, *fp, *ra;
595 HostStatus host_status; 613 HostStatus host_status;
596 HostStatus ip_status; 614 HostStatus ip_status;
597 int r, local = 0, host_ip_differ = 0; 615 int r, want_cert, local = 0, host_ip_differ = 0;
598 int salen; 616 int salen;
599 char ntop[NI_MAXHOST]; 617 char ntop[NI_MAXHOST];
600 char msg[1024]; 618 char msg[1024];
@@ -667,11 +685,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
667 host = put_host_port(hostname, port); 685 host = put_host_port(hostname, port);
668 } 686 }
669 687
688 retry:
689 want_cert = key_is_cert(host_key);
690 type = key_type(host_key);
691
670 /* 692 /*
671 * 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
672 * compare it with the key for the IP address. 694 * compare it with the key for the IP address.
673 */ 695 */
674 file_key = key_new(host_key->type); 696 file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type);
675 697
676 /* 698 /*
677 * 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
@@ -687,9 +709,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
687 } 709 }
688 /* 710 /*
689 * 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
690 * 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.
691 */ 714 */
692 if (options.check_host_ip) { 715 if (!want_cert && options.check_host_ip) {
693 Key *ip_key = key_new(host_key->type); 716 Key *ip_key = key_new(host_key->type);
694 717
695 ip_file = user_hostfile; 718 ip_file = user_hostfile;
@@ -713,11 +736,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
713 switch (host_status) { 736 switch (host_status) {
714 case HOST_OK: 737 case HOST_OK:
715 /* The host is known and the key matches. */ 738 /* The host is known and the key matches. */
716 debug("Host '%.200s' is known and matches the %s host key.", 739 debug("Host '%.200s' is known and matches the %s host %s.",
717 host, type); 740 host, type, want_cert ? "certificate" : "key");
718 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;
719 if (options.check_host_ip && ip_status == HOST_NEW) { 745 if (options.check_host_ip && ip_status == HOST_NEW) {
720 if (readonly) 746 if (readonly || want_cert)
721 logit("%s host key for IP address " 747 logit("%s host key for IP address "
722 "'%.128s' not in list of known hosts.", 748 "'%.128s' not in list of known hosts.",
723 type, ip); 749 type, ip);
@@ -749,7 +775,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
749 break; 775 break;
750 } 776 }
751 } 777 }
752 if (readonly) 778 if (readonly || want_cert)
753 goto fail; 779 goto fail;
754 /* The host is new. */ 780 /* The host is new. */
755 if (options.strict_host_key_checking == 1) { 781 if (options.strict_host_key_checking == 1) {
@@ -834,6 +860,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
834 "list of known hosts.", hostp, type); 860 "list of known hosts.", hostp, type);
835 break; 861 break;
836 case HOST_CHANGED: 862 case HOST_CHANGED:
863 if (want_cert) {
864 /*
865 * This is only a debug() since it is valid to have
866 * CAs with wildcard DNS matches that don't match
867 * all hosts that one might visit.
868 */
869 debug("Host certificate authority does not "
870 "match %s in %s:%d", CA_MARKER,
871 host_file, host_line);
872 goto fail;
873 }
837 if (readonly == ROQUIET) 874 if (readonly == ROQUIET)
838 goto fail; 875 goto fail;
839 if (options.check_host_ip && host_ip_differ) { 876 if (options.check_host_ip && host_ip_differ) {
@@ -970,6 +1007,20 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
970 return 0; 1007 return 0;
971 1008
972fail: 1009fail:
1010 if (want_cert) {
1011 /*
1012 * No matching certificate. Downgrade cert to raw key and
1013 * search normally.
1014 */
1015 debug("No matching CA found. Retry with plain key");
1016 raw_key = key_from_private(host_key);
1017 if (key_drop_cert(raw_key) != 0)
1018 fatal("Couldn't drop certificate");
1019 host_key = raw_key;
1020 goto retry;
1021 }
1022 if (raw_key != NULL)
1023 key_free(raw_key);
973 xfree(ip); 1024 xfree(ip);
974 xfree(host); 1025 xfree(host);
975 return -1; 1026 return -1;
@@ -982,7 +1033,8 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
982 struct stat st; 1033 struct stat st;
983 int flags = 0; 1034 int flags = 0;
984 1035
985 if (options.verify_host_key_dns && 1036 /* XXX certs are not yet supported for DNS */
1037 if (!key_is_cert(host_key) && options.verify_host_key_dns &&
986 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { 1038 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
987 1039
988 if (flags & DNS_VERIFY_FOUND) { 1040 if (flags & DNS_VERIFY_FOUND) {