summaryrefslogtreecommitdiff
path: root/sshconnect.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2010-02-27 07:55:05 +1100
committerDamien Miller <djm@mindrot.org>2010-02-27 07:55:05 +1100
commit0a80ca190a39943029719facf7edb990def7ae62 (patch)
treee423e30d8412de67170b8240ba919df10ed8e391 /sshconnect.c
parentd27d85d5320bb946d4bb734dcf45a8d20bad6020 (diff)
- OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/02/26 20:29:54 [PROTOCOL PROTOCOL.agent PROTOCOL.certkeys addrmatch.c auth-options.c] [auth-options.h auth.h auth2-pubkey.c authfd.c dns.c dns.h hostfile.c] [hostfile.h kex.h kexdhs.c kexgexs.c key.c key.h match.h monitor.c] [myproposal.h servconf.c servconf.h ssh-add.c ssh-agent.c ssh-dss.c] [ssh-keygen.1 ssh-keygen.c ssh-rsa.c ssh.1 ssh.c ssh2.h sshconnect.c] [sshconnect2.c sshd.8 sshd.c sshd_config.5] Add support for certificate key types for users and hosts. OpenSSH certificate key types are not X.509 certificates, but a much simpler format that encodes a public key, identity information and some validity constraints and signs it with a CA key. CA keys are regular SSH keys. This certificate style avoids the attack surface of X.509 certificates and is very easy to deploy. Certified host keys allow automatic acceptance of new host keys when a CA certificate is marked as sh/known_hosts. see VERIFYING HOST KEYS in ssh(1) for details. Certified user keys allow authentication of users when the signing CA key is marked as trusted in authorized_keys. See "AUTHORIZED_KEYS FILE FORMAT" in sshd(8) for details. Certificates are minted using ssh-keygen(1), documentation is in the "CERTIFICATES" section of that manpage. Documentation on the format of certificates is in the file PROTOCOL.certkeys feedback and ok markus@
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) {