From 1477ea162c05c09b4b5ebc19ac588fbf469349dc Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 7 Oct 2009 08:36:05 +1100 Subject: - dtucker@cvs.openbsd.org 2009/08/16 23:29:26 [sshd_config.5] Add PubkeyAuthentication to the list allowed in a Match block (bz #1577) --- sshd_config.5 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sshd_config.5') diff --git a/sshd_config.5 b/sshd_config.5 index 588aed56e..54a4480fe 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.106 2009/04/21 15:13:17 stevesk Exp $ -.Dd $Mdocdate: April 21 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.107 2009/08/16 23:29:26 dtucker Exp $ +.Dd $Mdocdate: August 16 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -614,6 +614,7 @@ Available keywords are .Cm PermitEmptyPasswords , .Cm PermitOpen , .Cm PermitRootLogin , +.Cm PubkeyAuthentication , .Cm RhostsRSAAuthentication , .Cm RSAAuthentication , .Cm X11DisplayOffset , -- cgit v1.2.3 From bad5076bb5d5587cf8b889cd9ce495c39282786b Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 11 Oct 2009 21:51:08 +1100 Subject: - (dtucker) OpenBSD CVS Sync - markus@cvs.openbsd.org 2009/10/08 14:03:41 [sshd_config readconf.c ssh_config.5 servconf.c sshd_config.5] disable protocol 1 by default (after a transition period of about 10 years) ok deraadt --- ChangeLog | 5 +++++ readconf.c | 4 ++-- servconf.c | 4 ++-- ssh_config.5 | 14 ++++++++------ sshd_config | 8 +++----- sshd_config.5 | 6 +++--- 6 files changed, 23 insertions(+), 18 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 85446e312..23bc18b67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ - (dtucker) [configure.ac sftp-client.c] Remove the gyrations required for dirent d_type and DTTOIF as we've switched OpenBSD to the more portable lstat. + - (dtucker) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2009/10/08 14:03:41 + [sshd_config readconf.c ssh_config.5 servconf.c sshd_config.5] + disable protocol 1 by default (after a transition period of about 10 years) + ok deraadt 20091007 - (dtucker) OpenBSD CVS Sync diff --git a/readconf.c b/readconf.c index 0bf5d7cb4..4a16974b8 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.177 2009/06/27 09:35:06 andreas Exp $ */ +/* $OpenBSD: readconf.c,v 1.178 2009/10/08 14:03:41 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1142,7 +1142,7 @@ fill_default_options(Options * options) /* options->macs, default set in myproposals.h */ /* options->hostkeyalgorithms, default set in myproposals.h */ if (options->protocol == SSH_PROTO_UNKNOWN) - options->protocol = SSH_PROTO_1|SSH_PROTO_2; + options->protocol = SSH_PROTO_2; if (options->num_identity_files == 0) { if (options->protocol & SSH_PROTO_1) { len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; diff --git a/servconf.c b/servconf.c index b51b86a8f..c2e5cc6f4 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.195 2009/04/14 21:10:54 jj Exp $ */ +/* $OpenBSD: servconf.c,v 1.196 2009/10/08 14:03:41 markus Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -139,7 +139,7 @@ fill_default_server_options(ServerOptions *options) /* Standard Options */ if (options->protocol == SSH_PROTO_UNKNOWN) - options->protocol = SSH_PROTO_1|SSH_PROTO_2; + options->protocol = SSH_PROTO_2; if (options->num_host_key_files == 0) { /* fill default hostkeys for protocols */ if (options->protocol & SSH_PROTO_1) diff --git a/ssh_config.5 b/ssh_config.5 index ea9a20b23..82c2a30b0 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.119 2009/02/22 23:50:57 djm Exp $ -.Dd $Mdocdate: February 22 2009 $ +.\" $OpenBSD: ssh_config.5,v 1.120 2009/10/08 14:03:41 markus Exp $ +.Dd $Mdocdate: October 8 2009 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -730,11 +730,13 @@ The possible values are and .Sq 2 . Multiple versions must be comma-separated. -The default is -.Dq 2,1 . -This means that ssh -tries version 2 and falls back to version 1 +When this option is set to +.Dq 2,1 +.Nm ssh +will try version 2 and fall back to version 1 if version 2 is not available. +The default is +.Dq 2 . .It Cm ProxyCommand Specifies the command to use to connect to the server. The command diff --git a/sshd_config b/sshd_config index 1b53a0efb..72fbae37b 100644 --- a/sshd_config +++ b/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ +# $OpenBSD: sshd_config,v 1.81 2009/10/08 14:03:41 markus Exp $ # This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. @@ -15,10 +15,8 @@ #ListenAddress 0.0.0.0 #ListenAddress :: -# Disable legacy (protocol version 1) support in the server for new -# installations. In future the default will change to require explicit -# activation of protocol 1 -Protocol 2 +# The default requires explicit activation of protocol 1 +#Protocol 2 # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key diff --git a/sshd_config.5 b/sshd_config.5 index 54a4480fe..00ac82a34 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.107 2009/08/16 23:29:26 dtucker Exp $ -.Dd $Mdocdate: August 16 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.108 2009/10/08 14:03:41 markus Exp $ +.Dd $Mdocdate: October 8 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -793,7 +793,7 @@ and .Sq 2 . Multiple versions must be comma-separated. The default is -.Dq 2,1 . +.Dq 2 . Note that the order of the protocol list does not indicate preference, because the client selects among multiple protocol versions offered by the server. -- cgit v1.2.3 From 7a4a76579e5321f52b773fc84f7bbe0f07adc5f2 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 11 Oct 2009 21:51:40 +1100 Subject: - jmc@cvs.openbsd.org 2009/10/08 20:42:12 [sshd_config.5 ssh_config.5 sshd.8 ssh.1] some tweaks now that protocol 1 is not offered by default; ok markus --- ChangeLog | 3 +++ ssh.1 | 16 +++++++--------- ssh_config.5 | 6 +++--- sshd.8 | 6 +++--- sshd_config.5 | 4 ++-- 5 files changed, 18 insertions(+), 17 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 23bc18b67..495c0968c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ [sshd_config readconf.c ssh_config.5 servconf.c sshd_config.5] disable protocol 1 by default (after a transition period of about 10 years) ok deraadt + - jmc@cvs.openbsd.org 2009/10/08 20:42:12 + [sshd_config.5 ssh_config.5 sshd.8 ssh.1] + some tweaks now that protocol 1 is not offered by default; ok markus 20091007 - (dtucker) OpenBSD CVS Sync diff --git a/ssh.1 b/ssh.1 index 6c6271ee4..8c3d32aaf 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.283 2009/03/19 15:15:09 jmc Exp $ -.Dd $Mdocdate: March 19 2009 $ +.\" $OpenBSD: ssh.1,v 1.284 2009/10/08 20:42:12 jmc Exp $ +.Dd $Mdocdate: October 8 2009 $ .Dt SSH 1 .Os .Sh NAME @@ -666,20 +666,18 @@ exits with the exit status of the remote command or with 255 if an error occurred. .Sh AUTHENTICATION The OpenSSH SSH client supports SSH protocols 1 and 2. -Protocol 2 is the default, with -.Nm -falling back to protocol 1 if it detects protocol 2 is unsupported. -These settings may be altered using the +The default is to use protocol 2 only, +though this can be changed via the .Cm Protocol option in -.Xr ssh_config 5 , -or enforced using the +.Xr ssh_config 5 +or the .Fl 1 and .Fl 2 options (see above). Both protocols support similar authentication methods, -but protocol 2 is preferred since +but protocol 2 is the default since it provides additional mechanisms for confidentiality (the traffic is encrypted using AES, 3DES, Blowfish, CAST128, or Arcfour) and integrity (hmac-md5, hmac-sha1, umac-64, hmac-ripemd160). diff --git a/ssh_config.5 b/ssh_config.5 index 82c2a30b0..89f3896e6 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.120 2009/10/08 14:03:41 markus Exp $ +.\" $OpenBSD: ssh_config.5,v 1.121 2009/10/08 20:42:13 jmc Exp $ .Dd $Mdocdate: October 8 2009 $ .Dt SSH_CONFIG 5 .Os @@ -731,12 +731,12 @@ and .Sq 2 . Multiple versions must be comma-separated. When this option is set to -.Dq 2,1 +.Dq 2,1 .Nm ssh will try version 2 and fall back to version 1 if version 2 is not available. The default is -.Dq 2 . +.Sq 2 . .It Cm ProxyCommand Specifies the command to use to connect to the server. The command diff --git a/sshd.8 b/sshd.8 index 111d491d9..7878d9f06 100644 --- a/sshd.8 +++ b/sshd.8 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.248 2009/03/26 08:38:39 sobrado Exp $ -.Dd $Mdocdate: March 26 2009 $ +.\" $OpenBSD: sshd.8,v 1.249 2009/10/08 20:42:13 jmc Exp $ +.Dd $Mdocdate: October 8 2009 $ .Dt SSHD 8 .Os .Sh NAME @@ -260,7 +260,7 @@ or .El .Sh AUTHENTICATION The OpenSSH SSH daemon supports SSH protocols 1 and 2. -Both protocols are supported by default, +The default is to use protocol 2 only, though this can be changed via the .Cm Protocol option in diff --git a/sshd_config.5 b/sshd_config.5 index 00ac82a34..4b3793d13 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.108 2009/10/08 14:03:41 markus Exp $ +.\" $OpenBSD: sshd_config.5,v 1.109 2009/10/08 20:42:13 jmc Exp $ .Dd $Mdocdate: October 8 2009 $ .Dt SSHD_CONFIG 5 .Os @@ -793,7 +793,7 @@ and .Sq 2 . Multiple versions must be comma-separated. The default is -.Dq 2 . +.Sq 2 . Note that the order of the protocol list does not indicate preference, because the client selects among multiple protocol versions offered by the server. -- cgit v1.2.3 From 34e314da1b832fee576e4ebd8b177154a45fec15 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 17:03:46 +1100 Subject: - reyk@cvs.openbsd.org 2009/10/28 16:38:18 [ssh_config.5 sshd.c misc.h ssh-keyscan.1 readconf.h sshconnect.c channels.c channels.h servconf.h servconf.c ssh.1 ssh-keyscan.c scp.1 sftp.1 sshd_config.5 readconf.c ssh.c misc.c] Allow to set the rdomain in ssh/sftp/scp/sshd and ssh-keyscan. ok markus@ --- ChangeLog | 6 ++++++ channels.c | 26 +++++++++++++++++++------- channels.h | 3 ++- misc.c | 39 ++++++++++++++++++++++++++++++++++++++- misc.h | 4 +++- readconf.c | 22 +++++++++++++++++++--- readconf.h | 4 +++- scp.1 | 5 +++-- servconf.c | 11 +++++++++-- servconf.h | 4 +++- sftp.1 | 5 +++-- ssh-keyscan.1 | 7 +++++-- ssh-keyscan.c | 17 +++++++++++++---- ssh.1 | 5 +++-- ssh.c | 3 ++- ssh_config.5 | 7 +++++-- sshconnect.c | 5 +++-- sshd.c | 9 +++++---- sshd_config.5 | 7 +++++-- 19 files changed, 149 insertions(+), 40 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 9f63b83b5..0a931a120 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,12 @@ Request roaming to be enabled if UseRoaming is true and the server supports it. ok markus@ + - reyk@cvs.openbsd.org 2009/10/28 16:38:18 + [ssh_config.5 sshd.c misc.h ssh-keyscan.1 readconf.h sshconnect.c + channels.c channels.h servconf.h servconf.c ssh.1 ssh-keyscan.c scp.1 + sftp.1 sshd_config.5 readconf.c ssh.c misc.c] + Allow to set the rdomain in ssh/sftp/scp/sshd and ssh-keyscan. + ok markus@ 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/channels.c b/channels.c index 22e7f628b..884c14c99 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.296 2009/05/25 06:48:00 andreas Exp $ */ +/* $OpenBSD: channels.c,v 1.297 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -162,6 +162,9 @@ static u_int x11_fake_data_len; /* AF_UNSPEC or AF_INET or AF_INET6 */ static int IPv4or6 = AF_UNSPEC; +/* Set the routing domain a.k.a. VRF */ +static int channel_rdomain = -1; + /* helper */ static void port_open_helper(Channel *c, char *rtype); @@ -2461,6 +2464,12 @@ channel_set_af(int af) IPv4or6 = af; } +void +channel_set_rdomain(int rdomain) +{ + channel_rdomain = rdomain; +} + static int channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, int *allocated_listen_port, @@ -2569,7 +2578,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, continue; } /* Create a port to listen for the host. */ - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + sock = socket_rdomain(ai->ai_family, ai->ai_socktype, + ai->ai_protocol, channel_rdomain); if (sock < 0) { /* this is no error since kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); @@ -2910,8 +2920,9 @@ connect_next(struct channel_connect *cctx) error("connect_next: getnameinfo failed"); continue; } - if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, - cctx->ai->ai_protocol)) == -1) { + if ((sock = socket_rdomain(cctx->ai->ai_family, + cctx->ai->ai_socktype, cctx->ai->ai_protocol, + channel_rdomain)) == -1) { if (cctx->ai->ai_next == NULL) error("socket: %.100s", strerror(errno)); else @@ -3097,8 +3108,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; - sock = socket(ai->ai_family, ai->ai_socktype, - ai->ai_protocol); + sock = socket_rdomain(ai->ai_family, ai->ai_socktype, + ai->ai_protocol, channel_rdomain); if (sock < 0) { if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) { error("socket: %.100s", strerror(errno)); @@ -3273,7 +3284,8 @@ x11_connect_display(void) } for (ai = aitop; ai; ai = ai->ai_next) { /* Create a socket. */ - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + sock = socket_rdomain(ai->ai_family, ai->ai_socktype, + ai->ai_protocol, channel_rdomain); if (sock < 0) { debug2("socket: %.100s", strerror(errno)); continue; diff --git a/channels.h b/channels.h index 1488ed7e5..b0f5dc321 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.98 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.99 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen @@ -231,6 +231,7 @@ int channel_find_open(void); /* tcp forwarding */ void channel_set_af(int af); +void channel_set_rdomain(int); void channel_permit_all_opens(void); void channel_add_permitted_opens(char *, int); int channel_add_adm_permitted_opens(char *, int); diff --git a/misc.c b/misc.c index 4dc152310..f0f1fd841 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.71 2009/02/21 19:32:04 tobias Exp $ */ +/* $OpenBSD: misc.c,v 1.72 2009/10/28 16:38:18 reyk Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -151,6 +151,43 @@ set_nodelay(int fd) error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); } +/* open a socket in the specified routing domain */ +int +socket_rdomain(int domain, int type, int protocol, int rdomain) +{ + int sock, ipproto = IPPROTO_IP; + + if ((sock = socket(domain, type, protocol)) == -1) + return (-1); + + if (rdomain == -1) + return (sock); + + switch (domain) { + case AF_INET6: + ipproto = IPPROTO_IPV6; + /* FALLTHROUGH */ + case AF_INET: + debug2("socket %d af %d setting rdomain %d", + sock, domain, rdomain); + if (setsockopt(sock, ipproto, SO_RDOMAIN, &rdomain, + sizeof(rdomain)) == -1) { + debug("setsockopt SO_RDOMAIN: %.100s", + strerror(errno)); + close(sock); + return (-1); + } + break; + default: + debug("socket %d af %d does not support rdomain %d", + sock, domain, rdomain); + close(sock); + return (-1); + } + + return (sock); +} + /* Characters considered whitespace in strsep calls. */ #define WHITESPACE " \t\r\n" #define QUOTE "\"" diff --git a/misc.h b/misc.h index e26b0aaff..87b7f0edf 100644 --- a/misc.h +++ b/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 dtucker Exp $ */ +/* $OpenBSD: misc.h,v 1.39 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen @@ -54,6 +54,8 @@ void freeargs(arglist *); int tun_open(int, int); +int socket_rdomain(int, int, int, int); + /* Common definitions for ssh tunnel device forwarding */ #define SSH_TUNMODE_NO 0x00 #define SSH_TUNMODE_POINTOPOINT 0x01 diff --git a/readconf.c b/readconf.c index 4a16974b8..6b2e3b21d 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.178 2009/10/08 14:03:41 markus Exp $ */ +/* $OpenBSD: readconf.c,v 1.179 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -130,8 +130,8 @@ typedef enum { oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, - oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, - oDeprecated, oUnsupported + oVisualHostKey, oUseRoaming, oRDomain, + oZeroKnowledgePasswordAuthentication, oDeprecated, oUnsupported } OpCodes; /* Textual representations of the tokens. */ @@ -229,6 +229,7 @@ static struct { { "permitlocalcommand", oPermitLocalCommand }, { "visualhostkey", oVisualHostKey }, { "useroaming", oUseRoaming }, + { "rdomain", oRDomain }, #ifdef JPAKE { "zeroknowledgepasswordauthentication", oZeroKnowledgePasswordAuthentication }, @@ -919,6 +920,19 @@ parse_int: intptr = &options->use_roaming; goto parse_flag; + case oRDomain: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", + filename, linenum); + value = a2port(arg); + if (value == -1) + fatal("%.200s line %d: Bad rdomain.", + filename, linenum); + if (*activep) + options->rdomain = value; + break; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1069,6 +1083,7 @@ initialize_options(Options * options) options->local_command = NULL; options->permit_local_command = -1; options->use_roaming = -1; + options->rdomain = -1; options->visual_host_key = -1; options->zero_knowledge_password_authentication = -1; } @@ -1217,6 +1232,7 @@ fill_default_options(Options * options) /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ + /* options->rdomain should not be set by default */ } /* diff --git a/readconf.h b/readconf.h index 2ebfebe94..6edc2eeda 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.79 2009/06/27 09:35:06 andreas Exp $ */ +/* $OpenBSD: readconf.h,v 1.80 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen @@ -125,6 +125,8 @@ typedef struct { int use_roaming; + int rdomain; /* routing domain a.k.a. VRF */ + } Options; #define SSHCTL_MASTER_NO 0 diff --git a/scp.1 b/scp.1 index 5033d84f2..b9245ea53 100644 --- a/scp.1 +++ b/scp.1 @@ -9,9 +9,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.46 2008/07/12 05:33:41 djm Exp $ +.\" $OpenBSD: scp.1,v 1.47 2009/10/28 16:38:18 reyk Exp $ .\" -.Dd $Mdocdate: July 12 2008 $ +.Dd $Mdocdate: October 28 2009 $ .Dt SCP 1 .Os .Sh NAME @@ -158,6 +158,7 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication +.It RDomain .It RekeyLimit .It RhostsRSAAuthentication .It RSAAuthentication diff --git a/servconf.c b/servconf.c index c2e5cc6f4..729f23bad 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.196 2009/10/08 14:03:41 markus Exp $ */ +/* $OpenBSD: servconf.c,v 1.197 2009/10/28 16:38:18 reyk Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -128,6 +128,7 @@ initialize_server_options(ServerOptions *options) options->adm_forced_command = NULL; options->chroot_directory = NULL; options->zero_knowledge_password_authentication = -1; + options->rdomain = -1; } void @@ -304,7 +305,7 @@ typedef enum { sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, + sUsePrivilegeSeparation, sAllowAgentForwarding, sRDomain, sZeroKnowledgePasswordAuthentication, sDeprecated, sUnsupported } ServerOpCodes; @@ -423,6 +424,7 @@ static struct { { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "rdomain", sRDomain, SSHCFG_GLOBAL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -1294,6 +1296,10 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; + case sRDomain: + intptr = &options->rdomain; + goto parse_int; + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1570,6 +1576,7 @@ dump_config(ServerOptions *o) dump_cfg_int(sMaxSessions, o->max_sessions); dump_cfg_int(sClientAliveInterval, o->client_alive_interval); dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); + dump_cfg_int(sRDomain, o->rdomain); /* formatted integer arguments */ dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login); diff --git a/servconf.h b/servconf.h index b3ac7da4b..19c7ae609 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.87 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.88 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen @@ -150,6 +150,8 @@ typedef struct { int num_permitted_opens; + int rdomain; + char *chroot_directory; } ServerOptions; diff --git a/sftp.1 b/sftp.1 index d1db0d6dd..b912d24e3 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.76 2009/08/19 04:56:03 jmc Exp $ +.\" $OpenBSD: sftp.1,v 1.77 2009/10/28 16:38:18 reyk Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: August 19 2009 $ +.Dd $Mdocdate: October 28 2009 $ .Dt SFTP 1 .Os .Sh NAME @@ -209,6 +209,7 @@ For full details of the options listed below, and their possible values, see .It PubkeyAuthentication .It RekeyLimit .It RhostsRSAAuthentication +.It RDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/ssh-keyscan.1 b/ssh-keyscan.1 index 4a5864566..c9fb597ed 100644 --- a/ssh-keyscan.1 +++ b/ssh-keyscan.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.26 2008/12/29 01:12:36 stevesk Exp $ +.\" $OpenBSD: ssh-keyscan.1,v 1.27 2009/10/28 16:38:18 reyk Exp $ .\" .\" Copyright 1995, 1996 by David Mazieres . .\" @@ -6,7 +6,7 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" -.Dd $Mdocdate: December 29 2008 $ +.Dd $Mdocdate: October 28 2009 $ .Dt SSH-KEYSCAN 1 .Os .Sh NAME @@ -20,6 +20,7 @@ .Op Fl p Ar port .Op Fl T Ar timeout .Op Fl t Ar type +.Op Fl V Ar rdomain .Op Ar host | addrlist namelist .Ar ... .Ek @@ -95,6 +96,8 @@ for protocol version 2. Multiple values may be specified by separating them with commas. The default is .Dq rsa . +.It Fl V Ar rdomain +Set the routing domain. .It Fl v Verbose mode. Causes diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 9a91be499..f30e85045 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.78 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.79 2009/10/28 16:38:18 reyk Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -68,6 +68,9 @@ int timeout = 5; int maxfd; #define MAXCON (maxfd - 10) +/* The default routing domain */ +int scan_rdomain = -1; + extern char *__progname; fd_set *read_wait; size_t read_wait_nfdset; @@ -412,7 +415,8 @@ tcpconnect(char *host) if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) fatal("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr)); for (ai = aitop; ai; ai = ai->ai_next) { - s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + s = socket_rdomain(ai->ai_family, ai->ai_socktype, + ai->ai_protocol, scan_rdomain); if (s < 0) { error("socket: %s", strerror(errno)); continue; @@ -715,7 +719,7 @@ usage(void) { fprintf(stderr, "usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n" - "\t\t [host | addrlist namelist] ...\n", + "\t\t [-V rdomain] [host | addrlist namelist] ...\n", __progname); exit(1); } @@ -741,7 +745,7 @@ main(int argc, char **argv) if (argc <= 1) usage(); - while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) { + while ((opt = getopt(argc, argv, "Hv46p:T:t:f:V:")) != -1) { switch (opt) { case 'H': hash_hosts = 1; @@ -802,6 +806,11 @@ main(int argc, char **argv) case '6': IPv4or6 = AF_INET6; break; + case 'V': + scan_rdomain = a2port(optarg); + if (scan_rdomain < 0) + scan_rdomain = -1; + break; case '?': default: usage(); diff --git a/ssh.1 b/ssh.1 index 7e7f64e46..8277d0fdf 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.286 2009/10/22 15:02:12 sobrado Exp $ -.Dd $Mdocdate: October 22 2009 $ +.\" $OpenBSD: ssh.1,v 1.287 2009/10/28 16:38:18 reyk Exp $ +.Dd $Mdocdate: October 28 2009 $ .Dt SSH 1 .Os .Sh NAME @@ -475,6 +475,7 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication +.It RDomain .It RekeyLimit .It RemoteForward .It RhostsRSAAuthentication diff --git a/ssh.c b/ssh.c index 5353e235c..90dbc69e9 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.327 2009/10/24 11:23:42 andreas Exp $ */ +/* $OpenBSD: ssh.c,v 1.328 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -630,6 +630,7 @@ main(int ac, char **av) fill_default_options(&options); channel_set_af(options.address_family); + channel_set_rdomain(options.rdomain); /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); diff --git a/ssh_config.5 b/ssh_config.5 index 89f3896e6..fde899477 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.121 2009/10/08 20:42:13 jmc Exp $ -.Dd $Mdocdate: October 8 2009 $ +.\" $OpenBSD: ssh_config.5,v 1.122 2009/10/28 16:38:18 reyk Exp $ +.Dd $Mdocdate: October 28 2009 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -782,6 +782,9 @@ or The default is .Dq yes . This option applies to protocol version 2 only. +.It Cm RDomain +Set the routing domain number. +The default routing domain is set by the system. .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted before the session key is renegotiated. diff --git a/sshconnect.c b/sshconnect.c index 3e57e859d..a09026e65 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.214 2009/05/28 16:50:16 andreas Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.215 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -190,7 +190,8 @@ ssh_create_socket(int privileged, struct addrinfo *ai) debug("Allocated local port %d.", p); return sock; } - sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + sock = socket_rdomain(ai->ai_family, ai->ai_socktype, ai->ai_protocol, + options.rdomain); if (sock < 0) error("socket: %.100s", strerror(errno)); diff --git a/sshd.c b/sshd.c index 38aaa1820..e23d462ee 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.367 2009/05/28 16:50:16 andreas Exp $ */ +/* $OpenBSD: sshd.c,v 1.368 2009/10/28 16:38:18 reyk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -960,8 +960,8 @@ server_listen(void) continue; } /* Create socket for listening. */ - listen_sock = socket(ai->ai_family, ai->ai_socktype, - ai->ai_protocol); + listen_sock = socket_rdomain(ai->ai_family, ai->ai_socktype, + ai->ai_protocol, options.rdomain); if (listen_sock < 0) { /* kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); @@ -1469,8 +1469,9 @@ main(int ac, char **av) if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; - /* set default channel AF */ + /* set default channel AF and routing domain */ channel_set_af(options.address_family); + channel_set_rdomain(options.rdomain); /* Check that there are no remaining arguments. */ if (optind < ac) { diff --git a/sshd_config.5 b/sshd_config.5 index 4b3793d13..1a30f29c1 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.109 2009/10/08 20:42:13 jmc Exp $ -.Dd $Mdocdate: October 8 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.110 2009/10/28 16:38:18 reyk Exp $ +.Dd $Mdocdate: October 28 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -812,6 +812,9 @@ with successful RSA host authentication is allowed. The default is .Dq no . This option applies to protocol version 1 only. +.It Cm RDomain +Set the routing domain number. +The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is -- cgit v1.2.3 From cc117f0deb26a3491aa90614974517ac2f18dc45 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 17:05:26 +1100 Subject: - jmc@cvs.openbsd.org 2009/10/28 21:45:08 [sshd_config.5 sftp.1] tweak previous; --- ChangeLog | 3 +++ sftp.1 | 4 ++-- sshd_config.5 | 8 ++++---- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 0a931a120..35c116484 100644 --- a/ChangeLog +++ b/ChangeLog @@ -36,6 +36,9 @@ sftp.1 sshd_config.5 readconf.c ssh.c misc.c] Allow to set the rdomain in ssh/sftp/scp/sshd and ssh-keyscan. ok markus@ + - jmc@cvs.openbsd.org 2009/10/28 21:45:08 + [sshd_config.5 sftp.1] + tweak previous; 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/sftp.1 b/sftp.1 index b912d24e3..ab53c1690 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.77 2009/10/28 16:38:18 reyk Exp $ +.\" $OpenBSD: sftp.1,v 1.78 2009/10/28 21:45:08 jmc Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -207,9 +207,9 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication +.It RDomain .It RekeyLimit .It RhostsRSAAuthentication -.It RDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/sshd_config.5 b/sshd_config.5 index 1a30f29c1..7e7c6f855 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.110 2009/10/28 16:38:18 reyk Exp $ +.\" $OpenBSD: sshd_config.5,v 1.111 2009/10/28 21:45:08 jmc Exp $ .Dd $Mdocdate: October 28 2009 $ .Dt SSHD_CONFIG 5 .Os @@ -806,15 +806,15 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm RDomain +Set the routing domain number. +The default routing domain is set by the system. .It Cm RhostsRSAAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. The default is .Dq no . This option applies to protocol version 1 only. -.It Cm RDomain -Set the routing domain number. -The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is -- cgit v1.2.3 From f788a91624601857c586a4dd97c66083946e7781 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 17:06:47 +1100 Subject: - djm@cvs.openbsd.org 2009/11/10 02:58:56 [sshd_config.5] clarify that StrictModes does not apply to ChrootDirectory. Permissions and ownership are always checked when chrooting. bz#1532 --- ChangeLog | 4 ++++ sshd_config.5 | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 712a9caf5..604b5d773 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,10 @@ [ssh_config.5] explain the constraints on LocalCommand some more so people don't try to abuse it. + - djm@cvs.openbsd.org 2009/11/10 02:58:56 + [sshd_config.5] + clarify that StrictModes does not apply to ChrootDirectory. Permissions + and ownership are always checked when chrooting. bz#1532 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/sshd_config.5 b/sshd_config.5 index 7e7c6f855..e54e70079 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.111 2009/10/28 21:45:08 jmc Exp $ -.Dd $Mdocdate: October 28 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.112 2009/11/10 02:58:56 djm Exp $ +.Dd $Mdocdate: November 10 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -832,6 +832,9 @@ This is normally desirable because novices sometimes accidentally leave their directory or files world-writable. The default is .Dq yes . +Note that this does not apply to +.Cm ChrootDirectory , +whose permissions and ownership are checked unconditionally. .It Cm Subsystem Configures an external subsystem (e.g. file transfer daemon). Arguments should be a subsystem name and a command (with optional arguments) -- cgit v1.2.3 From b8c884a0ba4050e4267be786414127c0f09d5544 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 18:53:43 +1100 Subject: - guenther@cvs.openbsd.org 2009/12/20 07:28:36 [ssh.c sftp.c scp.c] When passing user-controlled options with arguments to other programs, pass the option and option argument as separate argv entries and not smashed into one (e.g., as -l foo and not -lfoo). Also, always pass a "--" argument to stop option parsing, so that a positional argument that starts with a '-' isn't treated as an option. This fixes some error cases as well as the handling of hostnames and filenames that start with a '-'. Based on a diff by halex@ ok halex@ djm@ deraadt@ --- ChangeLog | 11 +++++++++++ scp.c | 21 ++++++++++++++------- sftp.c | 6 ++++-- ssh.c | 4 ++-- sshd_config.5 | 10 +++++----- 5 files changed, 36 insertions(+), 16 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 45f758529..605e0dca7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -108,6 +108,17 @@ [key.c] switch from 35 to the more common value of RSA_F4 == (2**16)+1 == 65537 for the RSA public exponent; discussed with provos; ok djm@ + - guenther@cvs.openbsd.org 2009/12/20 07:28:36 + [ssh.c sftp.c scp.c] + When passing user-controlled options with arguments to other programs, + pass the option and option argument as separate argv entries and + not smashed into one (e.g., as -l foo and not -lfoo). Also, always + pass a "--" argument to stop option parsing, so that a positional + argument that starts with a '-' isn't treated as an option. This + fixes some error cases as well as the handling of hostnames and + filenames that start with a '-'. + Based on a diff by halex@ + ok halex@ djm@ deraadt@ 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/scp.c b/scp.c index 323747806..09efb82ac 100644 --- a/scp.c +++ b/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.164 2008/10/10 04:55:16 stevesk Exp $ */ +/* $OpenBSD: scp.c,v 1.165 2009/12/20 07:28:36 guenther Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -244,8 +244,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) close(pout[1]); replacearg(&args, 0, "%s", ssh_program); - if (remuser != NULL) - addargs(&args, "-l%s", remuser); + if (remuser != NULL) { + addargs(&args, "-l"); + addargs(&args, "%s", remuser); + } + addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", cmd); @@ -337,10 +340,12 @@ main(int argc, char **argv) case 'c': case 'i': case 'F': - addargs(&args, "-%c%s", ch, optarg); + addargs(&args, "-%c", ch); + addargs(&args, "%s", optarg); break; case 'P': - addargs(&args, "-p%s", optarg); + addargs(&args, "-p"); + addargs(&args, "%s", optarg); break; case 'B': addargs(&args, "-oBatchmode yes"); @@ -548,6 +553,7 @@ toremote(char *targ, int argc, char **argv) } else { host = cleanhostname(argv[i]); } + addargs(&alist, "--"); addargs(&alist, "%s", host); addargs(&alist, "%s", cmd); addargs(&alist, "%s", src); @@ -558,7 +564,7 @@ toremote(char *targ, int argc, char **argv) errs = 1; } else { /* local to remote */ if (remin == -1) { - xasprintf(&bp, "%s -t %s", cmd, targ); + xasprintf(&bp, "%s -t -- %s", cmd, targ); host = cleanhostname(thost); if (do_cmd(host, tuser, bp, &remin, &remout) < 0) @@ -591,6 +597,7 @@ tolocal(int argc, char **argv) addargs(&alist, "-r"); if (pflag) addargs(&alist, "-p"); + addargs(&alist, "--"); addargs(&alist, "%s", argv[i]); addargs(&alist, "%s", argv[argc-1]); if (do_local_cmd(&alist)) @@ -610,7 +617,7 @@ tolocal(int argc, char **argv) suser = pwd->pw_name; } host = cleanhostname(host); - xasprintf(&bp, "%s -f %s", cmd, src); + xasprintf(&bp, "%s -f -- %s", cmd, src); if (do_cmd(host, suser, bp, &remin, &remout) < 0) { (void) xfree(bp); ++errs; diff --git a/sftp.c b/sftp.c index 1aa37423c..d8728cc25 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.114 2009/12/06 23:53:54 dtucker Exp $ */ +/* $OpenBSD: sftp.c,v 1.115 2009/12/20 07:28:36 guenther Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -1809,7 +1809,8 @@ main(int argc, char **argv) fprintf(stderr, "Missing username\n"); usage(); } - addargs(&args, "-l%s", userhost); + addargs(&args, "-l"); + addargs(&args, "%s", userhost); } if ((cp = colon(host)) != NULL) { @@ -1829,6 +1830,7 @@ main(int argc, char **argv) if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); + addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); diff --git a/ssh.c b/ssh.c index 90dbc69e9..6abf31b52 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.328 2009/10/28 16:38:18 reyk Exp $ */ +/* $OpenBSD: ssh.c,v 1.329 2009/12/20 07:28:36 guenther Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -528,7 +528,7 @@ main(int ac, char **av) ac -= optind; av += optind; - if (ac > 0 && !host && **av != '-') { + if (ac > 0 && !host) { if (strrchr(*av, '@')) { p = xstrdup(*av); cp = strrchr(p, '@'); diff --git a/sshd_config.5 b/sshd_config.5 index e54e70079..6d2ad9df0 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.112 2009/11/10 02:58:56 djm Exp $ -.Dd $Mdocdate: November 10 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.113 2009/12/19 16:53:13 stevesk Exp $ +.Dd $Mdocdate: December 19 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -182,16 +182,16 @@ PAM or though authentication styles supported in The default is .Dq yes . .It Cm ChrootDirectory -Specifies a path to +Specifies the pathname of a directory to .Xr chroot 2 to after authentication. -This path, and all its components, must be root-owned directories that are +All components of the pathname must be root-owned directories that are not writable by any other user or group. After the chroot, .Xr sshd 8 changes the working directory to the user's home directory. .Pp -The path may contain the following tokens that are expanded at runtime once +The pathname may contain the following tokens that are expanded at runtime once the connecting user has been authenticated: %% is replaced by a literal '%', %h is replaced by the home directory of the user being authenticated, and %u is replaced by the username of that user. -- cgit v1.2.3 From 535b5e172166c2515500bc20f3ea89216bd1f42b Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 18:56:48 +1100 Subject: - stevesk@cvs.openbsd.org 2009/12/29 16:38:41 [sshd_config.5 readconf.c ssh_config.5 scp.1 servconf.c sftp.1 ssh.1] Rename RDomain config option to RoutingDomain to be more clear and consistent with other options. NOTE: if you currently use RDomain in the ssh client or server config, or ssh/sshd -o, you must update to use RoutingDomain. ok markus@ djm@ --- ChangeLog | 7 +++++++ readconf.c | 4 ++-- scp.1 | 6 +++--- servconf.c | 4 ++-- sftp.1 | 6 +++--- ssh.1 | 6 +++--- ssh_config.5 | 6 +++--- sshd_config.5 | 6 +++--- 8 files changed, 26 insertions(+), 19 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index feaa27aee..9256d6488 100644 --- a/ChangeLog +++ b/ChangeLog @@ -127,6 +127,13 @@ [readconf.c servconf.c misc.h ssh-keyscan.c misc.c] validate routing domain is in range 0-RT_TABLEID_MAX. 'Looks right' deraadt@ + - stevesk@cvs.openbsd.org 2009/12/29 16:38:41 + [sshd_config.5 readconf.c ssh_config.5 scp.1 servconf.c sftp.1 ssh.1] + Rename RDomain config option to RoutingDomain to be more clear and + consistent with other options. + NOTE: if you currently use RDomain in the ssh client or server config, + or ssh/sshd -o, you must update to use RoutingDomain. + ok markus@ djm@ 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/readconf.c b/readconf.c index 2f1b0cd3b..40fe8f694 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.180 2009/12/25 19:40:21 stevesk Exp $ */ +/* $OpenBSD: readconf.c,v 1.181 2009/12/29 16:38:41 stevesk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -229,7 +229,7 @@ static struct { { "permitlocalcommand", oPermitLocalCommand }, { "visualhostkey", oVisualHostKey }, { "useroaming", oUseRoaming }, - { "rdomain", oRDomain }, + { "routingdomain", oRDomain }, #ifdef JPAKE { "zeroknowledgepasswordauthentication", oZeroKnowledgePasswordAuthentication }, diff --git a/scp.1 b/scp.1 index b9245ea53..1d1cad0b0 100644 --- a/scp.1 +++ b/scp.1 @@ -9,9 +9,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.47 2009/10/28 16:38:18 reyk Exp $ +.\" $OpenBSD: scp.1,v 1.48 2009/12/29 16:38:41 stevesk Exp $ .\" -.Dd $Mdocdate: October 28 2009 $ +.Dd $Mdocdate: December 29 2009 $ .Dt SCP 1 .Os .Sh NAME @@ -158,9 +158,9 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication -.It RDomain .It RekeyLimit .It RhostsRSAAuthentication +.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/servconf.c b/servconf.c index 8b8518aa8..2cdc480e6 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.198 2009/12/25 19:40:21 stevesk Exp $ */ +/* $OpenBSD: servconf.c,v 1.199 2009/12/29 16:38:41 stevesk Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -424,7 +424,7 @@ static struct { { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, - { "rdomain", sRDomain, SSHCFG_GLOBAL }, + { "routingdomain", sRDomain, SSHCFG_GLOBAL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; diff --git a/sftp.1 b/sftp.1 index ab53c1690..81d87680d 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.78 2009/10/28 21:45:08 jmc Exp $ +.\" $OpenBSD: sftp.1,v 1.79 2009/12/29 16:38:41 stevesk Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: October 28 2009 $ +.Dd $Mdocdate: December 29 2009 $ .Dt SFTP 1 .Os .Sh NAME @@ -207,9 +207,9 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication -.It RDomain .It RekeyLimit .It RhostsRSAAuthentication +.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/ssh.1 b/ssh.1 index 8277d0fdf..2f6ef5fff 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.287 2009/10/28 16:38:18 reyk Exp $ -.Dd $Mdocdate: October 28 2009 $ +.\" $OpenBSD: ssh.1,v 1.288 2009/12/29 16:38:41 stevesk Exp $ +.Dd $Mdocdate: December 29 2009 $ .Dt SSH 1 .Os .Sh NAME @@ -475,10 +475,10 @@ For full details of the options listed below, and their possible values, see .It Protocol .It ProxyCommand .It PubkeyAuthentication -.It RDomain .It RekeyLimit .It RemoteForward .It RhostsRSAAuthentication +.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/ssh_config.5 b/ssh_config.5 index 001130936..442222cc5 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.123 2009/11/10 02:56:22 djm Exp $ -.Dd $Mdocdate: November 10 2009 $ +.\" $OpenBSD: ssh_config.5,v 1.124 2009/12/29 16:38:41 stevesk Exp $ +.Dd $Mdocdate: December 29 2009 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -789,7 +789,7 @@ or The default is .Dq yes . This option applies to protocol version 2 only. -.It Cm RDomain +.It Cm RoutingDomain Set the routing domain number. The default routing domain is set by the system. .It Cm RekeyLimit diff --git a/sshd_config.5 b/sshd_config.5 index 6d2ad9df0..ada265373 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.113 2009/12/19 16:53:13 stevesk Exp $ -.Dd $Mdocdate: December 19 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.114 2009/12/29 16:38:41 stevesk Exp $ +.Dd $Mdocdate: December 29 2009 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -806,7 +806,7 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. -.It Cm RDomain +.It Cm RoutingDomain Set the routing domain number. The default routing domain is set by the system. .It Cm RhostsRSAAuthentication -- cgit v1.2.3 From 98e5d9a0d3beabc706982260fec70f823ff764b7 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 8 Jan 2010 18:57:39 +1100 Subject: - jmc@cvs.openbsd.org 2009/12/29 18:03:32 [sshd_config.5 ssh_config.5] sort previous; --- ChangeLog | 3 +++ ssh_config.5 | 8 ++++---- sshd_config.5 | 8 ++++---- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 9256d6488..929907961 100644 --- a/ChangeLog +++ b/ChangeLog @@ -134,6 +134,9 @@ NOTE: if you currently use RDomain in the ssh client or server config, or ssh/sshd -o, you must update to use RoutingDomain. ok markus@ djm@ + - jmc@cvs.openbsd.org 2009/12/29 18:03:32 + [sshd_config.5 ssh_config.5] + sort previous; 20091226 - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 diff --git a/ssh_config.5 b/ssh_config.5 index 442222cc5..3ffc469c2 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.124 2009/12/29 16:38:41 stevesk Exp $ +.\" $OpenBSD: ssh_config.5,v 1.125 2009/12/29 18:03:32 jmc Exp $ .Dd $Mdocdate: December 29 2009 $ .Dt SSH_CONFIG 5 .Os @@ -789,9 +789,6 @@ or The default is .Dq yes . This option applies to protocol version 2 only. -.It Cm RoutingDomain -Set the routing domain number. -The default routing domain is set by the system. .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted before the session key is renegotiated. @@ -860,6 +857,9 @@ The default is This option applies to protocol version 1 only and requires .Xr ssh 1 to be setuid root. +.It Cm RoutingDomain +Set the routing domain number. +The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether to try RSA authentication. The argument to this keyword must be diff --git a/sshd_config.5 b/sshd_config.5 index ada265373..a3326447f 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.114 2009/12/29 16:38:41 stevesk Exp $ +.\" $OpenBSD: sshd_config.5,v 1.115 2009/12/29 18:03:32 jmc Exp $ .Dd $Mdocdate: December 29 2009 $ .Dt SSHD_CONFIG 5 .Os @@ -806,15 +806,15 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. -.It Cm RoutingDomain -Set the routing domain number. -The default routing domain is set by the system. .It Cm RhostsRSAAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. The default is .Dq no . This option applies to protocol version 1 only. +.It Cm RoutingDomain +Set the routing domain number. +The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is -- cgit v1.2.3 From 7bd98e7f74ebd8bd32157b607acedcb68201b7de Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 10 Jan 2010 10:31:12 +1100 Subject: - dtucker@cvs.openbsd.org 2010/01/09 23:04:13 [channels.c ssh.1 servconf.c sshd_config.5 sshd.c channels.h servconf.h ssh-keyscan.1 ssh-keyscan.c readconf.c sshconnect.c misc.c ssh.c readconf.h scp.1 sftp.1 ssh_config.5 misc.h] Remove RoutingDomain from ssh since it's now not needed. It can be replaced with "route exec" or "nc -V" as a proxycommand. "route exec" also ensures that trafic such as DNS lookups stays withing the specified routingdomain. For example (from reyk): # route -T 2 exec /usr/sbin/sshd or inherited from the parent process $ route -T 2 exec sh $ ssh 10.1.2.3 ok deraadt@ markus@ stevesk@ reyk@ --- ChangeLog | 13 +++++++++++++ channels.c | 26 +++++++------------------- channels.h | 3 +-- misc.c | 51 +-------------------------------------------------- misc.h | 5 +---- readconf.c | 22 +++------------------- readconf.h | 4 +--- scp.1 | 5 ++--- servconf.c | 20 ++------------------ servconf.h | 4 +--- sftp.1 | 5 ++--- ssh-keyscan.1 | 7 ++----- ssh-keyscan.c | 19 ++++--------------- ssh.1 | 5 ++--- ssh.c | 3 +-- ssh_config.5 | 7 ++----- sshconnect.c | 5 ++--- sshd.c | 9 ++++----- sshd_config.5 | 7 ++----- 19 files changed, 53 insertions(+), 167 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index e38cd5108..ca189f943 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,19 @@ 20091210 - (dtucker) [configure.ac misc.c readconf.c servconf.c ssh-keyscan.c] Remove hacks add for RoutingDomain in preparation for its removal. + - dtucker@cvs.openbsd.org 2010/01/09 23:04:13 + [channels.c ssh.1 servconf.c sshd_config.5 sshd.c channels.h servconf.h + ssh-keyscan.1 ssh-keyscan.c readconf.c sshconnect.c misc.c ssh.c + readconf.h scp.1 sftp.1 ssh_config.5 misc.h] + Remove RoutingDomain from ssh since it's now not needed. It can be + replaced with "route exec" or "nc -V" as a proxycommand. "route exec" + also ensures that trafic such as DNS lookups stays withing the specified + routingdomain. For example (from reyk): + # route -T 2 exec /usr/sbin/sshd + or inherited from the parent process + $ route -T 2 exec sh + $ ssh 10.1.2.3 + ok deraadt@ markus@ stevesk@ reyk@ 20091209 - (dtucker) Wrap use of IPPROTO_IPV6 in an ifdef for platforms that don't diff --git a/channels.c b/channels.c index 949392390..87dbe96d3 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.299 2009/11/11 21:37:03 markus Exp $ */ +/* $OpenBSD: channels.c,v 1.300 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -163,9 +163,6 @@ static u_int x11_fake_data_len; /* AF_UNSPEC or AF_INET or AF_INET6 */ static int IPv4or6 = AF_UNSPEC; -/* Set the routing domain a.k.a. VRF */ -static int channel_rdomain = -1; - /* helper */ static void port_open_helper(Channel *c, char *rtype); @@ -2466,12 +2463,6 @@ channel_set_af(int af) IPv4or6 = af; } -void -channel_set_rdomain(int rdomain) -{ - channel_rdomain = rdomain; -} - static int channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, int *allocated_listen_port, @@ -2580,8 +2571,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, continue; } /* Create a port to listen for the host. */ - sock = socket_rdomain(ai->ai_family, ai->ai_socktype, - ai->ai_protocol, channel_rdomain); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { /* this is no error since kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); @@ -2922,9 +2912,8 @@ connect_next(struct channel_connect *cctx) error("connect_next: getnameinfo failed"); continue; } - if ((sock = socket_rdomain(cctx->ai->ai_family, - cctx->ai->ai_socktype, cctx->ai->ai_protocol, - channel_rdomain)) == -1) { + if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype, + cctx->ai->ai_protocol)) == -1) { if (cctx->ai->ai_next == NULL) error("socket: %.100s", strerror(errno)); else @@ -3110,8 +3099,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; - sock = socket_rdomain(ai->ai_family, ai->ai_socktype, - ai->ai_protocol, channel_rdomain); + sock = socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol); if (sock < 0) { if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) { error("socket: %.100s", strerror(errno)); @@ -3286,8 +3275,7 @@ x11_connect_display(void) } for (ai = aitop; ai; ai = ai->ai_next) { /* Create a socket. */ - sock = socket_rdomain(ai->ai_family, ai->ai_socktype, - ai->ai_protocol, channel_rdomain); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { debug2("socket: %.100s", strerror(errno)); continue; diff --git a/channels.h b/channels.h index 4dbeeb6e1..f65a311dc 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.100 2009/11/11 21:37:03 markus Exp $ */ +/* $OpenBSD: channels.h,v 1.101 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -235,7 +235,6 @@ int channel_find_open(void); /* tcp forwarding */ void channel_set_af(int af); -void channel_set_rdomain(int); void channel_permit_all_opens(void); void channel_add_permitted_opens(char *, int); int channel_add_adm_permitted_opens(char *, int); diff --git a/misc.c b/misc.c index 550b03cad..e1f723123 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.74 2009/12/25 19:40:21 stevesk Exp $ */ +/* $OpenBSD: misc.c,v 1.75 2010/01/09 23:04:13 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -151,43 +151,6 @@ set_nodelay(int fd) error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); } -/* open a socket in the specified routing domain */ -int -socket_rdomain(int domain, int type, int protocol, int rdomain) -{ - int sock, ipproto = IPPROTO_IP; - - if ((sock = socket(domain, type, protocol)) == -1) - return (-1); - - if (rdomain == -1) - return (sock); - - switch (domain) { - case AF_INET6: - ipproto = IPPROTO_IPV6; - /* FALLTHROUGH */ - case AF_INET: - debug2("socket %d af %d setting rdomain %d", - sock, domain, rdomain); - if (setsockopt(sock, ipproto, SO_RDOMAIN, &rdomain, - sizeof(rdomain)) == -1) { - debug("setsockopt SO_RDOMAIN: %.100s", - strerror(errno)); - close(sock); - return (-1); - } - break; - default: - debug("socket %d af %d does not support rdomain %d", - sock, domain, rdomain); - close(sock); - return (-1); - } - - return (sock); -} - /* Characters considered whitespace in strsep calls. */ #define WHITESPACE " \t\r\n" #define QUOTE "\"" @@ -273,18 +236,6 @@ a2port(const char *s) return (int)port; } -int -a2rdomain(const char *s) -{ - long long rdomain; - const char *errstr; - - rdomain = strtonum(s, 0, RT_TABLEID_MAX, &errstr); - if (errstr != NULL) - return -1; - return (int)rdomain; -} - int a2tun(const char *s, int *remote) { diff --git a/misc.h b/misc.h index 1e859e255..32073acd4 100644 --- a/misc.h +++ b/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.40 2009/12/25 19:40:21 stevesk Exp $ */ +/* $OpenBSD: misc.h,v 1.41 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -23,7 +23,6 @@ int set_nonblock(int); int unset_nonblock(int); void set_nodelay(int); int a2port(const char *); -int a2rdomain(const char *); int a2tun(const char *, int *); char *put_host_port(const char *, u_short); char *hpdelim(char **); @@ -55,8 +54,6 @@ void freeargs(arglist *); int tun_open(int, int); -int socket_rdomain(int, int, int, int); - /* Common definitions for ssh tunnel device forwarding */ #define SSH_TUNMODE_NO 0x00 #define SSH_TUNMODE_POINTOPOINT 0x01 diff --git a/readconf.c b/readconf.c index 40fe8f694..d424c1697 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.181 2009/12/29 16:38:41 stevesk Exp $ */ +/* $OpenBSD: readconf.c,v 1.182 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -130,8 +130,8 @@ typedef enum { oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, - oVisualHostKey, oUseRoaming, oRDomain, - oZeroKnowledgePasswordAuthentication, oDeprecated, oUnsupported + oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, + oDeprecated, oUnsupported } OpCodes; /* Textual representations of the tokens. */ @@ -229,7 +229,6 @@ static struct { { "permitlocalcommand", oPermitLocalCommand }, { "visualhostkey", oVisualHostKey }, { "useroaming", oUseRoaming }, - { "routingdomain", oRDomain }, #ifdef JPAKE { "zeroknowledgepasswordauthentication", oZeroKnowledgePasswordAuthentication }, @@ -920,19 +919,6 @@ parse_int: intptr = &options->use_roaming; goto parse_flag; - case oRDomain: - arg = strdelim(&s); - if (!arg || *arg == '\0') - fatal("%.200s line %d: Missing argument.", - filename, linenum); - value = a2rdomain(arg); - if (value == -1) - fatal("%.200s line %d: Bad rdomain.", - filename, linenum); - if (*activep) - options->rdomain = value; - break; - case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1083,7 +1069,6 @@ initialize_options(Options * options) options->local_command = NULL; options->permit_local_command = -1; options->use_roaming = -1; - options->rdomain = -1; options->visual_host_key = -1; options->zero_knowledge_password_authentication = -1; } @@ -1232,7 +1217,6 @@ fill_default_options(Options * options) /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ - /* options->rdomain should not be set by default */ } /* diff --git a/readconf.h b/readconf.h index 6edc2eeda..f7c0b9c6d 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.80 2009/10/28 16:38:18 reyk Exp $ */ +/* $OpenBSD: readconf.h,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -125,8 +125,6 @@ typedef struct { int use_roaming; - int rdomain; /* routing domain a.k.a. VRF */ - } Options; #define SSHCTL_MASTER_NO 0 diff --git a/scp.1 b/scp.1 index 1d1cad0b0..74ee5db13 100644 --- a/scp.1 +++ b/scp.1 @@ -9,9 +9,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.48 2009/12/29 16:38:41 stevesk Exp $ +.\" $OpenBSD: scp.1,v 1.49 2010/01/09 23:04:13 dtucker Exp $ .\" -.Dd $Mdocdate: December 29 2009 $ +.Dd $Mdocdate: January 9 2010 $ .Dt SCP 1 .Os .Sh NAME @@ -160,7 +160,6 @@ For full details of the options listed below, and their possible values, see .It PubkeyAuthentication .It RekeyLimit .It RhostsRSAAuthentication -.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/servconf.c b/servconf.c index 2cdc480e6..fc3e479bd 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.199 2009/12/29 16:38:41 stevesk Exp $ */ +/* $OpenBSD: servconf.c,v 1.200 2010/01/09 23:04:13 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -128,7 +128,6 @@ initialize_server_options(ServerOptions *options) options->adm_forced_command = NULL; options->chroot_directory = NULL; options->zero_knowledge_password_authentication = -1; - options->rdomain = -1; } void @@ -305,7 +304,7 @@ typedef enum { sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, sRDomain, + sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sDeprecated, sUnsupported } ServerOpCodes; @@ -424,7 +423,6 @@ static struct { { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, - { "routingdomain", sRDomain, SSHCFG_GLOBAL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -1296,19 +1294,6 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; - case sRDomain: - intptr = &options->rdomain; - arg = strdelim(&cp); - if (!arg || *arg == '\0') - fatal("%s line %d: missing rdomain value.", - filename, linenum); - if ((value = a2rdomain(arg)) == -1) - fatal("%s line %d: invalid rdomain value.", - filename, linenum); - if (*intptr == -1) - *intptr = value; - break; - case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1585,7 +1570,6 @@ dump_config(ServerOptions *o) dump_cfg_int(sMaxSessions, o->max_sessions); dump_cfg_int(sClientAliveInterval, o->client_alive_interval); dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); - dump_cfg_int(sRDomain, o->rdomain); /* formatted integer arguments */ dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login); diff --git a/servconf.h b/servconf.h index 19c7ae609..25a3f1b21 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.88 2009/10/28 16:38:18 reyk Exp $ */ +/* $OpenBSD: servconf.h,v 1.89 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -150,8 +150,6 @@ typedef struct { int num_permitted_opens; - int rdomain; - char *chroot_directory; } ServerOptions; diff --git a/sftp.1 b/sftp.1 index 81d87680d..3ec7a0234 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.79 2009/12/29 16:38:41 stevesk Exp $ +.\" $OpenBSD: sftp.1,v 1.80 2010/01/09 23:04:13 dtucker Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: December 29 2009 $ +.Dd $Mdocdate: January 9 2010 $ .Dt SFTP 1 .Os .Sh NAME @@ -209,7 +209,6 @@ For full details of the options listed below, and their possible values, see .It PubkeyAuthentication .It RekeyLimit .It RhostsRSAAuthentication -.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/ssh-keyscan.1 b/ssh-keyscan.1 index c9fb597ed..78255ff79 100644 --- a/ssh-keyscan.1 +++ b/ssh-keyscan.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.27 2009/10/28 16:38:18 reyk Exp $ +.\" $OpenBSD: ssh-keyscan.1,v 1.28 2010/01/09 23:04:13 dtucker Exp $ .\" .\" Copyright 1995, 1996 by David Mazieres . .\" @@ -6,7 +6,7 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" -.Dd $Mdocdate: October 28 2009 $ +.Dd $Mdocdate: January 9 2010 $ .Dt SSH-KEYSCAN 1 .Os .Sh NAME @@ -20,7 +20,6 @@ .Op Fl p Ar port .Op Fl T Ar timeout .Op Fl t Ar type -.Op Fl V Ar rdomain .Op Ar host | addrlist namelist .Ar ... .Ek @@ -96,8 +95,6 @@ for protocol version 2. Multiple values may be specified by separating them with commas. The default is .Dq rsa . -.It Fl V Ar rdomain -Set the routing domain. .It Fl v Verbose mode. Causes diff --git a/ssh-keyscan.c b/ssh-keyscan.c index faeb9e13e..7afe446ae 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.80 2009/12/25 19:40:21 stevesk Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -68,9 +68,6 @@ int timeout = 5; int maxfd; #define MAXCON (maxfd - 10) -/* The default routing domain */ -int scan_rdomain = -1; - extern char *__progname; fd_set *read_wait; size_t read_wait_nfdset; @@ -415,8 +412,7 @@ tcpconnect(char *host) if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) fatal("getaddrinfo %s: %s", host, ssh_gai_strerror(gaierr)); for (ai = aitop; ai; ai = ai->ai_next) { - s = socket_rdomain(ai->ai_family, ai->ai_socktype, - ai->ai_protocol, scan_rdomain); + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s < 0) { error("socket: %s", strerror(errno)); continue; @@ -719,7 +715,7 @@ usage(void) { fprintf(stderr, "usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n" - "\t\t [-V rdomain] [host | addrlist namelist] ...\n", + "\t\t [host | addrlist namelist] ...\n", __progname); exit(1); } @@ -745,7 +741,7 @@ main(int argc, char **argv) if (argc <= 1) usage(); - while ((opt = getopt(argc, argv, "Hv46p:T:t:f:V:")) != -1) { + while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) { switch (opt) { case 'H': hash_hosts = 1; @@ -806,13 +802,6 @@ main(int argc, char **argv) case '6': IPv4or6 = AF_INET6; break; - case 'V': - scan_rdomain = a2rdomain(optarg); - if (scan_rdomain == -1) { - fprintf(stderr, "Bad rdomain '%s'\n", optarg); - exit(1); - } - break; case '?': default: usage(); diff --git a/ssh.1 b/ssh.1 index 2f6ef5fff..8b228fcdf 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.288 2009/12/29 16:38:41 stevesk Exp $ -.Dd $Mdocdate: December 29 2009 $ +.\" $OpenBSD: ssh.1,v 1.289 2010/01/09 23:04:13 dtucker Exp $ +.Dd $Mdocdate: January 9 2010 $ .Dt SSH 1 .Os .Sh NAME @@ -478,7 +478,6 @@ For full details of the options listed below, and their possible values, see .It RekeyLimit .It RemoteForward .It RhostsRSAAuthentication -.It RoutingDomain .It RSAAuthentication .It SendEnv .It ServerAliveInterval diff --git a/ssh.c b/ssh.c index 6abf31b52..ee30e2b27 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.329 2009/12/20 07:28:36 guenther Exp $ */ +/* $OpenBSD: ssh.c,v 1.330 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -630,7 +630,6 @@ main(int ac, char **av) fill_default_options(&options); channel_set_af(options.address_family); - channel_set_rdomain(options.rdomain); /* reinit */ log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); diff --git a/ssh_config.5 b/ssh_config.5 index 3ffc469c2..01f5f4304 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.125 2009/12/29 18:03:32 jmc Exp $ -.Dd $Mdocdate: December 29 2009 $ +.\" $OpenBSD: ssh_config.5,v 1.126 2010/01/09 23:04:13 dtucker Exp $ +.Dd $Mdocdate: January 9 2010 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -857,9 +857,6 @@ The default is This option applies to protocol version 1 only and requires .Xr ssh 1 to be setuid root. -.It Cm RoutingDomain -Set the routing domain number. -The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether to try RSA authentication. The argument to this keyword must be diff --git a/sshconnect.c b/sshconnect.c index 3c8308ffb..5cfc3c16a 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.216 2009/11/10 04:30:45 dtucker Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.217 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -191,8 +191,7 @@ ssh_create_socket(int privileged, struct addrinfo *ai) debug("Allocated local port %d.", p); return sock; } - sock = socket_rdomain(ai->ai_family, ai->ai_socktype, ai->ai_protocol, - options.rdomain); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { error("socket: %.100s", strerror(errno)); return -1; diff --git a/sshd.c b/sshd.c index bdaf1574a..4e34f2439 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.369 2010/01/09 11:17:56 dtucker Exp $ */ +/* $OpenBSD: sshd.c,v 1.370 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -961,8 +961,8 @@ server_listen(void) continue; } /* Create socket for listening. */ - listen_sock = socket_rdomain(ai->ai_family, ai->ai_socktype, - ai->ai_protocol, options.rdomain); + listen_sock = socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol); if (listen_sock < 0) { /* kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); @@ -1470,9 +1470,8 @@ main(int ac, char **av) if (options.challenge_response_authentication) options.kbd_interactive_authentication = 1; - /* set default channel AF and routing domain */ + /* set default channel AF */ channel_set_af(options.address_family); - channel_set_rdomain(options.rdomain); /* Check that there are no remaining arguments. */ if (optind < ac) { diff --git a/sshd_config.5 b/sshd_config.5 index a3326447f..bf3319c4d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.115 2009/12/29 18:03:32 jmc Exp $ -.Dd $Mdocdate: December 29 2009 $ +.\" $OpenBSD: sshd_config.5,v 1.116 2010/01/09 23:04:13 dtucker Exp $ +.Dd $Mdocdate: January 9 2010 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -812,9 +812,6 @@ with successful RSA host authentication is allowed. The default is .Dq no . This option applies to protocol version 1 only. -.It Cm RoutingDomain -Set the routing domain number. -The default routing domain is set by the system. .It Cm RSAAuthentication Specifies whether pure RSA authentication is allowed. The default is -- cgit v1.2.3 From 0a80ca190a39943029719facf7edb990def7ae62 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sat, 27 Feb 2010 07:55:05 +1100 Subject: - 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@ --- ChangeLog | 33 +++ PROTOCOL | 23 ++- PROTOCOL.agent | 24 ++- PROTOCOL.certkeys | 191 ++++++++++++++++++ addrmatch.c | 78 ++++++- auth-options.c | 150 +++++++++++++- auth-options.h | 4 +- auth.h | 5 +- auth2-pubkey.c | 37 +++- authfd.c | 24 ++- dns.c | 8 +- dns.h | 6 +- hostfile.c | 31 ++- hostfile.h | 4 +- kex.h | 5 +- kexdhs.c | 19 +- kexgexs.c | 20 +- key.c | 595 ++++++++++++++++++++++++++++++++++++++++++++++++++---- key.h | 32 ++- match.h | 4 +- monitor.c | 5 +- myproposal.h | 6 +- servconf.c | 19 +- servconf.h | 5 +- ssh-add.c | 34 +++- ssh-agent.c | 24 ++- ssh-dss.c | 10 +- ssh-keygen.1 | 178 +++++++++++++++- ssh-keygen.c | 433 ++++++++++++++++++++++++++++++++++++--- ssh-rsa.c | 10 +- ssh.1 | 23 ++- ssh.c | 71 +++++-- ssh2.h | 5 +- sshconnect.c | 78 +++++-- sshconnect2.c | 4 +- sshd.8 | 25 ++- sshd.c | 117 +++++++++-- sshd_config.5 | 12 +- 38 files changed, 2164 insertions(+), 188 deletions(-) create mode 100644 PROTOCOL.certkeys (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 10c074c26..fec38e028 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +20100226 + - 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 trusted in ~/.ssh/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@ + 20100224 - (djm) [pkcs11.h ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] [ssh-pkcs11.h] Add $OpenBSD$ RCS idents so we can sync portable diff --git a/PROTOCOL b/PROTOCOL index 9b74b9475..5fc31eade 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -31,7 +31,14 @@ The method is documented in: http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt -3. connection: Channel write close extension "eow@openssh.com" +3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com" and + "ssh-dsa-cert-v00@openssh.com" + +OpenSSH introduces two new public key algorithms to support certificate +authentication for users and hostkeys. These methods are documented in +the file PROTOCOL.certkeys + +4. connection: Channel write close extension "eow@openssh.com" The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF message to allow an endpoint to signal its peer that it will send no @@ -70,7 +77,7 @@ message is only sent to OpenSSH peers (identified by banner). Other SSH implementations may be whitelisted to receive this message upon request. -4. connection: disallow additional sessions extension +5. connection: disallow additional sessions extension "no-more-sessions@openssh.com" Most SSH connections will only ever request a single session, but a @@ -98,7 +105,7 @@ of this message, the no-more-sessions request is only sent to OpenSSH servers (identified by banner). Other SSH implementations may be whitelisted to receive this message upon request. -5. connection: Tunnel forward extension "tun@openssh.com" +6. connection: Tunnel forward extension "tun@openssh.com" OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com" channel type. This channel type supports forwarding of network packets @@ -159,7 +166,7 @@ The contents of the "data" field for layer 2 packets is: The "frame" field contains an IEEE 802.3 Ethernet frame, including header. -6. sftp: Reversal of arguments to SSH_FXP_SYMLINK +7. sftp: Reversal of arguments to SSH_FXP_SYMLINK When OpenSSH's sftp-server was implemented, the order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately, @@ -172,7 +179,7 @@ SSH_FXP_SYMLINK as follows: string targetpath string linkpath -7. sftp: Server extension announcement in SSH_FXP_VERSION +8. sftp: Server extension announcement in SSH_FXP_VERSION OpenSSH's sftp-server lists the extensions it supports using the standard extension announcement mechanism in the SSH_FXP_VERSION server @@ -193,7 +200,7 @@ ever changed in an incompatible way. The server MAY advertise the same extension with multiple versions (though this is unlikely). Clients MUST check the version number before attempting to use the extension. -8. sftp: Extension request "posix-rename@openssh.com" +9. sftp: Extension request "posix-rename@openssh.com" This operation provides a rename operation with POSIX semantics, which are different to those provided by the standard SSH_FXP_RENAME in @@ -210,7 +217,7 @@ rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -9. sftp: Extension requests "statvfs@openssh.com" and +10. sftp: Extension requests "statvfs@openssh.com" and "fstatvfs@openssh.com" These requests correspond to the statvfs and fstatvfs POSIX system @@ -251,4 +258,4 @@ The values of the f_flag bitmask are as follows: Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are advertised in the SSH_FXP_VERSION hello with version "2". -$OpenBSD: PROTOCOL,v 1.14 2010/01/09 00:57:10 djm Exp $ +$OpenBSD: PROTOCOL,v 1.15 2010/02/26 20:29:54 djm Exp $ diff --git a/PROTOCOL.agent b/PROTOCOL.agent index 49adbdd5c..b34fcd318 100644 --- a/PROTOCOL.agent +++ b/PROTOCOL.agent @@ -173,6 +173,15 @@ be added using the following request string key_comment constraint[] key_constraints +DSA certificates may be added with: + byte SSH2_AGENTC_ADD_IDENTITY or + SSH2_AGENTC_ADD_ID_CONSTRAINED + string "ssh-dss-cert-v00@openssh.com" + string certificate + mpint dsa_private_key + string key_comment + constraint[] key_constraints + RSA keys may be added with this request: byte SSH2_AGENTC_ADD_IDENTITY or @@ -187,6 +196,19 @@ RSA keys may be added with this request: string key_comment constraint[] key_constraints +RSA certificates may be added with this request: + + byte SSH2_AGENTC_ADD_IDENTITY or + SSH2_AGENTC_ADD_ID_CONSTRAINED + string "ssh-rsa-cert-v00@openssh.com" + string certificate + mpint rsa_d + mpint rsa_iqmp + mpint rsa_p + mpint rsa_q + string key_comment + constraint[] key_constraints + Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse order to the protocol 1 add keys message. As with the corresponding protocol 1 "add key" request, the private key is overspecified to avoid @@ -513,4 +535,4 @@ Locking and unlocking affects both protocol 1 and protocol 2 keys. SSH_AGENT_CONSTRAIN_LIFETIME 1 SSH_AGENT_CONSTRAIN_CONFIRM 2 -$OpenBSD: PROTOCOL.agent,v 1.4 2008/07/01 23:12:47 stevesk Exp $ +$OpenBSD: PROTOCOL.agent,v 1.5 2010/02/26 20:29:54 djm Exp $ diff --git a/PROTOCOL.certkeys b/PROTOCOL.certkeys new file mode 100644 index 000000000..0b887a240 --- /dev/null +++ b/PROTOCOL.certkeys @@ -0,0 +1,191 @@ +This document describes a simple public-key certificate authentication +system for use by SSH. + +Background +---------- + +The SSH protocol currently supports a simple public key authentication +mechanism. Unlike other public key implementations, SSH eschews the +use of X.509 certificates and uses raw keys. This approach has some +benefits relating to simplicity of configuration and minimisation +of attack surface, but it does not support the important use-cases +of centrally managed, passwordless authentication and centrally +certified host keys. + +These protocol extensions build on the simple public key authentication +system already in SSH to allow certificate-based authentication. +The certificates used are not traditional X.509 certificates, with +numerous options and complex encoding rules, but something rather +more minimal: a key, some identity information and usage constraints +that have been signed with some other trusted key. + +A sshd server may be configured to allow authentication via certified +keys, by extending the existing ~/.ssh/authorized_keys mechanism +to allow specification of certification authority keys in addition +to raw user keys. The ssh client will support automatic verification +of acceptance of certified host keys, by adding a similar ability +to specify CA keys in ~/.ssh/known_hosts. + +Certified keys are represented using two new key types: +ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com that +include certification information along with the public key that is used +to sign challenges. ssh-keygen performs the CA signing operation. + +Protocol extensions +------------------- + +The SSH wire protocol includes several extensibility mechanisms. +These modifications shall take advantage of namespaced public key +algorithm names to add support for certificate authentication without +breaking the protocol - implementations that do not support the +extensions will simply ignore them. + +Authentication using the new key formats described below proceeds +using the existing SSH "publickey" authentication method described +in RFC4252 section 7. + +New public key formats +---------------------- + +The ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com key +types take a similar same high-level format (note: data types and +encoding are as per RFC4251 section 5). The serialised wire encoding of +these certificates is also used for storing them on disk. + +#define SSH_CERT_TYPE_USER 1 +#define SSH_CERT_TYPE_HOST 2 + +RSA certificate + + string "ssh-rsa-cert-v00@openssh.com" + mpint e + mpint n + uint32 type + string key id + string valid principals + uint64 valid after + uint64 valid before + string constraints + string nonce + string reserved + string signature key + string signature + +DSA certificate + + string "ssh-dss-cert-v00@openssh.com" + mpint p + mpint q + mpint g + mpint y + uint32 type + string key id + string valid principals + uint64 valid after + uint64 valid before + string constraints + string nonce + string reserved + string signature key + string signature + +e and n are the RSA exponent and public modulus respectively. + +p, q, g, y are the DSA parameters as described in FIPS-186-2. + +type specifies whether this certificate is for identification of a user +or a host using a SSH_CERT_TYPE_... value. + +key id is a free-form text field that is filled in by the CA at the time +of signing; the intention is that the contents of this field are used to +identify the identity principal in log messages. + +"valid principals" is a string containing zero or more principals as +strings packed inside it. These principals list the names for which this +certificate is valid; hostnames for SSH_CERT_TYPE_HOST certificates and +usernames for SSH_CERT_TYPE_USER certificates. As a special case, a +zero-length "valid principals" field means the certificate is valid for +any principal of the specified type. XXX DNS wildcards? + +"valid after" and "valid before" specify a validity period for the +certificate. Each represents a time in seconds since 1970-01-01 +00:00:00. A certificate is considered valid if: + valid after <= current time < valid before + +constraints is a set of zero or more key constraints encoded as below. + +The nonce field is a CA-provided random bitstring of arbitrary length +(but typically 16 or 32 bytes) included to make attacks that depend on +inducing collisions in the signature hash infeasible. + +The reserved field is current unused and is ignored in this version of +the protocol. + +signature key contains the CA key used to sign the certificate. +The valid key types for CA keys are ssh-rsa and ssh-dss. "Chained" +certificates, where the signature key type is a certificate type itself +are NOT supported. Note that it is possible for a RSA certificate key to +be signed by a DSS CA key and vice-versa. + +signature is computed over all preceding fields from the initial string +up to, and including the signature key. Signatures are computed and +encoded according to the rules defined for the CA's public key algorithm +(RFC4253 section 6.6 for ssh-rsa and ssh-dss). + +Constraints +----------- + +The constraints section of the certificate specifies zero or more +constraints on the certificates validity. The format of this field +is a sequence of zero or more tuples: + + string name + string data + +The name field identifies the constraint and the data field encodes +constraint-specific information (see below). All constraints are +"critical", if an implementation does not recognise a constraint +then the validating party should refuse to accept the certificate. + +The supported constraints and the contents and structure of their +data fields are: + +Name Format Description +----------------------------------------------------------------------------- +force-command string Specifies a command that is executed + (replacing any the user specified on the + ssh command-line) whenever this key is + used for authentication. + +permit-X11-forwarding empty Flag indicating that X11 forwarding + should be permitted. X11 forwarding will + be refused if this constraint is absent. + +permit-agent-forwarding empty Flag indicating that agent forwarding + should be allowed. Agent forwarding + must not be permitted unless this + constraint is present. + +permit-port-forwarding empty Flag indicating that port-forwarding + should be allowed. If this constraint is + not present then no port forwarding will + be allowed. + +permit-pty empty Flag indicating that PTY allocation + should be permitted. In the absence of + this constraint PTY allocation will be + disabled. + +permit-user-rc empty Flag indicating that execution of + ~/.ssh/rc should be permitted. Execution + of this script will not be permitted if + this constraint is not present. + +source-address string Comma-separated list of source addresses + from which this certificate is accepted + for authentication. Addresses are + specified in CIDR format (nn.nn.nn.nn/nn + or hhhh::hhhh/nn). + If this constraint is not present then + certificates may be presented from any + source address. diff --git a/addrmatch.c b/addrmatch.c index d39885b7b..5b6773cce 100644 --- a/addrmatch.c +++ b/addrmatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */ +/* $OpenBSD: addrmatch.c,v 1.5 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2004-2008 Damien Miller @@ -126,6 +126,8 @@ addr_netmask(int af, u_int l, struct xaddr *n) switch (af) { case AF_INET: n->af = AF_INET; + if (l == 0) + return 0; n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); return 0; case AF_INET6: @@ -422,3 +424,77 @@ addr_match_list(const char *addr, const char *_list) return ret; } + +/* + * Match "addr" against list CIDR list "_list". Lexical wildcards and + * negation are not supported. If "addr" == NULL, will verify structure + * of "_list". + * + * Returns 1 on match found (never returned when addr == NULL). + * Returns 0 on if no match found, or no errors found when addr == NULL. + * Returns -1 on error + */ +int +addr_match_cidr_list(const char *addr, const char *_list) +{ + char *list, *cp, *o; + struct xaddr try_addr, match_addr; + u_int masklen; + int ret = 0, r; + + if (addr != NULL && addr_pton(addr, &try_addr) != 0) { + debug2("%s: couldn't parse address %.100s", __func__, addr); + return 0; + } + if ((o = list = strdup(_list)) == NULL) + return -1; + while ((cp = strsep(&list, ",")) != NULL) { + if (*cp == '\0') { + error("%s: empty entry in list \"%.100s\"", + __func__, o); + ret = -1; + break; + } + + /* + * NB. This function is called in pre-auth with untrusted data, + * so be extra paranoid about junk reaching getaddrino (via + * addr_pton_cidr). + */ + + /* Stop junk from reaching getaddrinfo. +3 is for masklen */ + if (strlen(cp) > INET6_ADDRSTRLEN + 3) { + error("%s: list entry \"%.100s\" too long", + __func__, cp); + ret = -1; + break; + } +#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/" + if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) { + error("%s: list entry \"%.100s\" contains invalid " + "characters", __func__, cp); + ret = -1; + } + + /* Prefer CIDR address matching */ + r = addr_pton_cidr(cp, &match_addr, &masklen); + if (r == -1) { + error("Invalid network entry \"%.100s\"", cp); + ret = -1; + break; + } else if (r == -2) { + error("Inconsistent mask length for " + "network \"%.100s\"", cp); + ret = -1; + break; + } else if (r == 0 && addr != NULL) { + if (addr_netmatch(&try_addr, &match_addr, + masklen) == 0) + ret = 1; + continue; + } + } + xfree(o); + + return ret; +} diff --git a/auth-options.c b/auth-options.c index ab085c233..396bda62f 100644 --- a/auth-options.c +++ b/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 djm Exp $ */ +/* $OpenBSD: auth-options.c,v 1.45 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -44,6 +44,7 @@ int no_agent_forwarding_flag = 0; int no_x11_forwarding_flag = 0; int no_pty_flag = 0; int no_user_rc = 0; +int key_is_cert_authority = 0; /* "command=" option. */ char *forced_command = NULL; @@ -64,6 +65,7 @@ auth_clear_options(void) no_pty_flag = 0; no_x11_forwarding_flag = 0; no_user_rc = 0; + key_is_cert_authority = 0; while (custom_environment) { struct envstring *ce = custom_environment; custom_environment = ce->next; @@ -96,6 +98,12 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) return 1; while (*opts && *opts != ' ' && *opts != '\t') { + cp = "cert-authority"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + key_is_cert_authority = 1; + opts += strlen(cp); + goto next_option; + } cp = "no-port-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Port forwarding disabled."); @@ -374,3 +382,143 @@ bad_option: /* deny access */ return 0; } + +/* + * Set options from certificate constraints. These supersede user key options + * so this must be called after auth_parse_options(). + */ +int +auth_cert_constraints(Buffer *c_orig, struct passwd *pw) +{ + u_char *name = NULL, *data_blob = NULL; + u_int len; + Buffer c, data; + int ret = -1; + + int cert_no_port_forwarding_flag = 1; + int cert_no_agent_forwarding_flag = 1; + int cert_no_x11_forwarding_flag = 1; + int cert_no_pty_flag = 1; + int cert_no_user_rc = 1; + char *cert_forced_command = NULL; + int cert_source_address_done = 0; + + buffer_init(&data); + + /* Make copy to avoid altering original */ + buffer_init(&c); + buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig)); + + while (buffer_len(&c) > 0) { + if ((name = buffer_get_string_ret(&c, NULL)) == NULL || + (data_blob = buffer_get_string_ret(&c, &len)) == NULL) { + error("Certificate constraints corrupt"); + goto out; + } + buffer_append(&data, data_blob, len); + debug3("found certificate constraint \"%.100s\" len %u", + name, len); + if (strcmp(name, "permit-X11-forwarding") == 0) + cert_no_x11_forwarding_flag = 0; + else if (strcmp(name, "permit-agent-forwarding") == 0) + cert_no_agent_forwarding_flag = 0; + else if (strcmp(name, "permit-port-forwarding") == 0) + cert_no_port_forwarding_flag = 0; + else if (strcmp(name, "permit-pty") == 0) + cert_no_pty_flag = 0; + else if (strcmp(name, "permit-user-rc") == 0) + cert_no_user_rc = 0; + else if (strcmp(name, "force-command") == 0) { + char *command = buffer_get_string_ret(&data, NULL); + + if (command == NULL) { + error("Certificate constraint \"%s\" corrupt", + name); + goto out; + } + if (cert_forced_command != NULL) { + error("Certificate has multiple " + "forced-command constraints"); + xfree(command); + goto out; + } + cert_forced_command = command; + } else if (strcmp(name, "source-address") == 0) { + char *allowed = buffer_get_string_ret(&data, NULL); + const char *remote_ip = get_remote_ipaddr(); + + if (allowed == NULL) { + error("Certificate constraint \"%s\" corrupt", + name); + goto out; + } + if (cert_source_address_done++) { + error("Certificate has multiple " + "source-address constraints"); + xfree(allowed); + goto out; + } + switch (addr_match_cidr_list(remote_ip, allowed)) { + case 1: + /* accepted */ + xfree(allowed); + break; + case 0: + /* no match */ + logit("Authentication tried for %.100s with " + "valid certificate but not from a " + "permitted host (ip=%.200s).", + pw->pw_name, remote_ip); + auth_debug_add("Your address '%.200s' is not " + "permitted to use this certificate for " + "login.", remote_ip); + xfree(allowed); + goto out; + case -1: + error("Certificate source-address contents " + "invalid"); + xfree(allowed); + goto out; + } + } else { + error("Certificate constraint \"%s\" is not supported", + name); + goto out; + } + + if (buffer_len(&data) != 0) { + error("Certificate constraint \"%s\" corrupt " + "(extra data)", name); + goto out; + } + buffer_clear(&data); + xfree(name); + xfree(data_blob); + name = data_blob = NULL; + } + + /* successfully parsed all constraints */ + ret = 0; + + no_port_forwarding_flag |= cert_no_port_forwarding_flag; + no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; + no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; + no_pty_flag |= cert_no_pty_flag; + no_user_rc |= cert_no_user_rc; + /* CA-specified forced command supersedes key option */ + if (cert_forced_command != NULL) { + if (forced_command != NULL) + xfree(forced_command); + forced_command = cert_forced_command; + } + + out: + if (name != NULL) + xfree(name); + if (data_blob != NULL) + xfree(data_blob); + buffer_free(&data); + buffer_free(&c); + return ret; +} + diff --git a/auth-options.h b/auth-options.h index 14488f72d..694edc842 100644 --- a/auth-options.h +++ b/auth-options.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.h,v 1.17 2008/03/26 21:28:14 djm Exp $ */ +/* $OpenBSD: auth-options.h,v 1.18 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -30,8 +30,10 @@ extern int no_user_rc; extern char *forced_command; extern struct envstring *custom_environment; extern int forced_tun_device; +extern int key_is_cert_authority; int auth_parse_options(struct passwd *, char *, char *, u_long); void auth_clear_options(void); +int auth_cert_constraints(Buffer *, struct passwd *); #endif diff --git a/auth.h b/auth.h index bebfb672d..117485ca9 100644 --- a/auth.h +++ b/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.63 2009/08/15 18:56:34 fgsch Exp $ */ +/* $OpenBSD: auth.h,v 1.64 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -178,7 +178,8 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *, /* hostkey handling */ Key *get_hostkey_by_index(int); -Key *get_hostkey_by_type(int); +Key *get_hostkey_public_by_type(int); +Key *get_hostkey_private_by_type(int); int get_hostkey_index(Key *); int ssh1_session_key(BIGNUM *); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 2886f1275..66ca5266b 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.19 2008/07/03 21:46:58 otto Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.20 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include "xmalloc.h" @@ -178,6 +180,7 @@ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; + const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; @@ -196,11 +199,13 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) } found_key = 0; - found = key_new(key->type); + found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; + auth_clear_options(); + /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; @@ -227,8 +232,32 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) continue; } } - if (key_equal(found, key) && - auth_parse_options(pw, key_options, file, linenum) == 1) { + if (auth_parse_options(pw, key_options, file, linenum) != 1) + continue; + if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) { + if (!key_is_cert_authority) + continue; + if (!key_equal(found, key->cert->signature_key)) + continue; + debug("matching CA found: file %s, line %lu", + file, linenum); + fp = key_fingerprint(found, SSH_FP_MD5, + SSH_FP_HEX); + verbose("Found matching %s CA: %s", + key_type(found), fp); + xfree(fp); + if (key_cert_check_authority(key, 0, 0, pw->pw_name, + &reason) != 0) { + error("%s", reason); + auth_debug_add("%s", reason); + continue; + } + if (auth_cert_constraints(&key->cert->constraints, + pw) != 0) + continue; + found_key = 1; + break; + } else if (!key_is_cert_authority && key_equal(found, key)) { found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); diff --git a/authfd.c b/authfd.c index 78a53c7a6..28a8cf2d7 100644 --- a/authfd.c +++ b/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.81 2009/08/27 17:44:52 djm Exp $ */ +/* $OpenBSD: authfd.c,v 1.82 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -483,6 +483,16 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->rsa->p); buffer_put_bignum2(b, key->rsa->q); break; + case KEY_RSA_CERT: + if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) + fatal("%s: no cert/certblob", __func__); + buffer_put_string(b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + buffer_put_bignum2(b, key->rsa->d); + buffer_put_bignum2(b, key->rsa->iqmp); + buffer_put_bignum2(b, key->rsa->p); + buffer_put_bignum2(b, key->rsa->q); + break; case KEY_DSA: buffer_put_bignum2(b, key->dsa->p); buffer_put_bignum2(b, key->dsa->q); @@ -490,6 +500,13 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->dsa->pub_key); buffer_put_bignum2(b, key->dsa->priv_key); break; + case KEY_DSA_CERT: + if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) + fatal("%s: no cert/certblob", __func__); + buffer_put_string(b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + buffer_put_bignum2(b, key->dsa->priv_key); + break; } buffer_put_cstring(b, comment); } @@ -517,7 +534,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, ssh_encode_identity_rsa1(&msg, key->rsa, comment); break; case KEY_RSA: + case KEY_RSA_CERT: case KEY_DSA: + case KEY_DSA_CERT: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; @@ -565,7 +584,8 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key) buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); - } else if (key->type == KEY_DSA || key->type == KEY_RSA) { + } else if (key_type_plain(key->type) == KEY_DSA || + key_type_plain(key->type) == KEY_RSA) { key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); diff --git a/dns.c b/dns.c index a7da03fa3..2e7bb5aae 100644 --- a/dns.c +++ b/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.25 2008/06/12 00:03:49 dtucker Exp $ */ +/* $OpenBSD: dns.c,v 1.26 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -75,7 +75,7 @@ dns_result_totext(unsigned int res) */ static int dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, - u_char **digest, u_int *digest_len, const Key *key) + u_char **digest, u_int *digest_len, Key *key) { int success = 0; @@ -172,7 +172,7 @@ is_numeric_hostname(const char *hostname) */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, - const Key *hostkey, int *flags) + Key *hostkey, int *flags) { u_int counter; int result; @@ -271,7 +271,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, * Export the fingerprint of a key as a DNS resource record */ int -export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic) +export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) { u_int8_t rdata_pubkey_algorithm = 0; u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; diff --git a/dns.h b/dns.h index b2633a1fe..90cfd7b92 100644 --- a/dns.h +++ b/dns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -46,7 +46,7 @@ enum sshfp_hashes { #define DNS_VERIFY_MATCH 0x00000002 #define DNS_VERIFY_SECURE 0x00000004 -int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *); -int export_dns_rr(const char *, const Key *, FILE *, int); +int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *); +int export_dns_rr(const char *, Key *, FILE *, int); #endif /* DNS_H */ diff --git a/hostfile.c b/hostfile.c index cd28bf446..fc7f84c79 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.46 2009/10/11 23:03:15 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.47 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -199,7 +199,7 @@ check_host_in_hostfile_by_key_or_type(const char *filename, { FILE *f; char line[8192]; - int linenum = 0; + int linenum = 0, want_cert = key_is_cert(key); u_int kbits; char *cp, *cp2, *hashed_host; HostStatus end_return; @@ -229,6 +229,23 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!*cp || *cp == '#' || *cp == '\n') continue; + /* + * Ignore CA keys when looking for raw keys. + * Ignore raw keys when looking for CA keys. + */ + if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && + (cp[sizeof(CA_MARKER) - 1] == ' ' || + cp[sizeof(CA_MARKER) - 1] == '\t')) { + if (want_cert) { + /* Skip the marker and following whitespace */ + cp += sizeof(CA_MARKER); + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + } else + continue; + } else if (want_cert) + continue; + /* Find the end of the host name portion. */ for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) ; @@ -273,8 +290,14 @@ check_host_in_hostfile_by_key_or_type(const char *filename, continue; /* Check if the current key is the same as the given key. */ - if (key_equal(key, found)) { - /* Ok, they match. */ + if (want_cert && key_equal(key->cert->signature_key, found)) { + /* Found CA cert for key */ + debug3("check_host_in_hostfile: CA match line %d", + linenum); + fclose(f); + return HOST_OK; + } else if (!want_cert && key_equal(key, found)) { + /* Found identical key */ debug3("check_host_in_hostfile: match line %d", linenum); fclose(f); return HOST_OK; diff --git a/hostfile.h b/hostfile.h index d1983b3e0..ebac1e4f1 100644 --- a/hostfile.h +++ b/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */ +/* $OpenBSD: hostfile.h,v 1.17 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -28,6 +28,8 @@ int lookup_key_in_hostfile_by_type(const char *, const char *, #define HASH_MAGIC "|1|" #define HASH_DELIM '|' +#define CA_MARKER "@cert-authority" + char *host_hash(const char *, const char *, u_int); #endif diff --git a/kex.h b/kex.h index 1fa13799d..62fa2ea50 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.48 2009/10/24 11:13:54 andreas Exp $ */ +/* $OpenBSD: kex.h,v 1.49 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -126,7 +126,8 @@ struct Kex { char *client_version_string; char *server_version_string; int (*verify_host_key)(Key *); - Key *(*load_host_key)(int); + Key *(*load_host_public_key)(int); + Key *(*load_host_private_key)(int); int (*host_key_index)(Key *); void (*kex[KEX_MAX])(Kex *); }; diff --git a/kexdhs.c b/kexdhs.c index a6719f672..e722877d5 100644 --- a/kexdhs.c +++ b/kexdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhs.c,v 1.10 2009/06/21 07:37:15 dtucker Exp $ */ +/* $OpenBSD: kexdhs.c,v 1.11 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -50,7 +50,7 @@ kexdh_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; DH *dh; - Key *server_host_key; + Key *server_host_public, *server_host_private; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, hashlen, slen; int kout; @@ -71,11 +71,16 @@ kexdh_server(Kex *kex) debug("expecting SSH2_MSG_KEXDH_INIT"); packet_read_expect(SSH2_MSG_KEXDH_INIT); - if (kex->load_host_key == NULL) + if (kex->load_host_public_key == NULL || + kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) + server_host_public = kex->load_host_public_key(kex->hostkey_type); + if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); + server_host_private = kex->load_host_private_key(kex->hostkey_type); + if (server_host_private == NULL) + fatal("Missing private key for hostkey type %d", + kex->hostkey_type); /* key, cert */ if ((dh_client_pub = BN_new()) == NULL) @@ -113,7 +118,7 @@ kexdh_server(Kex *kex) memset(kbuf, 0, klen); xfree(kbuf); - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); /* calc H */ kex_dh_hash( @@ -137,7 +142,7 @@ kexdh_server(Kex *kex) } /* sign H */ - if (PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, + if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, hashlen)) < 0) fatal("kexdh_server: key_sign failed"); diff --git a/kexgexs.c b/kexgexs.c index 8515568b3..f4156af96 100644 --- a/kexgexs.c +++ b/kexgexs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexs.c,v 1.12 2009/06/21 07:37:15 dtucker Exp $ */ +/* $OpenBSD: kexgexs.c,v 1.13 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -52,18 +52,24 @@ void kexgex_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - Key *server_host_key; + Key *server_host_public, *server_host_private; DH *dh; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, slen, hashlen; int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; int type, kout; - if (kex->load_host_key == NULL) + if (kex->load_host_public_key == NULL || + kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) + server_host_public = kex->load_host_public_key(kex->hostkey_type); + if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); + server_host_private = kex->load_host_private_key(kex->hostkey_type); + if (server_host_private == NULL) + fatal("Missing private key for hostkey type %d", + kex->hostkey_type); + type = packet_read(); switch (type) { @@ -149,7 +155,7 @@ kexgex_server(Kex *kex) memset(kbuf, 0, klen); xfree(kbuf); - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) omin = min = omax = max = -1; @@ -179,7 +185,7 @@ kexgex_server(Kex *kex) } /* sign H */ - if (PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, + if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, hashlen)) < 0) fatal("kexgex_server: key_sign failed"); diff --git a/key.c b/key.c index 5aea416b3..387190b53 100644 --- a/key.c +++ b/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.82 2010/01/13 01:10:56 dtucker Exp $ */ +/* $OpenBSD: key.c,v 1.83 2010/02/26 20:29:54 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -52,6 +52,21 @@ #include "uuencode.h" #include "buffer.h" #include "log.h" +#include "ssh2.h" + +static struct KeyCert * +cert_new(void) +{ + struct KeyCert *cert; + + cert = xcalloc(1, sizeof(*cert)); + buffer_init(&cert->certblob); + buffer_init(&cert->constraints); + cert->key_id = NULL; + cert->principals = NULL; + cert->signature_key = NULL; + return cert; +} Key * key_new(int type) @@ -63,9 +78,11 @@ key_new(int type) k->type = type; k->dsa = NULL; k->rsa = NULL; + k->cert = NULL; switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if ((rsa = RSA_new()) == NULL) fatal("key_new: RSA_new failed"); if ((rsa->n = BN_new()) == NULL) @@ -75,6 +92,7 @@ key_new(int type) k->rsa = rsa; break; case KEY_DSA: + case KEY_DSA_CERT: if ((dsa = DSA_new()) == NULL) fatal("key_new: DSA_new failed"); if ((dsa->p = BN_new()) == NULL) @@ -93,16 +111,20 @@ key_new(int type) fatal("key_new: bad key type %d", k->type); break; } + + if (key_is_cert(k)) + k->cert = cert_new(); + return k; } -Key * -key_new_private(int type) +void +key_add_private(Key *k) { - Key *k = key_new(type); switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if ((k->rsa->d = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); if ((k->rsa->iqmp = BN_new()) == NULL) @@ -117,6 +139,7 @@ key_new_private(int type) fatal("key_new_private: BN_new failed"); break; case KEY_DSA: + case KEY_DSA_CERT: if ((k->dsa->priv_key = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); break; @@ -125,9 +148,34 @@ key_new_private(int type) default: break; } +} + +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + + key_add_private(k); return k; } +static void +cert_free(struct KeyCert *cert) +{ + u_int i; + + buffer_free(&cert->certblob); + buffer_free(&cert->constraints); + if (cert->key_id != NULL) + xfree(cert->key_id); + for (i = 0; i < cert->nprincipals; i++) + xfree(cert->principals[i]); + if (cert->principals != NULL) + xfree(cert->principals); + if (cert->signature_key != NULL) + key_free(cert->signature_key); +} + void key_free(Key *k) { @@ -136,11 +184,13 @@ key_free(Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if (k->rsa != NULL) RSA_free(k->rsa); k->rsa = NULL; break; case KEY_DSA: + case KEY_DSA_CERT: if (k->dsa != NULL) DSA_free(k->dsa); k->dsa = NULL; @@ -151,20 +201,49 @@ key_free(Key *k) fatal("key_free: bad key type %d", k->type); break; } + if (key_is_cert(k)) { + if (k->cert != NULL) + cert_free(k->cert); + k->cert = NULL; + } + xfree(k); } +static int +cert_compare(struct KeyCert *a, struct KeyCert *b) +{ + if (a == NULL && b == NULL) + return 1; + if (a == NULL || b == NULL) + return 0; + if (buffer_len(&a->certblob) != buffer_len(&b->certblob)) + return 0; + if (memcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob), + buffer_len(&a->certblob)) != 0) + return 0; + return 1; +} + +/* + * Compare public portions of key only, allowing comparisons between + * certificates and plain keys too. + */ int -key_equal(const Key *a, const Key *b) +key_equal_public(const Key *a, const Key *b) { - if (a == NULL || b == NULL || a->type != b->type) + if (a == NULL || b == NULL || + key_type_plain(a->type) != key_type_plain(b->type)) return 0; + switch (a->type) { case KEY_RSA1: + case KEY_RSA_CERT: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; + case KEY_DSA_CERT: case KEY_DSA: return a->dsa != NULL && b->dsa != NULL && BN_cmp(a->dsa->p, b->dsa->p) == 0 && @@ -177,16 +256,27 @@ key_equal(const Key *a, const Key *b) /* NOTREACHED */ } +int +key_equal(const Key *a, const Key *b) +{ + if (a == NULL || b == NULL || a->type != b->type) + return 0; + if (key_is_cert(a)) { + if (!cert_compare(a->cert, b->cert)) + return 0; + } + return key_equal_public(a, b); +} + u_char* -key_fingerprint_raw(const Key *k, enum fp_type dgst_type, - u_int *dgst_raw_length) +key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) { const EVP_MD *md = NULL; EVP_MD_CTX ctx; u_char *blob = NULL; u_char *retval = NULL; u_int len = 0; - int nlen, elen; + int nlen, elen, otype; *dgst_raw_length = 0; @@ -214,6 +304,14 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type, case KEY_RSA: key_to_blob(k, &blob, &len); break; + case KEY_DSA_CERT: + case KEY_RSA_CERT: + /* We want a fingerprint of the _key_ not of the cert */ + otype = k->type; + k->type = key_type_plain(k->type); + key_to_blob(k, &blob, &len); + k->type = otype; + break; case KEY_UNSPEC: return retval; default: @@ -408,7 +506,7 @@ key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k) } char * -key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) { char *retval = NULL; u_char *dgst_raw; @@ -533,6 +631,8 @@ key_read(Key *ret, char **cpp) case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: + case KEY_DSA_CERT: + case KEY_RSA_CERT: space = strchr(cp, ' '); if (space == NULL) { debug3("key_read: missing whitespace"); @@ -577,25 +677,36 @@ key_read(Key *ret, char **cpp) return -1; } /*XXXX*/ - if (ret->type == KEY_RSA) { + if (key_is_cert(ret)) { + if (!key_is_cert(k)) { + error("key_read: loaded key is not a cert"); + key_free(k); + return -1; + } + if (ret->cert != NULL) + cert_free(ret->cert); + ret->cert = k->cert; + k->cert = NULL; + } + if (key_type_plain(ret->type) == KEY_RSA) { if (ret->rsa != NULL) RSA_free(ret->rsa); ret->rsa = k->rsa; k->rsa = NULL; - success = 1; #ifdef DEBUG_PK RSA_print_fp(stderr, ret->rsa, 8); #endif - } else { + } + if (key_type_plain(ret->type) == KEY_DSA) { if (ret->dsa != NULL) DSA_free(ret->dsa); ret->dsa = k->dsa; k->dsa = NULL; - success = 1; #ifdef DEBUG_PK DSA_print_fp(stderr, ret->dsa, 8); #endif } + success = 1; /*XXXX*/ key_free(k); if (success != 1) @@ -622,28 +733,53 @@ key_write(const Key *key, FILE *f) u_char *blob; char *uu; - if (key->type == KEY_RSA1 && key->rsa != NULL) { + if (key_is_cert(key)) { + if (key->cert == NULL) { + error("%s: no cert data", __func__); + return 0; + } + if (buffer_len(&key->cert->certblob) == 0) { + error("%s: no signed certificate blob", __func__); + return 0; + } + } + + switch (key->type) { + case KEY_RSA1: + if (key->rsa == NULL) + return 0; /* size of modulus 'n' */ bits = BN_num_bits(key->rsa->n); fprintf(f, "%u", bits); if (write_bignum(f, key->rsa->e) && - write_bignum(f, key->rsa->n)) { - success = 1; - } else { - error("key_write: failed for RSA key"); - } - } else if ((key->type == KEY_DSA && key->dsa != NULL) || - (key->type == KEY_RSA && key->rsa != NULL)) { - key_to_blob(key, &blob, &len); - uu = xmalloc(2*len); - n = uuencode(blob, len, uu, 2*len); - if (n > 0) { - fprintf(f, "%s %s", key_ssh_name(key), uu); - success = 1; - } - xfree(blob); - xfree(uu); + write_bignum(f, key->rsa->n)) + return 1; + error("key_write: failed for RSA key"); + return 0; + case KEY_DSA: + case KEY_DSA_CERT: + if (key->dsa == NULL) + return 0; + break; + case KEY_RSA: + case KEY_RSA_CERT: + if (key->rsa == NULL) + return 0; + break; + default: + return 0; } + + key_to_blob(key, &blob, &len); + uu = xmalloc(2*len); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", key_ssh_name(key), uu); + success = 1; + } + xfree(blob); + xfree(uu); + return success; } @@ -657,6 +793,10 @@ key_type(const Key *k) return "RSA"; case KEY_DSA: return "DSA"; + case KEY_RSA_CERT: + return "RSA-CERT"; + case KEY_DSA_CERT: + return "DSA-CERT"; } return "unknown"; } @@ -669,6 +809,10 @@ key_ssh_name(const Key *k) return "ssh-rsa"; case KEY_DSA: return "ssh-dss"; + case KEY_RSA_CERT: + return "ssh-rsa-cert-v00@openssh.com"; + case KEY_DSA_CERT: + return "ssh-dss-cert-v00@openssh.com"; } return "ssh-unknown"; } @@ -679,8 +823,10 @@ key_size(const Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: return BN_num_bits(k->rsa->n); case KEY_DSA: + case KEY_DSA_CERT: return BN_num_bits(k->dsa->p); } return 0; @@ -723,6 +869,9 @@ key_generate(int type, u_int bits) case KEY_RSA1: k->rsa = rsa_generate_private_key(bits); break; + case KEY_RSA_CERT: + case KEY_DSA_CERT: + fatal("key_generate: cert keys cannot be generated directly"); default: fatal("key_generate: unknown type %d", type); } @@ -730,12 +879,55 @@ key_generate(int type, u_int bits) return k; } +void +key_cert_copy(const Key *from_key, struct Key *to_key) +{ + u_int i; + const struct KeyCert *from; + struct KeyCert *to; + + if (to_key->cert != NULL) { + cert_free(to_key->cert); + to_key->cert = NULL; + } + + if ((from = from_key->cert) == NULL) + return; + + to = to_key->cert = cert_new(); + + buffer_append(&to->certblob, buffer_ptr(&from->certblob), + buffer_len(&from->certblob)); + + buffer_append(&to->constraints, buffer_ptr(&from->constraints), + buffer_len(&from->constraints)); + + to->type = from->type; + to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id); + to->valid_after = from->valid_after; + to->valid_before = from->valid_before; + to->signature_key = from->signature_key == NULL ? + NULL : key_from_private(from->signature_key); + + to->nprincipals = from->nprincipals; + if (to->nprincipals > CERT_MAX_PRINCIPALS) + fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)", + __func__, to->nprincipals, CERT_MAX_PRINCIPALS); + if (to->nprincipals > 0) { + to->principals = xcalloc(from->nprincipals, + sizeof(*to->principals)); + for (i = 0; i < to->nprincipals; i++) + to->principals[i] = xstrdup(from->principals[i]); + } +} + Key * key_from_private(const Key *k) { Key *n = NULL; switch (k->type) { case KEY_DSA: + case KEY_DSA_CERT: n = key_new(k->type); if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || (BN_copy(n->dsa->q, k->dsa->q) == NULL) || @@ -745,6 +937,7 @@ key_from_private(const Key *k) break; case KEY_RSA: case KEY_RSA1: + case KEY_RSA_CERT: n = key_new(k->type); if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || (BN_copy(n->rsa->e, k->rsa->e) == NULL)) @@ -754,6 +947,8 @@ key_from_private(const Key *k) fatal("key_from_private: unknown type %d", k->type); break; } + if (key_is_cert(k)) + key_cert_copy(k, n); return n; } @@ -770,6 +965,10 @@ key_type_from_name(char *name) return KEY_RSA; } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; + } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) { + return KEY_RSA_CERT; + } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { + return KEY_DSA_CERT; } debug2("key_type_from_name: unknown key type '%s'", name); return KEY_UNSPEC; @@ -797,6 +996,117 @@ key_names_valid2(const char *names) return 1; } +static int +cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) +{ + u_char *principals, *constraints, *sig_key, *sig; + u_int signed_len, plen, clen, sklen, slen; + Buffer tmp; + char *principal; + int ret = -1; + + buffer_init(&tmp); + + /* Copy the entire key blob for verification and later serialisation */ + buffer_append(&key->cert->certblob, blob, blen); + + principals = constraints = sig_key = sig = NULL; + if (buffer_get_int_ret(&key->cert->type, b) != 0 || + (key->cert->key_id = buffer_get_string_ret(b, NULL)) == NULL || + (principals = buffer_get_string_ret(b, &plen)) == NULL || + buffer_get_int64_ret(&key->cert->valid_after, b) != 0 || + buffer_get_int64_ret(&key->cert->valid_before, b) != 0 || + (constraints = buffer_get_string_ret(b, &clen)) == NULL || + /* skip nonce */ buffer_get_string_ptr_ret(b, NULL) == NULL || + /* skip reserved */ buffer_get_string_ptr_ret(b, NULL) == NULL || + (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) { + error("%s: parse error", __func__); + goto out; + } + + /* Signature is left in the buffer so we can calculate this length */ + signed_len = buffer_len(&key->cert->certblob) - buffer_len(b); + + if ((sig = buffer_get_string_ret(b, &slen)) == NULL) { + error("%s: parse error", __func__); + goto out; + } + + if (key->cert->type != SSH2_CERT_TYPE_USER && + key->cert->type != SSH2_CERT_TYPE_HOST) { + error("Unknown certificate type %u", key->cert->type); + goto out; + } + + buffer_append(&tmp, principals, plen); + while (buffer_len(&tmp) > 0) { + if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) { + error("Too many principals"); + goto out; + } + if ((principal = buffer_get_string_ret(&tmp, NULL)) == NULL) { + error("Principals data invalid"); + goto out; + } + key->cert->principals = xrealloc(key->cert->principals, + key->cert->nprincipals + 1, sizeof(*key->cert->principals)); + key->cert->principals[key->cert->nprincipals++] = principal; + } + + buffer_clear(&tmp); + + buffer_append(&key->cert->constraints, constraints, clen); + buffer_append(&tmp, constraints, clen); + /* validate structure */ + while (buffer_len(&tmp) != 0) { + if (buffer_get_string_ptr(&tmp, NULL) == NULL || + buffer_get_string_ptr(&tmp, NULL) == NULL) { + error("Constraints data invalid"); + goto out; + } + } + buffer_clear(&tmp); + + if ((key->cert->signature_key = key_from_blob(sig_key, + sklen)) == NULL) { + error("Signature key invalid"); + goto out; + } + if (key->cert->signature_key->type != KEY_RSA && + key->cert->signature_key->type != KEY_DSA) { + error("Invalid signature key type %s (%d)", + key_type(key->cert->signature_key), + key->cert->signature_key->type); + goto out; + } + + switch (key_verify(key->cert->signature_key, sig, slen, + buffer_ptr(&key->cert->certblob), signed_len)) { + case 1: + break; /* Good signature */ + case 0: + error("Invalid signature on certificate"); + goto out; + case -1: + error("Certificate signature verification failed"); + goto out; + } + + ret = 0; + + out: + buffer_free(&tmp); + if (principals != NULL) + xfree(principals); + if (constraints != NULL) + xfree(constraints); + if (sig_key != NULL) + xfree(sig_key); + if (sig != NULL) + xfree(sig); + return ret; +} + Key * key_from_blob(const u_char *blob, u_int blen) { @@ -819,10 +1129,12 @@ key_from_blob(const u_char *blob, u_int blen) switch (type) { case KEY_RSA: + case KEY_RSA_CERT: key = key_new(type); if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { error("key_from_blob: can't read rsa key"); + badkey: key_free(key); key = NULL; goto out; @@ -832,15 +1144,14 @@ key_from_blob(const u_char *blob, u_int blen) #endif break; case KEY_DSA: + case KEY_DSA_CERT: key = key_new(type); if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 || buffer_get_bignum2_ret(&b, key->dsa->q) == -1 || buffer_get_bignum2_ret(&b, key->dsa->g) == -1 || buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) { error("key_from_blob: can't read dsa key"); - key_free(key); - key = NULL; - goto out; + goto badkey; } #ifdef DEBUG_PK DSA_print_fp(stderr, key->dsa, 8); @@ -853,6 +1164,10 @@ key_from_blob(const u_char *blob, u_int blen) error("key_from_blob: cannot handle type %s", ktype); goto out; } + if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) { + error("key_from_blob: can't parse cert data"); + goto badkey; + } rlen = buffer_len(&b); if (key != NULL && rlen != 0) error("key_from_blob: remaining bytes in key blob %d", rlen); @@ -875,6 +1190,12 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp) } buffer_init(&b); switch (key->type) { + case KEY_DSA_CERT: + case KEY_RSA_CERT: + /* Use the existing blob */ + buffer_append(&b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + break; case KEY_DSA: buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_bignum2(&b, key->dsa->p); @@ -911,8 +1232,10 @@ key_sign( const u_char *data, u_int datalen) { switch (key->type) { + case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_sign(key, sigp, lenp, data, datalen); + case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); default: @@ -935,8 +1258,10 @@ key_verify( return -1; switch (key->type) { + case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_verify(key, signature, signaturelen, data, datalen); + case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); default: @@ -958,6 +1283,9 @@ key_demote(const Key *k) pk->rsa = NULL; switch (k->type) { + case KEY_RSA_CERT: + key_cert_copy(k, pk); + /* FALLTHROUGH */ case KEY_RSA1: case KEY_RSA: if ((pk->rsa = RSA_new()) == NULL) @@ -967,6 +1295,9 @@ key_demote(const Key *k) if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) fatal("key_demote: BN_dup failed"); break; + case KEY_DSA_CERT: + key_cert_copy(k, pk); + /* FALLTHROUGH */ case KEY_DSA: if ((pk->dsa = DSA_new()) == NULL) fatal("key_demote: DSA_new failed"); @@ -986,3 +1317,199 @@ key_demote(const Key *k) return (pk); } + +int +key_is_cert(const Key *k) +{ + return k != NULL && + (k->type == KEY_RSA_CERT || k->type == KEY_DSA_CERT); +} + +/* Return the cert-less equivalent to a certified key type */ +int +key_type_plain(int type) +{ + switch (type) { + case KEY_RSA_CERT: + return KEY_RSA; + case KEY_DSA_CERT: + return KEY_DSA; + default: + return type; + } +} + +/* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */ +int +key_to_certified(Key *k) +{ + switch (k->type) { + case KEY_RSA: + k->cert = cert_new(); + k->type = KEY_RSA_CERT; + return 0; + case KEY_DSA: + k->cert = cert_new(); + k->type = KEY_DSA_CERT; + return 0; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + return -1; + } +} + +/* Convert a KEY_RSA_CERT or KEY_DSA_CERT to their raw key equivalent */ +int +key_drop_cert(Key *k) +{ + switch (k->type) { + case KEY_RSA_CERT: + cert_free(k->cert); + k->type = KEY_RSA; + return 0; + case KEY_DSA_CERT: + cert_free(k->cert); + k->type = KEY_DSA; + return 0; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + return -1; + } +} + +/* Sign a KEY_RSA_CERT or KEY_DSA_CERT, (re-)generating the signed certblob */ +int +key_certify(Key *k, Key *ca) +{ + Buffer principals; + u_char *ca_blob, *sig_blob, nonce[32]; + u_int i, ca_len, sig_len; + + if (k->cert == NULL) { + error("%s: key lacks cert info", __func__); + return -1; + } + + if (!key_is_cert(k)) { + error("%s: certificate has unknown type %d", __func__, + k->cert->type); + return -1; + } + + if (ca->type != KEY_RSA && ca->type != KEY_DSA) { + error("%s: CA key has unsupported type %s", __func__, + key_type(ca)); + return -1; + } + + key_to_blob(ca, &ca_blob, &ca_len); + + buffer_clear(&k->cert->certblob); + buffer_put_cstring(&k->cert->certblob, key_ssh_name(k)); + + switch (k->type) { + case KEY_DSA_CERT: + buffer_put_bignum2(&k->cert->certblob, k->dsa->p); + buffer_put_bignum2(&k->cert->certblob, k->dsa->q); + buffer_put_bignum2(&k->cert->certblob, k->dsa->g); + buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); + break; + case KEY_RSA_CERT: + buffer_put_bignum2(&k->cert->certblob, k->rsa->e); + buffer_put_bignum2(&k->cert->certblob, k->rsa->n); + break; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + buffer_clear(&k->cert->certblob); + xfree(ca_blob); + return -1; + } + + buffer_put_int(&k->cert->certblob, k->cert->type); + buffer_put_cstring(&k->cert->certblob, k->cert->key_id); + + buffer_init(&principals); + for (i = 0; i < k->cert->nprincipals; i++) + buffer_put_cstring(&principals, k->cert->principals[i]); + buffer_put_string(&k->cert->certblob, buffer_ptr(&principals), + buffer_len(&principals)); + buffer_free(&principals); + + buffer_put_int64(&k->cert->certblob, k->cert->valid_after); + buffer_put_int64(&k->cert->certblob, k->cert->valid_before); + buffer_put_string(&k->cert->certblob, + buffer_ptr(&k->cert->constraints), + buffer_len(&k->cert->constraints)); + + arc4random_buf(&nonce, sizeof(nonce)); + buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); + buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */ + buffer_put_string(&k->cert->certblob, ca_blob, ca_len); + xfree(ca_blob); + + /* Sign the whole mess */ + if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob), + buffer_len(&k->cert->certblob)) != 0) { + error("%s: signature operation failed", __func__); + buffer_clear(&k->cert->certblob); + return -1; + } + /* Append signature and we are done */ + buffer_put_string(&k->cert->certblob, sig_blob, sig_len); + xfree(sig_blob); + + return 0; +} + +int +key_cert_check_authority(const Key *k, int want_host, int require_principal, + const char *name, const char **reason) +{ + u_int i, principal_matches; + time_t now = time(NULL); + + if (want_host) { + if (k->cert->type != SSH2_CERT_TYPE_HOST) { + *reason = "Certificate invalid: not a host certificate"; + return -1; + } + } else { + if (k->cert->type != SSH2_CERT_TYPE_USER) { + *reason = "Certificate invalid: not a user certificate"; + return -1; + } + } + if (now < 0) { + error("%s: system clock lies before epoch", __func__); + *reason = "Certificate invalid: not yet valid"; + return -1; + } + if ((u_int64_t)now < k->cert->valid_after) { + *reason = "Certificate invalid: not yet valid"; + return -1; + } + if ((u_int64_t)now >= k->cert->valid_before) { + *reason = "Certificate invalid: expired"; + return -1; + } + if (k->cert->nprincipals == 0) { + if (require_principal) { + *reason = "Certificate lacks principal list"; + return -1; + } + } else { + principal_matches = 0; + for (i = 0; i < k->cert->nprincipals; i++) { + if (strcmp(name, k->cert->principals[i]) == 0) { + principal_matches = 1; + break; + } + } + if (!principal_matches) { + *reason = "Certificate invalid: name is not a listed " + "principal"; + return -1; + } + } + return 0; +} diff --git a/key.h b/key.h index 14aac79c2..6a2e049af 100644 --- a/key.h +++ b/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */ +/* $OpenBSD: key.h,v 1.28 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -26,6 +26,7 @@ #ifndef KEY_H #define KEY_H +#include "buffer.h" #include #include @@ -34,6 +35,8 @@ enum types { KEY_RSA1, KEY_RSA, KEY_DSA, + KEY_RSA_CERT, + KEY_DSA_CERT, KEY_UNSPEC }; enum fp_type { @@ -49,20 +52,35 @@ enum fp_rep { /* key is stored in external hardware */ #define KEY_FLAG_EXT 0x0001 +#define CERT_MAX_PRINCIPALS 256 +struct KeyCert { + Buffer certblob; /* Kept around for use on wire */ + u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ + char *key_id; + u_int nprincipals; + char **principals; + u_int64_t valid_after, valid_before; + Buffer constraints; + Key *signature_key; +}; + struct Key { int type; int flags; RSA *rsa; DSA *dsa; + struct KeyCert *cert; }; Key *key_new(int); +void key_add_private(Key *); Key *key_new_private(int); void key_free(Key *); Key *key_demote(const Key *); +int key_equal_public(const Key *, const Key *); int key_equal(const Key *, const Key *); -char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); -u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); +char *key_fingerprint(Key *, enum fp_type, enum fp_rep); +u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *); const char *key_type(const Key *); int key_write(const Key *, FILE *); int key_read(Key *, char **); @@ -71,6 +89,14 @@ u_int key_size(const Key *); Key *key_generate(int, u_int); Key *key_from_private(const Key *); int key_type_from_name(char *); +int key_is_cert(const Key *); +int key_type_plain(int); +int key_to_certified(Key *); +int key_drop_cert(Key *); +int key_certify(Key *, Key *); +void key_cert_copy(const Key *, struct Key *); +int key_cert_check_authority(const Key *, int, int, const char *, + const char **); Key *key_from_blob(const u_char *, u_int); int key_to_blob(const Key *, u_char **, u_int *); diff --git a/match.h b/match.h index 18f683070..3d7f70fc0 100644 --- a/match.h +++ b/match.h @@ -1,4 +1,4 @@ -/* $OpenBSD: match.h,v 1.14 2008/06/10 03:57:27 djm Exp $ */ +/* $OpenBSD: match.h,v 1.15 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -23,5 +23,5 @@ char *match_list(const char *, const char *, u_int *); /* addrmatch.c */ int addr_match_list(const char *, const char *); - +int addr_match_cidr_list(const char *, const char *); #endif diff --git a/monitor.c b/monitor.c index ace25c404..f67cb7670 100644 --- a/monitor.c +++ b/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.104 2009/06/12 20:43:22 andreas Exp $ */ +/* $OpenBSD: monitor.c,v 1.105 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -1721,7 +1721,8 @@ mm_get_kex(Buffer *m) kex->flags = buffer_get_int(m); kex->client_version_string = buffer_get_string(m, NULL); kex->server_version_string = buffer_get_string(m, NULL); - kex->load_host_key=&get_hostkey_by_type; + kex->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; return (kex); diff --git a/myproposal.h b/myproposal.h index 7bca3bcae..98f27fd15 100644 --- a/myproposal.h +++ b/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.23 2009/01/23 07:58:11 djm Exp $ */ +/* $OpenBSD: myproposal.h,v 1.24 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -40,7 +40,9 @@ "diffie-hellman-group1-sha1" #endif -#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" +#define KEX_DEFAULT_PK_ALG "ssh-rsa-cert-v00@openssh.com," \ + "ssh-dss-cert-v00@openssh.com," \ + "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "aes128-ctr,aes192-ctr,aes256-ctr," \ diff --git a/servconf.c b/servconf.c index 09296c9cf..0a6cdb655 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.202 2010/01/13 03:48:12 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.203 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -65,6 +65,7 @@ initialize_server_options(ServerOptions *options) options->listen_addrs = NULL; options->address_family = -1; options->num_host_key_files = 0; + options->num_host_cert_files = 0; options->pid_file = NULL; options->server_key_bits = -1; options->login_grace_time = -1; @@ -152,6 +153,7 @@ fill_default_server_options(ServerOptions *options) _PATH_HOST_DSA_KEY_FILE; } } + /* No certificates by default */ if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; if (options->listen_addrs == NULL) @@ -305,7 +307,7 @@ typedef enum { sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, - sZeroKnowledgePasswordAuthentication, + sZeroKnowledgePasswordAuthentication, sHostCertificate, sDeprecated, sUnsupported } ServerOpCodes; @@ -424,6 +426,7 @@ static struct { { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, + { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, { NULL, sBadOption, 0 } }; @@ -816,6 +819,16 @@ process_server_config_line(ServerOptions *options, char *line, } break; + case sHostCertificate: + intptr = &options->num_host_cert_files; + if (*intptr >= MAX_HOSTKEYS) + fatal("%s line %d: too many host certificates " + "specified (max %d).", filename, linenum, + MAX_HOSTCERTS); + charptr = &options->host_cert_files[*intptr]; + goto parse_filename; + break; + case sPidFile: charptr = &options->pid_file; goto parse_filename; @@ -1651,6 +1664,8 @@ dump_config(ServerOptions *o) /* string array arguments */ dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, o->host_key_files); + dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files, + o->host_cert_files); dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups); diff --git a/servconf.h b/servconf.h index c9b8619cd..c5c9c6ecd 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.90 2010/01/13 03:48:13 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.91 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -24,6 +24,7 @@ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ #define MAX_HOSTKEYS 256 /* Max # hostkeys. */ +#define MAX_HOSTCERTS 256 /* Max # host certificates. */ #define MAX_ACCEPT_ENV 256 /* Max # of env vars. */ #define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */ @@ -49,6 +50,8 @@ typedef struct { int address_family; /* Address family used by the server. */ char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ int num_host_key_files; /* Number of files for host keys. */ + char *host_cert_files[MAX_HOSTCERTS]; /* Files containing host certs. */ + int num_host_cert_files; /* Number of files for host certs. */ char *pid_file; /* Where to put our pid */ int server_key_bits;/* Size of the server key. */ int login_grace_time; /* Disconnect if no auth in this time diff --git a/ssh-add.c b/ssh-add.c index 90e5be20b..a7963223a 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.92 2010/02/08 10:50:20 markus Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.93 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -138,9 +138,9 @@ delete_all(AuthenticationConnection *ac) static int add_file(AuthenticationConnection *ac, const char *filename) { - Key *private; + Key *private, *cert; char *comment = NULL; - char msg[1024]; + char msg[1024], *certpath; int fd, perms_ok, ret = -1; if ((fd = open(filename, O_RDONLY)) < 0) { @@ -199,6 +199,34 @@ add_file(AuthenticationConnection *ac, const char *filename) fprintf(stderr, "Could not add identity: %s\n", filename); } + + /* Now try to add the certificate flavour too */ + xasprintf(&certpath, "%s-cert.pub", filename); + if ((cert = key_load_public(certpath, NULL)) != NULL) { + /* Graft with private bits */ + if (key_to_certified(private) != 0) + fatal("%s: key_to_certified failed", __func__); + key_cert_copy(cert, private); + key_free(cert); + + if (ssh_add_identity_constrained(ac, private, comment, + lifetime, confirm)) { + fprintf(stderr, "Certificate added: %s (%s)\n", + certpath, private->cert->key_id); + if (lifetime != 0) + fprintf(stderr, "Lifetime set to %d seconds\n", + lifetime); + if (confirm != 0) + fprintf(stderr, "The user has to confirm each " + "use of the key\n"); + } else { + error("Certificate %s (%s) add failed", certpath, + private->cert->key_id); + } + } else + fprintf(stderr, "Unable to load certificate %s", certpath); + + xfree(certpath); xfree(comment); key_free(private); diff --git a/ssh-agent.c b/ssh-agent.c index 46a744f4e..b5c565271 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.164 2010/02/09 00:50:36 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -468,6 +468,8 @@ process_add_identity(SocketEntry *e, int version) int type, success = 0, death = 0, confirm = 0; char *type_name, *comment; Key *k = NULL; + u_char *cert; + u_int len; switch (version) { case 1: @@ -498,6 +500,14 @@ process_add_identity(SocketEntry *e, int version) buffer_get_bignum2(&e->request, k->dsa->pub_key); buffer_get_bignum2(&e->request, k->dsa->priv_key); break; + case KEY_DSA_CERT: + cert = buffer_get_string(&e->request, &len); + if ((k = key_from_blob(cert, len)) == NULL) + fatal("Certificate parse failed"); + xfree(cert); + key_add_private(k); + buffer_get_bignum2(&e->request, k->dsa->priv_key); + break; case KEY_RSA: k = key_new_private(type); buffer_get_bignum2(&e->request, k->rsa->n); @@ -510,6 +520,17 @@ process_add_identity(SocketEntry *e, int version) /* Generate additional parameters */ rsa_generate_additional_parameters(k->rsa); break; + case KEY_RSA_CERT: + cert = buffer_get_string(&e->request, &len); + if ((k = key_from_blob(cert, len)) == NULL) + fatal("Certificate parse failed"); + xfree(cert); + key_add_private(k); + buffer_get_bignum2(&e->request, k->rsa->d); + buffer_get_bignum2(&e->request, k->rsa->iqmp); + buffer_get_bignum2(&e->request, k->rsa->p); + buffer_get_bignum2(&e->request, k->rsa->q); + break; default: buffer_clear(&e->request); goto send; @@ -519,6 +540,7 @@ process_add_identity(SocketEntry *e, int version) /* enable blinding */ switch (k->type) { case KEY_RSA: + case KEY_RSA_CERT: case KEY_RSA1: if (RSA_blinding_on(k->rsa, NULL) != 1) { error("process_add_identity: RSA_blinding_on failed"); diff --git a/ssh-dss.c b/ssh-dss.c index 51a06e98f..449f493b4 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-dss.c,v 1.24 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD: ssh-dss.c,v 1.25 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -53,7 +53,9 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, u_int rlen, slen, len, dlen; Buffer b; - if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + if (key == NULL || + (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || + key->dsa == NULL) { error("ssh_dss_sign: no DSA key"); return -1; } @@ -116,7 +118,9 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, int rlen, ret; Buffer b; - if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + if (key == NULL || + (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || + key->dsa == NULL) { error("ssh_dss_verify: no DSA key"); return -1; } diff --git a/ssh-keygen.1 b/ssh-keygen.1 index f09e1a100..772caf7ad 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.83 2010/02/10 23:20:38 markus Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.84 2010/02/26 20:29:54 djm Exp $ .\" .\" -*- nroff -*- .\" @@ -37,7 +37,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: February 10 2010 $ +.Dd $Mdocdate: February 26 2010 $ .Dt SSH-KEYGEN 1 .Os .Sh NAME @@ -106,6 +106,14 @@ .Op Fl v .Op Fl a Ar num_trials .Op Fl W Ar generator +.Nm ssh-keygen +.Fl s Ar ca_key +.Fl I Ar certificate_identity +.Op Fl h +.Op Fl n Ar principals +.Op Fl O Ar constraint +.Op Fl V Ar validity_interval +.Ar .Sh DESCRIPTION .Nm generates, manages and converts authentication keys for @@ -245,6 +253,17 @@ but they do not reveal identifying information should the file's contents be disclosed. This option will not modify existing hashed hostnames and is therefore safe to use on files that mix hashed and non-hashed names. +.It Fl h +When signing a key, create a host certificate instead of a user +certificate. +Please see the +.Sx CERTIFICATES +section for details. +.It Fl I +Specify the key identity when signing a public key. +Please see the +.Sx CERTIFICATES +section for details. .It Fl i This option will read an unencrypted private (or public) key file in SSH2-compatible format and print an OpenSSH compatible private @@ -268,6 +287,67 @@ Specify the amount of memory to use (in megabytes) when generating candidate moduli for DH-GEX. .It Fl N Ar new_passphrase Provides the new passphrase. +.It Fl n Ar principals +Specify one or more principals (user or host names) to be included in +a certificate when signing a key. +Multiple principals may be specified, separated by commas. +Please see the +.Sx CERTIFICATES +section for details. +.It Fl O Ar constraint +Specify a certificate constraint when signing a key. +This option may be specified multiple times. +Please see the +.Sx CERTIFICATES +section for details. +The constraints that are valid for user certificates are: +.Bl -tag -width Ds +.It Ic no-x11-forwarding +Disable X11 forwarding. (permitted by default) +.It Ic no-agent-forwarding +Disable +.Xr ssh-agent 1 +forwarding. (permitted by default) +.It Ic no-port-forwarding +Disable port forwarding. (permitted by default) +.It Ic no-pty +Disable PTY allocation. (permitted by default) +.It Ic no-user-rc +Disable execution of +.Pa ~/.ssh/rc +by +.Xr sshd 8 . +(permitted by default) +.It Ic clear +Clear all enabled permissions. +This is useful for clearing the default set of permissions so permissions may +be added individually. +.It Ic permit-x11-forwarding +Allows X11 forwarding. +.It Ic permit-port-forwarding +Allows port forwarding. +.It Ic permit-pty +Allows PTY allocation. +.It Ic permit-user-rc +Allows execution of +.Pa ~/.ssh/rc +by +.Xr sshd 8 . +.It Ic force-command=command +Forces the execution of +.Ar command +instead of any shell or command specified by the user when +the certificate is used for authentication. +.It Ic source-address=address_list +Restrict the source addresses from which the certificate is considered valid +from. +The +.Ar address_list +is a comma-separated list of one or more address/netmask pairs in CIDR +format. +.El +.Pp +At present, no constraints are valid for host keys. .It Fl P Ar passphrase Provides the (old) passphrase. .It Fl p @@ -297,6 +377,11 @@ Print the SSHFP fingerprint resource record named for the specified public key file. .It Fl S Ar start Specify start point (in hex) when generating candidate moduli for DH-GEX. +.It Fl s Ar ca_key +Certify (sign) a public key using the specified CA key. +Please see the +.Sx CERTIFICATES +section for details. .It Fl T Ar output_file Test DH group exchange candidate primes (generated using the .Fl G @@ -310,6 +395,29 @@ for protocol version 1 and or .Dq dsa for protocol version 2. +.It Fl V Ar validity_interval +Specify a validity interval when signing a certificate. +A validity interval may consist of a single time, indicating that the +certificate is valid beginning now and expiring at that time, or may consist +of two times separated by a colon to indicate an explicit time interval. +The start time may be specified as a date in YYYYMMDD format, a time +in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting +of a minus sign followed by a relative time in the format described in the +.Sx TIME FORMATS +section of +.Xr ssh_config 5 . +The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or +a relative time starting with a plus character. +.Pp +For example: +.Dq +52w1d +(valid from now to 52 weeks and one day from now), +.Dq -4w:+4w +(valid from four weeks ago to four weeks from now), +.Dq 20100101123000:20110101123000 +(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011), +.Dq -1d:20110101 +(valid from yesterday to midnight, January 1st, 2011). .It Fl v Verbose mode. Causes @@ -380,6 +488,72 @@ Screened DH groups may be installed in .Pa /etc/moduli . It is important that this file contains moduli of a range of bit lengths and that both ends of a connection share common moduli. +.Sh CERTIFICATES +.Nm +supports signing of keys to produce certificates that may be used for +user or host authentication. +Certificates consist of a public key, some identity information, zero or +more principal (user or host) names and an optional set of constraints that +are signed by a Certification Authority (CA) key. +Clients or servers may then trust only the CA key and verify its signature +on a certificate rather than trusting many user/host keys. +Note that OpenSSH certificates are a different, and much simpler, format to +the X.509 certificates used in +.Xr ssl 8 . +.Pp +.Nm +supports two types of certificates: user and host. +User certificates authenticate users to servers, whereas host certificates +authenticate server hosts to users. To generate a user certificate: +.Pp +.Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub +.Pp +The resultant certificate will be placed in +.Pa /path/to/user_key_cert.pub . +A host certificate requires the +.Fl h +option: +.Pp +.Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub +.Pp +The host certificate will be output to +.Pa /path/to/host_key_cert.pub . +In both cases, +.Ar key_id +is a "key identifier" that is logged by the server when the certificate +is used for authentication. +.Pp +Certificates may be limited to be valid for a set of principal (user/host) +names. +By default, generated certificates are valid for all users or hosts. +To generate a certificate for a specified set of principals: +.Pp +.Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub +.Dl $ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub +.Pp +Additional limitations on the validity and use of user certificates may +be specified through certificate constraints. +A constrained certificate may disable features of the SSH session, may be +valid only when presented from particular source addresses or may +force the use of a specific command. +For a list of valid certificate constraints, see the documentation for the +.Fl O +option above. +.Pp +Finally, certificates may be defined with a validity lifetime. +The +.Fl V +option allows specification of certificate start and end times. +A certificate that is presented at a time outside this range will not be +considered valid. +By default, certificates have a maximum validity interval. +.Pp +For certificates to be used for user or host authentication, the CA +public key must be trusted by +.Xr sshd 8 +or +.Xr ssh 1 . +Please refer to those manual pages for details. .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/identity diff --git a/ssh-keygen.c b/ssh-keygen.c index b6b7a2d9f..60261c210 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.178 2010/02/09 00:50:59 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.179 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -48,6 +48,7 @@ #include "match.h" #include "hostfile.h" #include "dns.h" +#include "ssh2.h" #ifdef ENABLE_PKCS11 #include "ssh-pkcs11.h" @@ -98,6 +99,35 @@ char *identity_new_passphrase = NULL; /* This is set to the new comment if given on the command line. */ char *identity_comment = NULL; +/* Path to CA key when certifying keys. */ +char *ca_key_path = NULL; + +/* Key type when certifying */ +u_int cert_key_type = SSH2_CERT_TYPE_USER; + +/* "key ID" of signed key */ +char *cert_key_id = NULL; + +/* Comma-separated list of principal names for certifying keys */ +char *cert_principals = NULL; + +/* Validity period for certificates */ +u_int64_t cert_valid_from = 0; +u_int64_t cert_valid_to = ~0ULL; + +/* Certificate constraints */ +#define CONSTRAINT_X_FWD (1) +#define CONSTRAINT_AGENT_FWD (1<<1) +#define CONSTRAINT_PORT_FWD (1<<2) +#define CONSTRAINT_PTY (1<<3) +#define CONSTRAINT_USER_RC (1<<4) +#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ + CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ + CONSTRAINT_USER_RC) +u_int32_t constraint_flags = CONSTRAINT_DEFAULT; +char *constraint_command = NULL; +char *constraint_src_addr = NULL; + /* Dump public key file in format used by real and the original SSH 2 */ int convert_to_ssh2 = 0; int convert_from_ssh2 = 0; @@ -591,7 +621,7 @@ do_fingerprint(struct passwd *pw) } static void -print_host(FILE *f, const char *name, Key *public, int hash) +printhost(FILE *f, const char *name, Key *public, int ca, int hash) { if (print_fingerprint) { enum fp_rep rep; @@ -611,7 +641,7 @@ print_host(FILE *f, const char *name, Key *public, int hash) } else { if (hash && (name = host_hash(name, NULL, 0)) == NULL) fatal("hash_host failed"); - fprintf(f, "%s ", name); + fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name); if (!key_write(public, f)) fatal("key_write failed"); fprintf(f, "\n"); @@ -622,10 +652,11 @@ static void do_known_hosts(struct passwd *pw, const char *name) { FILE *in, *out = stdout; - Key *public; + Key *pub; char *cp, *cp2, *kp, *kp2; char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; + int ca; if (!have_identity) { cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); @@ -681,9 +712,19 @@ do_known_hosts(struct passwd *pw, const char *name) fprintf(out, "%s\n", cp); continue; } + /* Check whether this is a CA key */ + if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && + (cp[sizeof(CA_MARKER) - 1] == ' ' || + cp[sizeof(CA_MARKER) - 1] == '\t')) { + ca = 1; + cp += sizeof(CA_MARKER); + } else + ca = 0; + /* Find the end of the host name portion. */ for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) ; + if (*kp == '\0' || *(kp + 1) == '\0') { error("line %d missing key: %.40s...", num, line); @@ -693,15 +734,15 @@ do_known_hosts(struct passwd *pw, const char *name) *kp++ = '\0'; kp2 = kp; - public = key_new(KEY_RSA1); - if (key_read(public, &kp) != 1) { + pub = key_new(KEY_RSA1); + if (key_read(pub, &kp) != 1) { kp = kp2; - key_free(public); - public = key_new(KEY_UNSPEC); - if (key_read(public, &kp) != 1) { + key_free(pub); + pub = key_new(KEY_UNSPEC); + if (key_read(pub, &kp) != 1) { error("line %d invalid key: %.40s...", num, line); - key_free(public); + key_free(pub); invalid = 1; continue; } @@ -719,43 +760,52 @@ do_known_hosts(struct passwd *pw, const char *name) c = (strcmp(cp2, cp) == 0); if (find_host && c) { printf("# Host %s found: " - "line %d type %s\n", name, - num, key_type(public)); - print_host(out, cp, public, 0); + "line %d type %s%s\n", name, + num, key_type(pub), + ca ? " (CA key)" : ""); + printhost(out, cp, pub, ca, 0); } - if (delete_host && !c) - print_host(out, cp, public, 0); + if (delete_host && !c && !ca) + printhost(out, cp, pub, ca, 0); } else if (hash_hosts) - print_host(out, cp, public, 0); + printhost(out, cp, pub, ca, 0); } else { if (find_host || delete_host) { c = (match_hostname(name, cp, strlen(cp)) == 1); if (find_host && c) { printf("# Host %s found: " - "line %d type %s\n", name, - num, key_type(public)); - print_host(out, name, public, - hash_hosts); + "line %d type %s%s\n", name, + num, key_type(pub), + ca ? " (CA key)" : ""); + printhost(out, name, pub, + ca, hash_hosts && !ca); } - if (delete_host && !c) - print_host(out, cp, public, 0); + if (delete_host && !c && !ca) + printhost(out, cp, pub, ca, 0); } else if (hash_hosts) { for (cp2 = strsep(&cp, ","); cp2 != NULL && *cp2 != '\0'; cp2 = strsep(&cp, ",")) { - if (strcspn(cp2, "*?!") != strlen(cp2)) + if (ca) { + fprintf(stderr, "Warning: " + "ignoring CA key for host: " + "%.64s\n", cp2); + printhost(out, cp2, pub, ca, 0); + } else if (strcspn(cp2, "*?!") != + strlen(cp2)) { fprintf(stderr, "Warning: " "ignoring host name with " "metacharacters: %.64s\n", cp2); - else - print_host(out, cp2, public, 1); + printhost(out, cp2, pub, ca, 0); + } else + printhost(out, cp2, pub, ca, 1); } has_unhashed = 1; } } - key_free(public); + key_free(pub); } fclose(in); @@ -1012,6 +1062,293 @@ do_change_comment(struct passwd *pw) exit(0); } +static const char * +fmt_validity(void) +{ + char from[32], to[32]; + static char ret[64]; + time_t tt; + struct tm *tm; + + *from = *to = '\0'; + if (cert_valid_from == 0 && + cert_valid_to == 0xffffffffffffffffULL) + return "forever"; + + if (cert_valid_from != 0) { + /* XXX revisit INT_MAX in 2038 :) */ + tt = cert_valid_from > INT_MAX ? INT_MAX : cert_valid_from; + tm = localtime(&tt); + strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); + } + if (cert_valid_to != 0xffffffffffffffffULL) { + /* XXX revisit INT_MAX in 2038 :) */ + tt = cert_valid_to > INT_MAX ? INT_MAX : cert_valid_to; + tm = localtime(&tt); + strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); + } + + if (cert_valid_from == 0) { + snprintf(ret, sizeof(ret), "before %s", to); + return ret; + } + if (cert_valid_to == 0xffffffffffffffffULL) { + snprintf(ret, sizeof(ret), "after %s", from); + return ret; + } + + snprintf(ret, sizeof(ret), "from %s to %s", from, to); + return ret; +} + +static void +add_flag_constraint(Buffer *c, const char *name) +{ + debug3("%s: %s", __func__, name); + buffer_put_cstring(c, name); + buffer_put_string(c, NULL, 0); +} + +static void +add_string_constraint(Buffer *c, const char *name, const char *value) +{ + Buffer b; + + debug3("%s: %s=%s", __func__, name, value); + buffer_init(&b); + buffer_put_cstring(&b, value); + + buffer_put_cstring(c, name); + buffer_put_string(c, buffer_ptr(&b), buffer_len(&b)); + + buffer_free(&b); +} + +static void +prepare_constraint_buf(Buffer *c) +{ + + buffer_clear(c); + if ((constraint_flags & CONSTRAINT_X_FWD) != 0) + add_flag_constraint(c, "permit-X11-forwarding"); + if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) + add_flag_constraint(c, "permit-agent-forwarding"); + if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) + add_flag_constraint(c, "permit-port-forwarding"); + if ((constraint_flags & CONSTRAINT_PTY) != 0) + add_flag_constraint(c, "permit-pty"); + if ((constraint_flags & CONSTRAINT_USER_RC) != 0) + add_flag_constraint(c, "permit-user-rc"); + if (constraint_command != NULL) + add_string_constraint(c, "forced-command", constraint_command); + if (constraint_src_addr != NULL) + add_string_constraint(c, "source-address", constraint_src_addr); +} + +static void +do_ca_sign(struct passwd *pw, int argc, char **argv) +{ + int i, fd; + u_int n; + Key *ca, *public; + char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; + FILE *f; + + tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); + if ((ca = load_identity(tmp)) == NULL) + fatal("Couldn't load CA key \"%s\"", tmp); + xfree(tmp); + + for (i = 0; i < argc; i++) { + /* Split list of principals */ + n = 0; + if (cert_principals != NULL) { + otmp = tmp = xstrdup(cert_principals); + plist = NULL; + for (; (cp = strsep(&tmp, ",")) != NULL; n++) { + plist = xrealloc(plist, n + 1, sizeof(*plist)); + if (*(plist[n] = xstrdup(cp)) == '\0') + fatal("Empty principal name"); + } + xfree(otmp); + } + + tmp = tilde_expand_filename(argv[i], pw->pw_uid); + if ((public = key_load_public(tmp, &comment)) == NULL) + fatal("%s: unable to open \"%s\"", __func__, tmp); + if (public->type != KEY_RSA && public->type != KEY_DSA) + fatal("%s: key \"%s\" type %s cannot be certified", + __func__, tmp, key_type(public)); + + /* Prepare certificate to sign */ + if (key_to_certified(public) != 0) + fatal("Could not upgrade key %s to certificate", tmp); + public->cert->type = cert_key_type; + public->cert->key_id = xstrdup(cert_key_id); + public->cert->nprincipals = n; + public->cert->principals = plist; + public->cert->valid_after = cert_valid_from; + public->cert->valid_before = cert_valid_to; + prepare_constraint_buf(&public->cert->constraints); + public->cert->signature_key = key_from_private(ca); + + if (key_certify(public, ca) != 0) + fatal("Couldn't not certify key %s", tmp); + + if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) + *cp = '\0'; + xasprintf(&out, "%s-cert.pub", tmp); + xfree(tmp); + + if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) + fatal("Could not open \"%s\" for writing: %s", out, + strerror(errno)); + if ((f = fdopen(fd, "w")) == NULL) + fatal("%s: fdopen: %s", __func__, strerror(errno)); + if (!key_write(public, f)) + fatal("Could not write certified key to %s", out); + fprintf(f, " %s\n", comment); + fclose(f); + + if (!quiet) + logit("Signed %s key %s: id \"%s\"%s%s valid %s", + cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", + out, cert_key_id, + cert_principals != NULL ? " for " : "", + cert_principals != NULL ? cert_principals : "", + fmt_validity()); + + key_free(public); + xfree(out); + } + exit(0); +} + +static u_int64_t +parse_relative_time(const char *s, time_t now) +{ + int64_t mul, secs; + + mul = *s == '-' ? -1 : 1; + + if ((secs = convtime(s + 1)) == -1) + fatal("Invalid relative certificate time %s", s); + if (mul == -1 && secs > now) + fatal("Certificate time %s cannot be represented", s); + return now + (u_int64_t)(secs * mul); +} + +static u_int64_t +parse_absolute_time(const char *s) +{ + struct tm tm; + time_t tt; + + if (strlen(s) != 8 && strlen(s) != 14) + fatal("Invalid certificate time format %s", s); + + bzero(&tm, sizeof(tm)); + if (strptime(s, + strlen(s) == 8 ? "%Y%m%d" : "%Y%m%d%H%M%S", &tm) == NULL) + fatal("Invalid certificate time %s", s); + if ((tt = mktime(&tm)) < 0) + fatal("Certificate time %s cannot be represented", s); + return (u_int64_t)tt; +} + +static void +parse_cert_times(char *timespec) +{ + char *from, *to; + time_t now = time(NULL); + int64_t secs; + + /* +timespec relative to now */ + if (*timespec == '+' && strchr(timespec, ':') == NULL) { + if ((secs = convtime(timespec + 1)) == -1) + fatal("Invalid relative certificate life %s", timespec); + cert_valid_to = now + secs; + /* + * Backdate certificate one minute to avoid problems on hosts + * with poorly-synchronised clocks. + */ + cert_valid_from = ((now - 59)/ 60) * 60; + return; + } + + /* + * from:to, where + * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS + * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS + */ + from = xstrdup(timespec); + to = strchr(from, ':'); + if (to == NULL || from == to || *(to + 1) == '\0') + fatal("Invalid certificate life specification %s", optarg); + *to++ = '\0'; + + if (*from == '-' || *from == '+') + cert_valid_from = parse_relative_time(from, now); + else + cert_valid_from = parse_absolute_time(from); + + if (*to == '-' || *to == '+') + cert_valid_to = parse_relative_time(to, cert_valid_from); + else + cert_valid_to = parse_absolute_time(to); + + if (cert_valid_to <= cert_valid_from) + fatal("Empty certificate validity interval"); + xfree(from); +} + +static void +add_cert_constraint(char *opt) +{ + char *val; + + if (strcmp(opt, "clear") == 0) + constraint_flags = 0; + else if (strcasecmp(opt, "no-x11-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_X_FWD; + else if (strcasecmp(opt, "permit-x11-forwarding") == 0) + constraint_flags |= CONSTRAINT_X_FWD; + else if (strcasecmp(opt, "no-agent-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_AGENT_FWD; + else if (strcasecmp(opt, "permit-agent-forwarding") == 0) + constraint_flags |= CONSTRAINT_AGENT_FWD; + else if (strcasecmp(opt, "no-port-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_PORT_FWD; + else if (strcasecmp(opt, "permit-port-forwarding") == 0) + constraint_flags |= CONSTRAINT_PORT_FWD; + else if (strcasecmp(opt, "no-pty") == 0) + constraint_flags &= ~CONSTRAINT_PTY; + else if (strcasecmp(opt, "permit-pty") == 0) + constraint_flags |= CONSTRAINT_PTY; + else if (strcasecmp(opt, "no-user-rc") == 0) + constraint_flags &= ~CONSTRAINT_USER_RC; + else if (strcasecmp(opt, "permit-user-rc") == 0) + constraint_flags |= CONSTRAINT_USER_RC; + else if (strncasecmp(opt, "force-command=", 14) == 0) { + val = opt + 14; + if (*val == '\0') + fatal("Empty force-command constraint"); + if (constraint_command != NULL) + fatal("force-command already specified"); + constraint_command = xstrdup(val); + } else if (strncasecmp(opt, "source-address=", 15) == 0) { + val = opt + 15; + if (*val == '\0') + fatal("Empty source-address constraint"); + if (constraint_src_addr != NULL) + fatal("source-address already specified"); + if (addr_match_cidr_list(NULL, val) != 0) + fatal("Invalid source-address list"); + constraint_src_addr = xstrdup(val); + } else + fatal("Unsupported certificate constraint \"%s\"", opt); +} + static void usage(void) { @@ -1031,18 +1368,24 @@ usage(void) fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); fprintf(stderr, " -g Use generic DNS resource record format.\n"); fprintf(stderr, " -H Hash names in known_hosts file.\n"); + fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n"); + fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); + fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n"); + fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n"); fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); fprintf(stderr, " -r hostname Print DNS resource record.\n"); + fprintf(stderr, " -s ca_key Certify keys with CA key.\n"); fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); fprintf(stderr, " -t type Specify type of key to create.\n"); + fprintf(stderr, " -V from:to Specify certificate validity interval.\n"); fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -y Read private key file and print public key.\n"); @@ -1094,8 +1437,8 @@ main(int argc, char **argv) exit(1); } - while ((opt = getopt(argc, argv, - "degiqpclBHvxXyF:b:f:t:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { + while ((opt = getopt(argc, argv, "degiqpclBHhvxXyF:b:f:t:D:I:P:N:n:" + "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { switch (opt) { case 'b': bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); @@ -1110,6 +1453,9 @@ main(int argc, char **argv) case 'H': hash_hosts = 1; break; + case 'I': + cert_key_id = optarg; + break; case 'R': delete_host = 1; rr_hostname = optarg; @@ -1120,6 +1466,9 @@ main(int argc, char **argv) case 'B': print_bubblebabble = 1; break; + case 'n': + cert_principals = optarg; + break; case 'p': change_passphrase = 1; break; @@ -1141,6 +1490,9 @@ main(int argc, char **argv) case 'N': identity_new_passphrase = optarg; break; + case 'O': + add_cert_constraint(optarg); + break; case 'C': identity_comment = optarg; break; @@ -1152,6 +1504,10 @@ main(int argc, char **argv) /* export key */ convert_to_ssh2 = 1; break; + case 'h': + cert_key_type = SSH2_CERT_TYPE_HOST; + constraint_flags = 0; + break; case 'i': case 'X': /* import key */ @@ -1163,6 +1519,9 @@ main(int argc, char **argv) case 'd': key_type_name = "dsa"; break; + case 's': + ca_key_path = optarg; + break; case 't': key_type_name = optarg; break; @@ -1217,6 +1576,9 @@ main(int argc, char **argv) if (BN_hex2bn(&start, optarg) == 0) fatal("Invalid start point."); break; + case 'V': + parse_cert_times(optarg); + break; case '?': default: usage(); @@ -1226,7 +1588,15 @@ main(int argc, char **argv) /* reinit */ log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); - if (optind < argc) { + argv += optind; + argc -= optind; + + if (ca_key_path != NULL) { + if (argc < 1) { + printf("Too few arguments.\n"); + usage(); + } + } else if (argc > 0) { printf("Too many arguments.\n"); usage(); } @@ -1238,6 +1608,11 @@ main(int argc, char **argv) printf("Cannot use -l with -D or -R.\n"); usage(); } + if (ca_key_path != NULL) { + if (cert_key_id == NULL) + fatal("Must specify key id (-I) when certifying"); + do_ca_sign(pw, argc, argv); + } if (delete_host || hash_hosts || find_host) do_known_hosts(pw, rr_hostname); if (print_fingerprint || print_bubblebabble) diff --git a/ssh-rsa.c b/ssh-rsa.c index 0e16ff85f..842857fee 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.39 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.40 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -46,7 +46,9 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, int ok, nid; Buffer b; - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + if (key == NULL || + (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || + key->rsa == NULL) { error("ssh_rsa_sign: no RSA key"); return -1; } @@ -113,7 +115,9 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, u_int len, dlen, modlen; int rlen, ret, nid; - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + if (key == NULL || + (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || + key->rsa == NULL) { error("ssh_rsa_verify: no RSA key"); return -1; } diff --git a/ssh.1 b/ssh.1 index 6964cd09c..7d8f92aba 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.294 2010/02/11 13:23:29 jmc Exp $ -.Dd $Mdocdate: February 11 2010 $ +.\" $OpenBSD: ssh.1,v 1.295 2010/02/26 20:29:54 djm Exp $ +.Dd $Mdocdate: February 26 2010 $ .Dt SSH 1 .Os .Sh NAME @@ -1103,6 +1103,25 @@ See the option in .Xr ssh_config 5 for more information. +.Pp +Host keys may also be presented as certificates signed by a trusted +certification authority (CA). +In this case, trust of the CA key alone is sufficient for the host key +to be accepted. +To specify a public key as a trusted CA key in a known hosts file, +it should be added after a +.Dq @cert-authority +tag and a set of one or more domain-name wildcards separated by commas. +For example: +.Pp +.Dl @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... +.Pp +See the +.Sx CERTIFICATES +section of +.Xr ssh-keygen 1 +for more details. +.Pp .Sh SSH-BASED VIRTUAL PRIVATE NETWORKS .Nm contains support for Virtual Private Network (VPN) tunnelling diff --git a/ssh.c b/ssh.c index 25ccdcaa5..b9553d3e1 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.334 2010/02/08 22:03:05 jmc Exp $ */ +/* $OpenBSD: ssh.c,v 1.335 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1306,34 +1306,35 @@ load_public_identity_files(void) int i = 0; Key *public; struct passwd *pw; + u_int n_ids; + char *identity_files[SSH_MAX_IDENTITY_FILES]; + Key *identity_keys[SSH_MAX_IDENTITY_FILES]; #ifdef ENABLE_PKCS11 Key **keys; int nkeys; +#endif /* PKCS11 */ + n_ids = 0; + bzero(identity_files, sizeof(identity_files)); + bzero(identity_keys, sizeof(identity_keys)); + +#ifdef ENABLE_PKCS11 if (options.pkcs11_provider != NULL && options.num_identity_files < SSH_MAX_IDENTITY_FILES && (pkcs11_init(!options.batch_mode) == 0) && (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, &keys)) > 0) { - int count = 0; for (i = 0; i < nkeys; i++) { - count++; - memmove(&options.identity_files[1], - &options.identity_files[0], - sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); - memmove(&options.identity_keys[1], - &options.identity_keys[0], - sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); - options.num_identity_files++; - options.identity_keys[0] = keys[i]; - options.identity_files[0] = + if (n_ids >= SSH_MAX_IDENTITY_FILES) { + key_free(keys[i]); + continue; + } + identity_keys[n_ids] = keys[i]; + identity_files[n_ids] = xstrdup(options.pkcs11_provider); /* XXX */ + n_ids++; } - if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) - options.num_identity_files = SSH_MAX_IDENTITY_FILES; - i = count; xfree(keys); - /* XXX leaks some keys */ } #endif /* ENABLE_PKCS11 */ if ((pw = getpwuid(original_real_uid)) == NULL) @@ -1343,7 +1344,11 @@ load_public_identity_files(void) if (gethostname(thishost, sizeof(thishost)) == -1) fatal("load_public_identity_files: gethostname: %s", strerror(errno)); - for (; i < options.num_identity_files; i++) { + for (i = 0; i < options.num_identity_files; i++) { + if (n_ids >= SSH_MAX_IDENTITY_FILES) { + xfree(options.identity_files[i]); + continue; + } cp = tilde_expand_filename(options.identity_files[i], original_real_uid); filename = percent_expand(cp, "d", pwdir, @@ -1354,9 +1359,37 @@ load_public_identity_files(void) debug("identity file %s type %d", filename, public ? public->type : -1); xfree(options.identity_files[i]); - options.identity_files[i] = filename; - options.identity_keys[i] = public; + identity_files[n_ids] = filename; + identity_keys[n_ids] = public; + + if (++n_ids >= SSH_MAX_IDENTITY_FILES) + continue; + + /* Try to add the certificate variant too */ + xasprintf(&cp, "%s-cert", filename); + public = key_load_public(cp, NULL); + debug("identity file %s type %d", cp, + public ? public->type : -1); + if (public == NULL) { + xfree(cp); + continue; + } + if (!key_is_cert(public)) { + debug("%s: key %s type %s is not a certificate", + __func__, cp, key_type(public)); + key_free(public); + xfree(cp); + continue; + } + identity_keys[n_ids] = public; + /* point to the original path, most likely the private key */ + identity_files[n_ids] = xstrdup(filename); + n_ids++; } + options.num_identity_files = n_ids; + memcpy(options.identity_files, identity_files, sizeof(identity_files)); + memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); + bzero(pwname, strlen(pwname)); xfree(pwname); bzero(pwdir, strlen(pwdir)); diff --git a/ssh2.h b/ssh2.h index b01af7b1a..3ffaf686b 100644 --- a/ssh2.h +++ b/ssh2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh2.h,v 1.12 2009/10/24 11:19:17 andreas Exp $ */ +/* $OpenBSD: ssh2.h,v 1.13 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -173,3 +173,6 @@ #define SSH2_MSG_KEX_ROAMING_AUTH_OK 33 #define SSH2_MSG_KEX_ROAMING_AUTH_FAIL 34 +/* Certificate types for OpenSSH certificate keys extension */ +#define SSH2_CERT_TYPE_USER 1 +#define SSH2_CERT_TYPE_HOST 2 diff --git a/sshconnect.c b/sshconnect.c index 63c4650f7..35c2f49be 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.218 2010/01/13 00:19:04 dtucker Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.219 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -58,6 +58,7 @@ #include "misc.h" #include "dns.h" #include "roaming.h" +#include "ssh2.h" #include "version.h" char *client_version_string = NULL; @@ -576,6 +577,23 @@ confirm(const char *prompt) } } +static int +check_host_cert(const char *host, const Key *host_key) +{ + const char *reason; + + if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) { + error("%s", reason); + return 0; + } + if (buffer_len(&host_key->cert->constraints) != 0) { + error("Certificate for %s contains unsupported constraint(s)", + host); + return 0; + } + return 1; +} + /* * check whether the supplied host key is valid, return -1 if the key * 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, Key *host_key, int readonly, const char *user_hostfile, const char *system_hostfile) { - Key *file_key; - const char *type = key_type(host_key); + Key *file_key, *raw_key = NULL; + const char *type; char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp, *ra; HostStatus host_status; HostStatus ip_status; - int r, local = 0, host_ip_differ = 0; + int r, want_cert, local = 0, host_ip_differ = 0; int salen; char ntop[NI_MAXHOST]; char msg[1024]; @@ -667,11 +685,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, host = put_host_port(hostname, port); } + retry: + want_cert = key_is_cert(host_key); + type = key_type(host_key); + /* * Store the host key from the known host file in here so that we can * compare it with the key for the IP address. */ - file_key = key_new(host_key->type); + file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type); /* * 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, } /* * Also perform check for the ip address, skip the check if we are - * localhost or the hostname was an ip address to begin with + * localhost, looking for a certificate, or the hostname was an ip + * address to begin with. */ - if (options.check_host_ip) { + if (!want_cert && options.check_host_ip) { Key *ip_key = key_new(host_key->type); ip_file = user_hostfile; @@ -713,11 +736,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, switch (host_status) { case HOST_OK: /* The host is known and the key matches. */ - debug("Host '%.200s' is known and matches the %s host key.", - host, type); - debug("Found key in %s:%d", host_file, host_line); + debug("Host '%.200s' is known and matches the %s host %s.", + host, type, want_cert ? "certificate" : "key"); + debug("Found %s in %s:%d", + want_cert ? "certificate" : "key", host_file, host_line); + if (want_cert && !check_host_cert(hostname, host_key)) + goto fail; if (options.check_host_ip && ip_status == HOST_NEW) { - if (readonly) + if (readonly || want_cert) logit("%s host key for IP address " "'%.128s' not in list of known hosts.", type, ip); @@ -749,7 +775,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, break; } } - if (readonly) + if (readonly || want_cert) goto fail; /* The host is new. */ if (options.strict_host_key_checking == 1) { @@ -834,6 +860,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, "list of known hosts.", hostp, type); break; case HOST_CHANGED: + if (want_cert) { + /* + * This is only a debug() since it is valid to have + * CAs with wildcard DNS matches that don't match + * all hosts that one might visit. + */ + debug("Host certificate authority does not " + "match %s in %s:%d", CA_MARKER, + host_file, host_line); + goto fail; + } if (readonly == ROQUIET) goto fail; if (options.check_host_ip && host_ip_differ) { @@ -970,6 +1007,20 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, return 0; fail: + if (want_cert) { + /* + * No matching certificate. Downgrade cert to raw key and + * search normally. + */ + debug("No matching CA found. Retry with plain key"); + raw_key = key_from_private(host_key); + if (key_drop_cert(raw_key) != 0) + fatal("Couldn't drop certificate"); + host_key = raw_key; + goto retry; + } + if (raw_key != NULL) + key_free(raw_key); xfree(ip); xfree(host); return -1; @@ -982,7 +1033,8 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) struct stat st; int flags = 0; - if (options.verify_host_key_dns && + /* XXX certs are not yet supported for DNS */ + if (!key_is_cert(host_key) && options.verify_host_key_dns && verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { if (flags & DNS_VERIFY_FOUND) { diff --git a/sshconnect2.c b/sshconnect2.c index e81064dae..2a5943e7e 100644 --- a/sshconnect2.c +++ b/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.179 2010/01/13 01:20:20 dtucker Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.180 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -1311,6 +1311,8 @@ pubkey_prepare(Authctxt *authctxt) key = options.identity_keys[i]; if (key && key->type == KEY_RSA1) continue; + if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) + continue; options.identity_keys[i] = NULL; id = xcalloc(1, sizeof(*id)); id->key = key; diff --git a/sshd.8 b/sshd.8 index 76b7e2987..fcd5195db 100644 --- a/sshd.8 +++ b/sshd.8 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd.8,v 1.250 2010/01/30 21:08:33 djm Exp $ -.Dd $Mdocdate: January 30 2010 $ +.\" $OpenBSD: sshd.8,v 1.251 2010/02/26 20:29:54 djm Exp $ +.Dd $Mdocdate: February 26 2010 $ .Dt SSHD 8 .Os .Sh NAME @@ -47,6 +47,7 @@ .Op Fl 46DdeiqTt .Op Fl b Ar bits .Op Fl C Ar connection_spec +.Op Fl c Ar host_certificate_file .Op Fl f Ar config_file .Op Fl g Ar login_grace_time .Op Fl h Ar host_key_file @@ -101,6 +102,15 @@ to use IPv6 addresses only. .It Fl b Ar bits Specifies the number of bits in the ephemeral protocol version 1 server key (default 1024). +.It Fl c Ar host_certificate_file +Specifies a path to a certificate file to identify +.Nm +during key exchange. +The certificate file must match a host key file specified using the +.Fl -h +option or the +.Cm HostKey +configuration directive. .It Fl C Ar connection_spec Specify the connection parameters to use for the .Fl T @@ -498,6 +508,13 @@ No spaces are permitted, except within double quotes. The following option specifications are supported (note that option keywords are case-insensitive): .Bl -tag -width Ds +.It Cm from="cert-authority" +Specifies that the listed key is a certification authority (CA) that is +trusted to validate signed certificates for user authentication. +.Pp +Certificates may encode access restrictions similar to these key options. +If both certificate restrictions and key options are present, the most +restrictive union of the two is applied. .It Cm command="command" Specifies that the command is executed whenever this key is used for authentication. @@ -517,6 +534,10 @@ The command originally supplied by the client is available in the .Ev SSH_ORIGINAL_COMMAND environment variable. Note that this option applies to shell, command or subsystem execution. +Also note that this command may be superseded by either a +.Xr sshd_config 5 +.Cm ForceCommand +directive or a command embedded in a certificate. .It Cm environment="NAME=value" Specifies that the string is to be added to the environment when logging in using this key. diff --git a/sshd.c b/sshd.c index bf2e76cc8..0c3c04e4e 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.372 2010/01/29 00:20:41 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.373 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -205,6 +205,7 @@ struct { Key *server_key; /* ephemeral server key */ Key *ssh1_host_key; /* ssh1 host key */ Key **host_keys; /* all private host keys */ + Key **host_certificates; /* all public host certificates */ int have_ssh1_key; int have_ssh2_key; u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; @@ -545,6 +546,10 @@ destroy_sensitive_data(void) key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; } + if (sensitive_data.host_certificates[i]) { + key_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } } sensitive_data.ssh1_host_key = NULL; memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); @@ -571,6 +576,7 @@ demote_sensitive_data(void) if (tmp->type == KEY_RSA1) sensitive_data.ssh1_host_key = tmp; } + /* Certs do not need demotion */ } /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ @@ -717,10 +723,11 @@ list_hostkey_types(void) const char *p; char *ret; int i; + Key *key; buffer_init(&b); for (i = 0; i < options.num_host_key_files; i++) { - Key *key = sensitive_data.host_keys[i]; + key = sensitive_data.host_keys[i]; if (key == NULL) continue; switch (key->type) { @@ -732,6 +739,19 @@ list_hostkey_types(void) buffer_append(&b, p, strlen(p)); break; } + /* If the private key has a cert peer, then list that too */ + key = sensitive_data.host_certificates[i]; + if (key == NULL) + continue; + switch (key->type) { + case KEY_RSA_CERT: + case KEY_DSA_CERT: + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + p = key_ssh_name(key); + buffer_append(&b, p, strlen(p)); + break; + } } buffer_append(&b, "\0", 1); ret = xstrdup(buffer_ptr(&b)); @@ -740,19 +760,36 @@ list_hostkey_types(void) return ret; } -Key * -get_hostkey_by_type(int type) +static Key * +get_hostkey_by_type(int type, int need_private) { int i; + Key *key; for (i = 0; i < options.num_host_key_files; i++) { - Key *key = sensitive_data.host_keys[i]; + if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) + key = sensitive_data.host_certificates[i]; + else + key = sensitive_data.host_keys[i]; if (key != NULL && key->type == type) - return key; + return need_private ? + sensitive_data.host_keys[i] : key; } return NULL; } +Key * +get_hostkey_public_by_type(int type) +{ + return get_hostkey_by_type(type, 0); +} + +Key * +get_hostkey_private_by_type(int type) +{ + return get_hostkey_by_type(type, 1); +} + Key * get_hostkey_by_index(int ind) { @@ -767,8 +804,13 @@ get_hostkey_index(Key *key) int i; for (i = 0; i < options.num_host_key_files; i++) { - if (key == sensitive_data.host_keys[i]) - return (i); + if (key_is_cert(key)) { + if (key == sensitive_data.host_certificates[i]) + return (i); + } else { + if (key == sensitive_data.host_keys[i]) + return (i); + } } return (-1); } @@ -807,9 +849,9 @@ usage(void) fprintf(stderr, "%s, %s\n", SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); fprintf(stderr, -"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n" -" [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n" -" [-o option] [-p port] [-u len]\n" +"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" +" [-f config_file] [-g login_grace_time] [-h host_key_file]\n" +" [-k key_gen_time] [-o option] [-p port] [-u len]\n" ); exit(1); } @@ -1236,7 +1278,7 @@ main(int ac, char **av) { extern char *optarg; extern int optind; - int opt, i, on = 1; + int opt, i, j, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; char *test_user = NULL, *test_host = NULL, *test_addr = NULL; @@ -1289,6 +1331,14 @@ main(int ac, char **av) case 'f': config_file_name = optarg; break; + case 'c': + if (options.num_host_cert_files >= MAX_HOSTCERTS) { + fprintf(stderr, "too many host certificates.\n"); + exit(1); + } + options.host_cert_files[options.num_host_cert_files++] = + derelativise_path(optarg); + break; case 'd': if (debug_flag == 0) { debug_flag = 1; @@ -1536,6 +1586,46 @@ main(int ac, char **av) exit(1); } + /* + * Load certificates. They are stored in an array at identical + * indices to the public keys that they relate to. + */ + sensitive_data.host_certificates = xcalloc(options.num_host_key_files, + sizeof(Key *)); + for (i = 0; i < options.num_host_key_files; i++) + sensitive_data.host_certificates[i] = NULL; + + for (i = 0; i < options.num_host_cert_files; i++) { + key = key_load_public(options.host_cert_files[i], NULL); + if (key == NULL) { + error("Could not load host certificate: %s", + options.host_cert_files[i]); + continue; + } + if (!key_is_cert(key)) { + error("Certificate file is not a certificate: %s", + options.host_cert_files[i]); + key_free(key); + continue; + } + /* Find matching private key */ + for (j = 0; j < options.num_host_key_files; j++) { + if (key_equal_public(key, + sensitive_data.host_keys[j])) { + sensitive_data.host_certificates[j] = key; + break; + } + } + if (j >= options.num_host_key_files) { + error("No matching private key for certificate: %s", + options.host_cert_files[i]); + key_free(key); + continue; + } + sensitive_data.host_certificates[j] = key; + debug("host certificate: #%d type %d %s", j, key->type, + key_type(key)); + } /* Check certain values for sanity. */ if (options.protocol & SSH_PROTO_1) { if (options.server_key_bits < 512 || @@ -2205,7 +2295,8 @@ do_ssh2_kex(void) kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; - kex->load_host_key=&get_hostkey_by_type; + kex->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; xxx_kex = kex; diff --git a/sshd_config.5 b/sshd_config.5 index bf3319c4d..001114655 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.116 2010/01/09 23:04:13 dtucker Exp $ -.Dd $Mdocdate: January 9 2010 $ +.\" $OpenBSD: sshd_config.5,v 1.117 2010/02/26 20:29:54 djm Exp $ +.Dd $Mdocdate: February 26 2010 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -411,6 +411,14 @@ uses the name supplied by the client rather than attempting to resolve the name from the TCP connection itself. The default is .Dq no . +.It Cm HostCertificate +Specifies a file containing a public host certificate. +The certificate's public key must match a private host key already specified +by +.Cm HostKey . +The default behaviour of +.Xr sshd 8 +is not to load any certificates. .It Cm HostKey Specifies a file containing a private host key used by SSH. -- cgit v1.2.3 From 1aed65eb27feec505997c98621bdf158f9ab8b99 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 4 Mar 2010 21:53:35 +1100 Subject: - djm@cvs.openbsd.org 2010/03/04 10:36:03 [auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c] [authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h] [ssh-keygen.c ssh.1 sshconnect.c sshd_config.5] Add a TrustedUserCAKeys option to sshd_config to specify CA keys that are trusted to authenticate users (in addition than doing it per-user in authorized_keys). Add a RevokedKeys option to sshd_config and a @revoked marker to known_hosts to allow keys to me revoked and banned for user or host authentication. feedback and ok markus@ --- ChangeLog | 13 +++++++ auth-rh-rsa.c | 5 ++- auth-rsa.c | 5 ++- auth.c | 31 ++++++++++++++++- auth.h | 3 +- auth2-hostbased.c | 5 ++- auth2-pubkey.c | 53 +++++++++++++++++++++++++++- authfile.c | 64 +++++++++++++++++++++++++++++++++- authfile.h | 3 +- hostfile.c | 102 +++++++++++++++++++++++++++++++++++++++++++----------- hostfile.h | 5 +-- servconf.c | 19 +++++++++- servconf.h | 4 ++- ssh-keygen.c | 2 +- ssh.1 | 20 +++++++++-- sshconnect.c | 24 +++++++++++-- sshd_config.5 | 25 +++++++++++-- 17 files changed, 343 insertions(+), 40 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 0b5663ba4..07d4aeb05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,19 @@ [key.c] use buffer_get_string_ptr_ret() where we are checking the return value explicitly instead of the fatal()-causing buffer_get_string_ptr() + - djm@cvs.openbsd.org 2010/03/04 10:36:03 + [auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c] + [authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h] + [ssh-keygen.c ssh.1 sshconnect.c sshd_config.5] + Add a TrustedUserCAKeys option to sshd_config to specify CA keys that + are trusted to authenticate users (in addition than doing it per-user + in authorized_keys). + + Add a RevokedKeys option to sshd_config and a @revoked marker to + known_hosts to allow keys to me revoked and banned for user or host + authentication. + + feedback and ok markus@ 20100303 - (djm) [PROTOCOL.certkeys] Add RCS Ident diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index eca750275..b21a0f4a2 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -44,6 +44,9 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, { HostStatus host_status; + if (auth_key_is_revoked(client_host_key)) + return 0; + /* Check if we would accept it using rhosts authentication. */ if (!auth_rhosts(pw, cuser)) return 0; diff --git a/auth-rsa.c b/auth-rsa.c index bf5462076..65571a890 100644 --- a/auth-rsa.c +++ b/auth-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */ +/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -94,6 +94,9 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) MD5_CTX md; int len; + if (auth_key_is_revoked(key)) + return 0; + /* don't allow short keys */ if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", diff --git a/auth.c b/auth.c index ab9c69fb8..e680efbcc 100644 --- a/auth.c +++ b/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.84 2010/02/09 06:18:46 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.85 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -69,6 +69,7 @@ #ifdef GSSAPI #include "ssh-gss.h" #endif +#include "authfile.h" #include "monitor_wrap.h" /* import */ @@ -582,6 +583,34 @@ getpwnamallow(const char *user) return (NULL); } +/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ +int +auth_key_is_revoked(Key *key) +{ + char *key_fp; + + if (options.revoked_keys_file == NULL) + return 0; + + switch (key_in_file(key, options.revoked_keys_file, 0)) { + case 0: + /* key not revoked */ + return 0; + case -1: + /* Error opening revoked_keys_file: refuse all keys */ + error("Revoked keys file is unreadable: refusing public key " + "authentication"); + return 1; + case 1: + /* Key revoked */ + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + error("%s key %s is revoked", key_type(key), key_fp); + xfree(key_fp); + return 1; + } + fatal("key_in_file returned junk"); +} + void auth_debug_add(const char *fmt,...) { diff --git a/auth.h b/auth.h index 117485ca9..a65b87dd1 100644 --- a/auth.h +++ b/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.64 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -171,6 +171,7 @@ char *authorized_keys_file(struct passwd *); char *authorized_keys_file2(struct passwd *); FILE *auth_openkeyfile(const char *, struct passwd *, int); +int auth_key_is_revoked(Key *); HostStatus check_key_in_hostfiles(struct passwd *, Key *, const char *, diff --git a/auth2-hostbased.c b/auth2-hostbased.c index 041051c53..721646520 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -145,6 +145,9 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, HostStatus host_status; int len; + if (auth_key_is_revoked(key)) + return 0; + resolvedname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 66ca5266b..51aa77487 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.20 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.21 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -56,6 +56,7 @@ #endif #include "monitor_wrap.h" #include "misc.h" +#include "authfile.h" /* import */ extern ServerOptions options; @@ -276,6 +277,47 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) return found_key; } +/* Authenticate a certificate key against TrustedUserCAKeys */ +static int +user_cert_trusted_ca(struct passwd *pw, Key *key) +{ + char *key_fp, *ca_fp; + const char *reason; + int ret = 0; + + if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) + return 0; + + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + ca_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + + if (key_in_file(key->cert->signature_key, + options.trusted_user_ca_keys, 1) != 1) { + debug2("%s: CA %s %s is not listed in %s", __func__, + key_type(key->cert->signature_key), ca_fp, + options.trusted_user_ca_keys); + goto out; + } + if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { + error("%s", reason); + auth_debug_add("%s", reason); + goto out; + } + if (auth_cert_constraints(&key->cert->constraints, pw) != 0) + goto out; + + verbose("%s certificate %s allowed by trusted %s key %s", + key_type(key), key_fp, key_type(key->cert->signature_key), ca_fp); + ret = 1; + + out: + if (key_fp != NULL) + xfree(key_fp); + if (ca_fp != NULL) + xfree(ca_fp); + return ret; +} + /* check whether given key is in .ssh/authorized_keys* */ int user_key_allowed(struct passwd *pw, Key *key) @@ -283,6 +325,15 @@ user_key_allowed(struct passwd *pw, Key *key) int success; char *file; + if (auth_key_is_revoked(key)) + return 0; + if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) + return 0; + + success = user_cert_trusted_ca(pw, key); + if (success) + return success; + file = authorized_keys_file(pw); success = user_key_allowed2(pw, key, file); xfree(file); diff --git a/authfile.c b/authfile.c index 2c615709d..224c6aa80 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.79 2010/01/12 00:16:47 dtucker Exp $ */ +/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -692,3 +692,65 @@ key_load_public(const char *filename, char **commentp) key_free(pub); return NULL; } + +/* + * Returns 1 if the specified "key" is listed in the file "filename", + * 0 if the key is not listed or -1 on error. + * If strict_type is set then the key type must match exactly, + * otherwise a comparison that ignores certficiate data is performed. + */ +int +key_in_file(Key *key, const char *filename, int strict_type) +{ + FILE *f; + char line[SSH_MAX_PUBKEY_BYTES]; + char *cp; + u_long linenum = 0; + int ret = 0; + Key *pub; + int (*key_compare)(const Key *, const Key *) = strict_type ? + key_equal : key_equal_public; + + if ((f = fopen(filename, "r")) == NULL) { + if (errno == ENOENT) { + debug("%s: keyfile \"%s\" missing", __func__, filename); + return 0; + } else { + error("%s: could not open keyfile \"%s\": %s", __func__, + filename, strerror(errno)); + return -1; + } + } + + while (read_keyfile_line(f, filename, line, sizeof(line), + &linenum) != -1) { + cp = line; + + /* Skip leading whitespace. */ + for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) + ; + + /* Skip comments and empty lines */ + switch (*cp) { + case '#': + case '\n': + case '\0': + continue; + } + + pub = key_new(KEY_UNSPEC); + if (key_read(pub, &cp) != 1) { + key_free(pub); + continue; + } + if (key_compare(key, pub)) { + ret = 1; + key_free(pub); + break; + } + key_free(pub); + } + fclose(f); + return ret; +} + diff --git a/authfile.h b/authfile.h index a6c74934d..6dfa478e7 100644 --- a/authfile.h +++ b/authfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 dtucker Exp $ */ +/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -22,5 +22,6 @@ Key *key_load_private(const char *, const char *, char **); Key *key_load_private_type(int, const char *, const char *, char **, int *); Key *key_load_private_pem(int, int, const char *, char **); int key_perm_ok(int, const char *); +int key_in_file(Key *, const char *, int); #endif diff --git a/hostfile.c b/hostfile.c index fc7f84c79..afab6dad1 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.47 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -183,6 +183,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen return 1; } +static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA } +check_markers(char **cpp) +{ + char marker[32], *sp, *cp = *cpp; + int ret = MRK_NONE; + + while (*cp == '@') { + /* Only one marker is allowed */ + if (ret != MRK_NONE) + return MRK_ERROR; + /* Markers are terminated by whitespace */ + if ((sp = strchr(cp, ' ')) == NULL && + (sp = strchr(cp, '\t')) == NULL) + return MRK_ERROR; + /* Extract marker for comparison */ + if (sp <= cp + 1 || sp >= cp + sizeof(marker)) + return MRK_ERROR; + memcpy(marker, cp, sp - cp); + marker[sp - cp] = '\0'; + if (strcmp(marker, CA_MARKER) == 0) + ret = MRK_CA; + else if (strcmp(marker, REVOKE_MARKER) == 0) + ret = MRK_REVOKE; + else + return MRK_ERROR; + + /* Skip past marker and any whitespace that follows it */ + cp = sp; + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + } + *cpp = cp; + return ret; +} + /* * Checks whether the given host (which must be in all lowercase) is already * in the list of our known hosts. Returns HOST_OK if the host is known and @@ -195,17 +230,21 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen static HostStatus check_host_in_hostfile_by_key_or_type(const char *filename, - const char *host, const Key *key, int keytype, Key *found, int *numret) + const char *host, const Key *key, int keytype, Key *found, + int want_revocation, int *numret) { FILE *f; char line[8192]; - int linenum = 0, want_cert = key_is_cert(key); + int want, have, linenum = 0, want_cert = key_is_cert(key); u_int kbits; char *cp, *cp2, *hashed_host; HostStatus end_return; debug3("check_host_in_hostfile: host %s filename %s", host, filename); + if (want_revocation && (key == NULL || keytype != 0 || found != NULL)) + fatal("%s: invalid arguments", __func__); + /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); if (!f) @@ -229,21 +268,18 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!*cp || *cp == '#' || *cp == '\n') continue; - /* - * Ignore CA keys when looking for raw keys. - * Ignore raw keys when looking for CA keys. - */ - if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && - (cp[sizeof(CA_MARKER) - 1] == ' ' || - cp[sizeof(CA_MARKER) - 1] == '\t')) { - if (want_cert) { - /* Skip the marker and following whitespace */ - cp += sizeof(CA_MARKER); - for (; *cp == ' ' || *cp == '\t'; cp++) - ; - } else - continue; - } else if (want_cert) + if (want_revocation) + want = MRK_REVOKE; + else if (want_cert) + want = MRK_CA; + else + want = MRK_NONE; + + if ((have = check_markers(&cp)) == MRK_ERROR) { + verbose("%s: invalid marker at %s:%d", + __func__, filename, linenum); + continue; + } else if (want != have) continue; /* Find the end of the host name portion. */ @@ -267,6 +303,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename, /* Got a match. Skip host name. */ cp = cp2; + if (want_revocation) + found = key_new(KEY_UNSPEC); + /* * Extract the key from the line. This will skip any leading * whitespace. Ignore badly formatted lines. @@ -289,6 +328,24 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!hostfile_check_key(kbits, found, host, filename, linenum)) continue; + if (want_revocation) { + if (key_is_cert(key) && + key_equal_public(key->cert->signature_key, found)) { + verbose("check_host_in_hostfile: revoked CA " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + if (key_equal_public(key, found)) { + verbose("check_host_in_hostfile: revoked key " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + key_free(found); + continue; + } + /* Check if the current key is the same as the given key. */ if (want_cert && key_equal(key->cert->signature_key, found)) { /* Found CA cert for key */ @@ -325,8 +382,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key, { if (key == NULL) fatal("no key to look up"); - return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, - found, numret)); + if (check_host_in_hostfile_by_key_or_type(filename, host, + key, 0, NULL, 1, NULL) == HOST_REVOKED) + return HOST_REVOKED; + return check_host_in_hostfile_by_key_or_type(filename, host, key, 0, + found, 0, numret); } int @@ -334,7 +394,7 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host, int keytype, Key *found, int *numret) { return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, - keytype, found, numret) == HOST_FOUND); + keytype, found, 0, numret) == HOST_FOUND); } /* diff --git a/hostfile.h b/hostfile.h index ebac1e4f1..1d460c1a9 100644 --- a/hostfile.h +++ b/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.17 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: hostfile.h,v 1.18 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -15,7 +15,7 @@ #define HOSTFILE_H typedef enum { - HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND + HOST_OK, HOST_NEW, HOST_CHANGED, HOST_REVOKED, HOST_FOUND } HostStatus; int hostfile_read_key(char **, u_int *, Key *); @@ -29,6 +29,7 @@ int lookup_key_in_hostfile_by_type(const char *, const char *, #define HASH_DELIM '|' #define CA_MARKER "@cert-authority" +#define REVOKE_MARKER "@revoked" char *host_hash(const char *, const char *, u_int); diff --git a/servconf.c b/servconf.c index 0a6cdb655..f9e2f2dfd 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.203 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.204 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -129,6 +129,8 @@ initialize_server_options(ServerOptions *options) options->adm_forced_command = NULL; options->chroot_directory = NULL; options->zero_knowledge_password_authentication = -1; + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; } void @@ -308,6 +310,7 @@ typedef enum { sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sDeprecated, sUnsupported } ServerOpCodes; @@ -427,6 +430,8 @@ static struct { { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -1323,6 +1328,14 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; + case sTrustedUserCAKeys: + charptr = &options->trusted_user_ca_keys; + goto parse_filename; + + case sRevokedKeys: + charptr = &options->revoked_keys_file; + goto parse_filename; + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1437,6 +1450,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) return; M_CP_STROPT(adm_forced_command); M_CP_STROPT(chroot_directory); + M_CP_STROPT(trusted_user_ca_keys); + M_CP_STROPT(revoked_keys_file); } #undef M_CP_INTOPT @@ -1656,6 +1671,8 @@ dump_config(ServerOptions *o) dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); dump_cfg_string(sForceCommand, o->adm_forced_command); dump_cfg_string(sChrootDirectory, o->chroot_directory); + dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); + dump_cfg_string(sRevokedKeys, o->revoked_keys_file); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); diff --git a/servconf.h b/servconf.h index c5c9c6ecd..860009f9c 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.91 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -154,6 +154,8 @@ typedef struct { int num_permitted_opens; char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/ssh-keygen.c b/ssh-keygen.c index f910dce38..c2120bbc1 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.180 2010/03/02 23:20:57 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.181 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland diff --git a/ssh.1 b/ssh.1 index 183dc277f..e8a4e5953 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.296 2010/02/26 22:09:28 jmc Exp $ -.Dd $Mdocdate: February 26 2010 $ +.\" $OpenBSD: ssh.1,v 1.297 2010/03/04 10:36:03 djm Exp $ +.Dd $Mdocdate: March 4 2010 $ .Dt SSH 1 .Os .Sh NAME @@ -1121,6 +1121,22 @@ See the section of .Xr ssh-keygen 1 for more details. +.Pp +Keys may be also be marked as revoked using the +.Dq @revoked +marker. +Revoked keys will always trigger a warning when encountered and the host +that presented them will be treated as untrusted. +For example: +.Pp +.Dl @revoked * ssh-rsa AAAAB5W... +.Pp +Revoking a key revokes it for direct use and as a certification authority. +Do not use both the +.Dq @cert-authority and +.Dq @revoked +markers on the same line. +.Pp .Sh SSH-BASED VIRTUAL PRIVATE NETWORKS .Nm contains support for Virtual Private Network (VPN) tunnelling diff --git a/sshconnect.c b/sshconnect.c index 35c2f49be..9de52224d 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.219 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -859,6 +859,25 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); break; + case HOST_REVOKED: + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REVOKED HOST KEY DETECTED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("The %s host key for %s is marked as revoked.", type, host); + error("This could mean that a stolen key is being used to"); + error("impersonate this host."); + + /* + * If strict host key checking is in use, the user will have + * to edit the key manually and we can only abort. + */ + if (options.strict_host_key_checking) { + error("%s host key for %.200s was revoked and you have " + "requested strict checking.", type, host); + goto fail; + } + goto continue_unsafe; + case HOST_CHANGED: if (want_cert) { /* @@ -908,6 +927,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, goto fail; } + continue_unsafe: /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or @@ -1007,7 +1027,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, return 0; fail: - if (want_cert) { + if (want_cert && host_status != HOST_REVOKED) { /* * No matching certificate. Downgrade cert to raw key and * search normally. diff --git a/sshd_config.5 b/sshd_config.5 index 001114655..07e74e2b7 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,8 +34,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.117 2010/02/26 20:29:54 djm Exp $ -.Dd $Mdocdate: February 26 2010 $ +.\" $OpenBSD: sshd_config.5,v 1.118 2010/03/04 10:36:03 djm Exp $ +.Dd $Mdocdate: March 4 2010 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -814,6 +814,11 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm RevokedKeys +Specifies a list of revoked public keys. +Keys listed in this file will be refused for public key authentication. +Note that if this file is not readable, then public key authentication will +be refused for all users. .It Cm RhostsRSAAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. @@ -889,6 +894,22 @@ This avoids infinitely hanging sessions. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm TrustedUserCAKeys +Specifies a file containing public keys of certificate authorities that are +trusted sign user certificates for authentication. +Keys are listed one per line, empty lines and comments starting with +.Ql # +are allowed. +If a certificate is presented for authentication and has its signing CA key +listed in this file, then it may be used for authentication for any user +listed in the certificate's principals list. +Note that certificates that lack a list of principals will not be permitted +for authentication using +.Cm TrustedUserCAKeys . +For more details in certificates, please see the +.Sx CERTIFICATES +section in +.Xr ssh-keygen 1 . .It Cm UseDNS Specifies whether .Xr sshd 8 -- cgit v1.2.3 From 72b33820af596f78a7ea7ee1200ae4c46b6167e5 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 5 Mar 2010 07:39:01 +1100 Subject: - jmc@cvs.openbsd.org 2010/03/04 12:51:25 [ssh.1 sshd_config.5] tweak previous; --- ChangeLog | 6 ++++++ ssh.1 | 8 ++++---- sshd_config.5 | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index f6c61d89d..ab7f88fe2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +20100305 + - OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/03/04 12:51:25 + [ssh.1 sshd_config.5] + tweak previous; + 20100304 - (djm) [ssh-keygen.c] Use correct local variable, instead of maybe-undefined global "optarg" diff --git a/ssh.1 b/ssh.1 index e8a4e5953..8c53d4b07 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh.1,v 1.297 2010/03/04 10:36:03 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.298 2010/03/04 12:51:25 jmc Exp $ .Dd $Mdocdate: March 4 2010 $ .Dt SSH 1 .Os @@ -1122,7 +1122,7 @@ section of .Xr ssh-keygen 1 for more details. .Pp -Keys may be also be marked as revoked using the +Keys may also be marked as revoked using the .Dq @revoked marker. Revoked keys will always trigger a warning when encountered and the host @@ -1133,10 +1133,10 @@ For example: .Pp Revoking a key revokes it for direct use and as a certification authority. Do not use both the -.Dq @cert-authority and +.Dq @cert-authority +and .Dq @revoked markers on the same line. -.Pp .Sh SSH-BASED VIRTUAL PRIVATE NETWORKS .Nm contains support for Virtual Private Network (VPN) tunnelling diff --git a/sshd_config.5 b/sshd_config.5 index 07e74e2b7..a0427584d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.118 2010/03/04 10:36:03 djm Exp $ +.\" $OpenBSD: sshd_config.5,v 1.119 2010/03/04 12:51:25 jmc Exp $ .Dd $Mdocdate: March 4 2010 $ .Dt SSHD_CONFIG 5 .Os @@ -897,7 +897,7 @@ To disable TCP keepalive messages, the value should be set to .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted sign user certificates for authentication. -Keys are listed one per line, empty lines and comments starting with +Keys are listed one per line; empty lines and comments starting with .Ql # are allowed. If a certificate is presented for authentication and has its signing CA key @@ -906,7 +906,7 @@ listed in the certificate's principals list. Note that certificates that lack a list of principals will not be permitted for authentication using .Cm TrustedUserCAKeys . -For more details in certificates, please see the +For more details on certificates, see the .Sx CERTIFICATES section in .Xr ssh-keygen 1 . -- cgit v1.2.3 From c6db99ec14f511d8ee5efb3c1fee42ab1ab61c8e Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 5 Mar 2010 10:41:45 +1100 Subject: - djm@cvs.openbsd.org 2010/03/04 23:17:25 [sshd_config.5] missing word; spotted by jmc@ --- ChangeLog | 3 +++ sshd_config.5 | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'sshd_config.5') diff --git a/ChangeLog b/ChangeLog index 1659e324a..f8e1d0e2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ - jmc@cvs.openbsd.org 2010/03/04 22:52:40 [ssh-keygen.1] fix Bk/Ek; + - djm@cvs.openbsd.org 2010/03/04 23:17:25 + [sshd_config.5] + missing word; spotted by jmc@ - (tim) [ssh-pkcs11.c] Fix "non-constant initializer" errors in older compilers. OK djm@ diff --git a/sshd_config.5 b/sshd_config.5 index a0427584d..2f5410281 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.119 2010/03/04 12:51:25 jmc Exp $ +.\" $OpenBSD: sshd_config.5,v 1.120 2010/03/04 23:17:25 djm Exp $ .Dd $Mdocdate: March 4 2010 $ .Dt SSHD_CONFIG 5 .Os @@ -896,7 +896,7 @@ To disable TCP keepalive messages, the value should be set to .Dq no . .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are -trusted sign user certificates for authentication. +trusted to sign user certificates for authentication. Keys are listed one per line; empty lines and comments starting with .Ql # are allowed. -- cgit v1.2.3