SSH is a protocol used to open a command shell on a remote host via an encrypted communications channel. When a firewall or other network roadblock prevents a user on host A from directly opening an SSH connection to a host C it is often necessary to connect through an intermediary. Users will often enter a command on host A to establish an SSH connection to the intermediate host B, and then enter a command to host B via that connection to establish an SSH connection from host B to host C. If an attacker controls host B, the attacker can either capture the credentials (password) used to establish the connection between the user and host C or may simply capture the connection after it is established. The SSH hop modifications, discussed in this README, introduce a mechanism to facilitate a more secure use of SSH for establishing remote command shells via connections through intermediate hosts. As before, an encrypted channel is established from host A and host B. As before, a connection is then opened from host B to host C. However, this connection is used to establish an encrypted channel between host A and host C, preventing the owner of host B from eavesdropping on or modifying its contents. The OpenBSD project's version of SSH, OpenSSH, supports those secure connections via intermediary hosts by configuring a sequence of port forwarding SSH connections. In the general case, SSH port forwarding allows a user process to make a TCP/IP connection to a specially configured SSH client which forwards communications from the user process to a server on a remote host via the SSH tunnel between the SSH client and SSH server. These four processes may be running on up to four separate hosts. Barring any application-dependent encryption between the user process and remote server, only the communications between the SSH client and SSH server are encrypted. When port forwarding is used for SSH hopping as described above, the user process is another SSH client process and the server on the remote host is an SSH server. In that case, the four processes are running on at least three hosts and the communications between the user process and its remote server are encrypted as they transit the intermediate host. Setting up such a port forwarding connection for SSH hopping involves spawning multiple SSH client processes at the command line. Although not difficult to set up, it does require some thought and a deeper knowledge of the SSH options than would be possessed by a casual user. In addition, the TCP/IP port provided by the specially configured SSH client process to be used for port forwarding is potentially accessible to other users on that host, which would give them access to the remote host. The SSH hop modifications described below seek to improve the usability of the SSH connection chaining to encourage use of a more secure connection strategy through intermediaries than might otherwise be used. Each host in the chain of encrypted connections from the source host to the ultimate destination host represents a single "hop". The authentication credentials are revealed only at the source host and at the host for which those credentials are intended. The following SSH hop command line syntax is provided to access the destination host (hostn) via a chain of hosts (...) with host1 as the first intermediate host in the chain: ssh [ssh_global_options] -H [ssh_local_options] [-p port1] [user1@]host1 ... -H [ssh_local_options] [-p portn] [usern@]hostn [command] The "ssh_global_options" and "ssh_local_options" represent any SSH options, other than -H, that are relevant in, respectively, the global and local contexts. The global options appear before the first -H in the command and are applied, as appropriate, to every hop in the chain. The effect is as if those options preceded every set of hop specific options for every hop in the chain. The local options follow a -H and are specific only to that one hop. For more information on which SSH options can be used as global options and which can be used as local options, please see the next section ("SSH option processing in conjunction with the -H option"). A host name or IP address must be provided following each -H. The user name of the account at each hop is determined by matching the first of the following rules to apply: 1) user name attached to the host name (e.g., -H user@host) 2) user name specified in the local options (using -l option) (e.g., -H -l user host) 3) user name specified in the global options (using -l option) (e.g., ssh -l user -H ...) 4) the name of the user account issuing the SSH command Example: +-------+ +------------+ +--------------------+ |student| | hobbes | | calvin | |@school| -----> |@gateway.com| -----> |@spaceship.world.net| +-------+ +------------+ +--------------------+ Suppose "student@school" wants to log into "spaceship.world.net" as "calvin" via his "hobbes" account at "gateway.com". The following command could be used: %school> ssh -l calvin -H hobbes@gateway.com -H spaceship.world.net That command will create a chain of subprocesses on the host "school" to construct two encrypted tunnels. The first encrypted tunnel will connect "student@school" to "hobbes@gateway.com". The second encrypted tunnel will connect "student@school" to "calvin@spaceship.world.net" via the first encrypted tunnel. To make SSH hopping more secure on the source host, support was also added for using Unix Domain Sockets, rather than TCP/IP sockets, for the ports on that host used for port forwarding (port forwarded ports). The disadvantage to using TCP/IP for the port forwarded port is that other users on the source host might be able to connect to the TCP/IP port and gain access to a remote host to which they should not have access. Unlike TCP/IP sockets, Unix Domain Sockets can be protected from access by users other than the one who created the port forwarding tunnel. By extension, the connection to the remote host will also be protected from unauthorized access. To support use of Unix Domain Sockets for port forwarding, two options were added to SSH. The -U and -u options were added to support use of Unix Domain Sockets for port forwarding. The syntax is as follows: -U ,, Local port forwarding information used for creating this connection. The parameters are: the path for the Unix Domain Socket (UDS) to be created, the remote host to which to authenticate, and the SSH port on the remote host. -u Path to the Unix Domain Socket (UDS) to which SSH should connect. The UDS will have been created from the -U option in a previous SSH command. Example: In the previous example, two encryption tunnels were created to connect "student@school" to "calvin@spaceship.world.net". The tunnels are created by spawning two subprocesses Those two subprocesses will be described next. The first subprocess creates an SSH tunnel from the "student" account on "school" to the "hobbes" account on "gateway.com". It runs in the background and prohibits use of stdin, remote commands, and X11 forwarding (-n -N -x). It also creates a Unix Domain Socket on the local host to be used for port forwarding (-U). As noted above, the -U option specifies the three parameters needed for port forwarding in a comma separated list. The Unix Domain Socket is created in the user's .ssh directory and its name contains information about the remote endpoint of the tunnel. Note that the remote account is calvin@spaceship.world.net and that the remote port for contacting the SSH daemon is the standard SSH port, 22. ssh -n -N -x \ -U ~/.ssh/.ssh_184_513_calvin@spaceship.world.net_22,calvin@spaceship.world.net,22 \ hobbes@gateway.world.com The second process creates a tunnel from the "student" account on "school" to the "calvin" account on "spaceship.world.net" through the tunnel from "student@school" to "hobbes@gateway.com". It forces allocation of a pseudo-tty (-t -t) for command line input and sets the name of the remote host (-o). If the name of the remote host is not set using the -o option, it will be shown as localhost since that is where the entry point for the forwarding port resides. The Unix Domain Socket created by the first process is used for accessing the remote machine (-u). If the Unix Domain Socket specified in the -u option does not exist, the second process will report an error and exit. ssh -t -t \ -u ~/.ssh/.ssh_1034_513_calvin@spaceship.world.net_22 \ -o HostKeyAlias=spaceship.world.net \ calvin@localhost Please see the ssh.1 man page for more information. ============================================================================= SSH option processing in conjunction with -H option. The following table contains a list of SSH options and how those options are handled in the global and local contexts. In general, the options are handled the same in both contexts. Keys to the symbols and terminology precede the table. --------------------------------------------------------------------- KEY: Column labels: Option = SSH command line option Global = options specified before the first -H option Local = options specified after a single -H option Symbols in Global and Local columns: f = only on first hop l = only on last hop y = all applicable hops Key to numbers in comment field: 1 - will be inserted by the top level (hopper) process to all but the last child 2 - will be inserted by the top level (hopper) process to all but the first child --------------------------------------------------------------------- Option Global Local Comments ------ ------ ----- --------------------------------------------- a y y A l y b f y c y y e l y f l l 1 g l l i y y I y y k y y l y y m y y n l l 1 N l l 1 o y y 2 for -o HostKeyAlias= p y* y* Apply when port not previously specified. Order of precedence for port assignment: 1) first local p 2) first global p 3) default SSH port P y y Deprecated but still supported (use privileged port) q y y s l l t l l T l l v y y x l l 1 X l l Y l l C y y F y y L l l R l l D l l U l l 1 u f f 2 O l l M l l S l l 1 y y 2 y y 4 y y 6 y y ============================================================================= TODO: 1) SCP 2) SFTP ============================================================================= Overview of changes to the source files: Makefile.in =========== Added target for sshhop_test. Added sshhop.o to dependency list and object list for sshhop_test and ssh. README.sshhop ============= New. This file. channels.c ========== Added function port_open_helper_base(). Additional cleanup added for unix domain sockets. Function port_open_helper() functions as previously but the bulk of the code now resides in port_open_helper_base() which is invoked from port_open_helper() or directly. Port_open_helper_base() is called directly to omit looking up the ip address and port when Unix Domain Sockets are in use. The original function channel_setup_fwd_listener() is renamed channel_setup_fwd_port_listener(). A new function channel_setup_fwd_uds_listener() is added to handle processing for Unix Domain Sockets. The new channel_setup_fwd_listener() function calls one of two functions: channel_setup_fwd_port_listener() and channel_setup_fwd_uds_listener() depending on whether ports or unix domain sockets are being used. channels.h ========== Added fwd_path to Channel structure to support use of Unix Domain Sockets for port forwarding. clientloop.c ============ Added remote prompt id flag to read_passphrase() call. misc.c ====== Added #include "pathnames.h". Needed for new construct_uds_path() function. Added comma (,) as separator for forwarding information. Colon (:) and slash (/) could both be used in a unix domain socket designator and thus cannot be used as separators. Added function construct_uds_path() used to ensure a consistent naming convention for Unix Domain Sockets. misc.h ====== Added function declaration for construct_uds_path(). Added bit code for remote prompt id flag. readconf.c ========== Added configuration options: "PrivateLocalForward" (takes a UDS path as the forwarding port) "UnixDomainSocket" (UnixDomainSocket to which to connect) Added handling of listen_port value when Unix Domain Socket specified (i.e., listen_port < 0). readconf.h ========== Revised information on listen_port (to reflect use with Unix Domain Sockets). Added uds_path configuration parameter. readpass.c ========== Added function add_id_to_prompt() to add remote process id to prompt. Added conditional to call add_id_to_prompt() if RP_ADD_ID flag is set. scard.c ======= Added remote prompt id flag to read_passphrase() call. ssh.1 ===== Added descriptions of new options (-u -U -H) and new config parameters (PrivateLocalForward and UnixDomainSocket) ssh.c ===== Declared variables static that are used only in scope of ssh.c Updated usage information to reflect new usage (-H option). Moved option parsing from main() into new function parse_options() (the diff output is somewhat confusing since lines from main() show up as being deleted from parse_options() and then added to the "new" main()). Use SSH_CMD_LINE_OPTIONS #define for option list so it can be shared with code in sshhop.c Added -u and -U options. Added check for config option for uds_path variable. Added call to sshop_parse_options() and additional processing if multiple hops were specified. Functions to support processing of multiple hop information are all located in sshhop.c (new). If no -H options (no hop processing) is indicated then options are parsed and the program continues as before. Added tilde expansion check for uds path. Modified connection logic to handle UDS connection. ssh.h ===== Added SSH_CMDLINE_OPTIONS sshconnect.c ============ Added function ssh_connect_uds() to support using a Unix Domain Socket as a connection endpoint instead of a regular socket. The Unix Domain Socket is a protected resource of an individual rather than a resource that may be accessible to any user on the machine. Added remote prompt id flag to read_passphrase() call. Added AF_UNIX processing to check_host_key() to support use of Unix Domain Sockets for port forwarding: a) new case (AF_UNIX) added to switch and b) conditional based on the address family added when no proxy command. sshconnect.h ============ Added function declaration for ssh_connect_uds(). sshconnect1.c ============ Added remote prompt id flag to read_passphrase() calls. sshconnect2.c ============ Includes patch supplied by openSSH folks to provide hostname in prompt (patch is not included in openSSH distribution). Added remote prompt id flag to read_passphrase() calls. sshhop.c ======== New. Contains command line processing for new -H option. Contains functions for properly configuring argument lists for multiple SSH subprocesses, functions for starting the SSH subprocesses, and functions for terminating the multiple SSH subprocesses. The top-level control for the multiple hop processing is in ssh.c. sshhop.h ======== New. Function declarations for functions used in sshhop.c sshhop_test.c ============= New. Program to test sshhop.c functionality outside of ssh.