Secure Shell: Part 1

By Amy Rich

With sniffing and cracking at an all time high, security-conscious system administrators recognize that sending clear text passwords across the network is a luxury of the past. Even sensitive information between machines in the same company often needs to be protected from unauthorized employees. The most common solution to this problem involves replacing the "r" commands (rsh, rlogin, rcp), telnet, and ftp with a suite of tools collectively known as Secure Shell. Secure Shell provides secure encrypted communications between two untrusted hosts over an insecure network.

While this series of articles will specifically cover the OpenSSH distribution, most of the information is also applicable to the Secure Shell packages included with Solaris 9 Operating Environment.


A Bit of History

After his network was the target of a password sniffing attack in 1995, Tatu Ylönen, a researcher at the Helsinki University of Technology in Finland, developed the SSH1 protocol to protect his passwords and data. Later that year, he released the SSH-1 (SSHv1) protocol to the general public as freeware and submitted an IETF Internet Draft.

The SSH-1 protocol soon became wildly popular, and Ylönen formed SSH Communications Security, Ltd. (SCS) to handle the flood of user questions, requests, and bug fixes. Unfortunately, several insecurities and limitations inherent in the SSH-1 protocol proved to be unfixable while still retaining backwards compatibility, so SCS introduced a new protocol, SSH-2 (SSHv2), in 1996.

When SCS released later versions of Secure Shell based on the SSH-1 protocol and then the new versions of Secure Shell based on the SSH-2 protocol in 1998, it tightened the license restrictions and required commercial entities to pay a licensing fee. As a result, many companies declined to move to the more secure version of the protocol.

Early in 1999, Björn Grönvall rediscovered the last free version of SCS's Secure Shell (ssh-1.2.12), fixed some bugs, and released his own copy of the code, named OSSH. However, OSSH only had support for SSHv1.3, so many people still remained with older versions of YlPH*PH*PH\uFFFDPH*PH*PHnen's original code.

Later that same year, the OpenBSD project became aware of Björn's distribution and forked off yet another branch, creating OpenSSH. The OpenSSH team included support for both the SSH-1 and SSH-2 protocols (SSHv1.3, SSHv1.5, and SSHv2), added many security enhancements, and increased portability. Because of the licensing freedom, good support, and continuing development, OpenSSH remains the most popular Secure Shell distribution today.

Recognizing the need for secure sessions and the popularity of OpenSSH, Sun Microsystems, Inc. started distributing its own Secure Shell packages with the Solaris 9 Operating Environment. The Solaris 9 OE cluster SUNWCssh contains the following packages:

  SUNWsshcu        SSH Common, (Usr)
  SUNWsshdr        SSH Server, (Root)
  SUNWsshdu        SSH Server, (Usr)
  SUNWsshr         SSH Client and utilities, (Root)
  SUNWsshu         SSH Client and utilities, (Usr)

The majority of Sun's Secure Shell distribution is based on the OpenSSH 2.9 source code tree and therefore bears much resemblance to this older version. Since Sun maintains its own source code tree, however, it lacks some of the newer features, such as privilege separation, included in current versions of OpenSSH. Sun has also continued development on its fork of Secure Shell, adding in support for BSM auditing, I18N/L10N support and two proxy commands, SOCKS5 and HTTP. While running straight OpenSSH in heterogeneous environments might prove easier, Sun only provides customer support for its own Secure Shell packages.


Overview of OpenSSH

Programs

OpenSSH automatically and transparently encrypts all traffic (including passwords) to effectively eliminate eavesdropping, connection hijacking, and other network-level attacks. It accepts password, rhost/shost, skey, kerberos, and public key authentication. Additionally, OpenSSH provides a myriad of secure tunneling capabilities and tcp-wrapper compatibility. OpenSSH consists of the following client, server, and helper programs:

sshd(8) This program is started from an rc script at boot time and runs as a daemon on the server machine. The daemon listens for connections from client machines, performs authentication, and starts serving the client whenever it receives a connection.
ssh(1) This client program is invoked by users to log into another machine or to execute commands on another machine. This program can also be invoked as slogin.
scp(1) This program is a replacement for rcp that securely copies files from one machine to another.
ssh-keygen(1) This program creates public key authentication (RSA1, RSA, or DSA) keys for use with the ssh(1) and sshd(8) programs.
ssh-agent(1) This program is run by a user to hold private keys for authentication.
ssh-add(1) This program registers new keys with the ssh agent.
sftp-server(8) This program is a limited replacement for the ftp daemon.
sftp(1) This program is a limited ftp client replacement.
ssh-keyscan(1) This program is a utility for gathering the public ssh host keys of a number of hosts. It was designed to aid in building and verifying ssh_known_hosts files. ssh-keyscan provides a minimal interface suitable for use by shell and perl scripts.
ssh-keysign(8) This program is used by ssh(1) to access the local host keys and generate the digital signature required during host-based authentication with SSHv2.

Configuration, Data, and Resource Files
In addition to the above programs, OpenSSH can be configured to consult a number of configuration, data, and resource files:

/var/run/sshd.pid This file contains the process ID of the parent sshd process.
/etc/rc0.d/K03sshd
/etc/rc1.d/K03sshd
/etc/rc2.d/K03sshd
/etc/rc3.d/S89sshd
/etc/rcS.d/K03sshd
/etc/init.d/sshd
These files are Solaris start and stop scripts. They are provided with Sun's secure shell packages, or you can create your own for use with OpenSSH.
/etc/nologin If this world readable file exists, sshd refuses to let anyone except root log in. The contents of this file are displayed to anyone attempting a non-root connection.
/etc/hosts.allow
/etc/hosts.deny
If compiled with LIBWRAP support, tcp-wrappers access controls may be defined here as described in the hosts_access(5) man page.
/etc/hosts.equiv This file is used during .rhosts authentication.
/etc/shosts.equiv This is processed exactly as /etc/hosts.equiv. However, this file may be useful in environments that want to run both rsh/rlogin and ssh.
/etc/sshrc If this file exists and $HOME/.ssh/rc does not, it is run with /bin/sh after reading the environment files but before starting the user's shell or command. This file can be used to globally specify machine-specific login-time initializations.
sshd_config Contains configuration data for the ssh daemon, sshd. This file is commonly found in /etc, /etc/ssh, or /usr/local/etc.
ssh_host_key Contains the private part of the machine host key. This file should be owned and only accessible by root. The ssh daemon will not start if this file is group/world-accessible. Additional key files can be specified in the sshd_config file. These files are commonly found in /etc, /etc/ssh, or /usr/local/etc.
ssh_host_key.pub Contains the public part of the machine host key. This file should be world-readable but writable only by root. Additional key files can be specified in the sshd_config file. These files are commonly found in /etc, /etc/ssh, or /usr/local/etc.
ssh_known_hosts
$HOME/.ssh/known_hosts
These files are consulted when using rhosts with RSA host authentication to check the public key of the host. The key must be listed in one of these files to be accepted. ssh_known_hosts should be world-readable, and $HOME/.ssh/known_hosts can (but need not be) world-readable. ssh_known_hosts is commonly found in /etc, /etc/ssh, or /usr/local/etc.
$HOME/.ssh/authorized_keys Lists the public RSA keys that can be used to log into the user's account.
$HOME/.ssh/authorized_keys2 Lists the public DSA keys that can be used to log into the user's account.
$HOME/.rhosts This file, used with rhost authentication, contains host-username pairs, separated by a space, one per line. It is also possible to use netgroups in the file. Either host or user name may be of the form +@groupname to specify all hosts or all users in the group.
$HOME/.shosts For ssh, this file is exactly the same as for .rhosts. However, this file is not used by rlogin and rshd, so using this permits access using SSH only.
$HOME/.ssh/environment If it exists, this file is read into the environment at login. It can only contain empty lines, comment lines, and assignment lines of the form name=value.
$HOME/.ssh/rc If this file exists, it is run with /bin/sh after reading the environment files but before starting the user's shell or command. The primary purpose of this file is to run any initialization routines that may be needed before the user's home directory becomes accessible; AFS is a particular example of such an environment.

The default installation of OpenSSH works out of the box, but a number of options exist for site-specific customization. Reading the man pages for each of the above programs and the sshd_config and ssh_config files provides a great deal of insight for basic OpenSSH configuration.


Setting Up Public Key Authentication

One of the best ways to start extending the use of ssh is to move beyond basic password-authenticated sessions and configure public key authentication. Public key authentication, an alternative to password and host-based authentication methods, uses cryptographic keys to verify a user's identity. Public key authentication affords more flexibility and security than any other form of authentication that ssh offers. Disabling other, less secure, authentication methods in sshd_config is highly recommended.

Under OpenSSH, three types of keys are allowed, RSA for SSHv1 (SSHv1 should be avoided because of security concerns and disabled in sshd_config), RSA for SSHv2, and DSA for SSHv2. On the local machine, users may generate a default key for each type they wish to use:







Each of these commands will ask for a pass phrase, which is then associated with that key unless changed with the -p flag to ssh-keygen:   ssh-keygen -p -f $HOME/.ssh/id_dsa

When using public key-based authentication, the remote machine requires a copy of the local public key. Copy the contents of the public key on the local system to the file $HOME/.ssh/authorized_keys on the remote system. When logging in to the remote system, the user now types in the pass phrase to authenticate. To increase security and cut down on the amount of typing required, use an agent.


Using SSH Agents

An SSH agent caches private keys in memory as plaintext, requiring users to only type in a pass phrase once for each key. When using an agent, authentication pass phrases never traverse the network, providing additional security. There are two programs associated with an agent: ssh-agent and ssh-add. ssh-agent acts as the key repository (sometimes referred to as the "key ring"), and ssh-add adds existing private RSA and/or DSA keys to this repository.

When invoked, ssh-agent creates an empty repository by making a UNIX-domain socket and forking into the background. When using ssh-agent as part of an interactive session, it is typically called at the very beginning of the session so that the agent environment is inherited by all programs and sub-shells. The user can invoke ssh-add from the command line or from shell initialization files, but the largest benefit usually comes from running ssh-agent before starting an X session. If the user runs xdm and uses .xinitrc to set up the environment, replace the user's .xinitrc file with the following instead:

  #!/bin/sh
  # redirect errors to a file for debugging
  if ( cp /dev/null ${TMPDIR}/{$USER}.xsession-errors 2> /dev/null )
  then
    chmod 600 ${TMPDIR}/${USER}.xsession-errors
    exec > ${TMPDIR}/${USER}.xsession-errors 2>&1
  fi
 
  if [ -f ${HOME}/.xsession ]
  then
    exec ${SHELL} ${HOME}/.xsession
  fi

The .xsession file then needs lines to stop and start the agent. Here's a short example .xsession file written for tcsh (the syntax is different if using a bourne style shell) that runs the window manager ctwm and brings up one xterm:

#!/usr/local/bin/tcsh

  # Check to see if an agent is already running.  If not, start one.
  if ( ! ${?SSH_AGENT_PID} && ! ${?SSH2_AGENT_PID} ) then
    eval `ssh-agent -c` > /dev/null
  endif

  xrdb .Xdefaults
  xterm -sb -sl 6000 -ut -vb -T 'Xterm' &
  ctwm -W

  # Now that the session is terminated, kill the associated agent.
  if ( ${?SSH_AGENT_PID} ) then
    kill -15 ${SSH_AGENT_PID}
  else if ( ${?SSH2_AGENT_PID} ) then
    kill -15 ${SSH2_AGENT_PID}
  endif

If using a vendor's stock window manager and not .xinitrc, there's usually someplace within the window manager config files to add comparable lines. For example, Sun Secure Shell product documentation suggests the following if running CDE:

To start the agent daemon automatically, add the following lines to the end of the $HOME/.dtprofile script:

  if [ "$SSH_AUTH_SOCK" = "" -a -x /usr/bin/ssh-agent ]; then
    eval `/usr/bin/ssh-agent`
  fi

To terminate the Secure Shell agent daemon when exiting the CDE session, add the following to the $HOME/.dt/sessions/sessionexit script:

  if [ "$SSH_AGENT_PID" != "" -a -x /usr/bin/ssh-agent ]; then
    /usr/bin/ssh-agent -k
  fi

Now, when logging in via xdm, the agent runs and the environment variables SSH_AUTH_SOCK and SSH_AGENT_PID obtain the appropriate values. There are no keys in the repository at this point. Any new processes started within the X session inherit the environment and have access to the UNIX-domain socket and any later added keys. From the existing xterm (or any subsequently opened terminal), run ssh-add and type in the pass phrase for each key when prompted. A shell startup script could include a few lines to invoke ssh-add automatically. The code below assumes that all keys are in $HOME/.ssh/keys and that the user's shell is tcsh. Add the following to the .tcshrc or .cshrc:

  # skip remaining setup if not an interactive shell
  if ($?USER == 0 || $?prompt == 0) exit
  # see if the agent is running, but without any keys
    if ( `ssh-add -l` == "The agent has no identities." ) then
  # If so, cd into the key dir and add everything that doesn't end with .pub
      pushd $HOME/.ssh/keys
      foreach key (`ls|grep -v '\.pub$'`)
        ssh-add $key
      end
  # go back to the previous
      popd
    endif
  endif


Generating Multiple Keys

Much can be gained from having multiple keys, especially for role-based accounts like root or operator. If a user creates multiple keys for different remote hosts, only a subset of hosts is vulnerable if a key is compromised. Assigning an additional pass phrase-less key to root allows for the running of jobs from cron while still maintaining the security of a pass phrase on root's default key. Multiple keys can also allow remote machines to only execute specific commands based on the key, allowing one account to automate various different tasks securely.

Generating additional RSA and DSA keys is easy using ssh-keygen. If additional DSA keys for two separate networks are required because of security reasons, generate them with the following commands:

  ssh-keygen -t dsa -f $HOME/.ssh/network-a
  ssh-keygen -t dsa -f $HOME/.ssh/network-b

This creates the private keys $HOME/.ssh/network-a and $HOME/.ssh/network-b and the corresponding public keys $HOME/.ssh/network-a.pub and $HOME/.ssh/network-b.pub. Add the appropriate public key to the $HOME/.ssh/authorized_keys file on the client, network-a-machine, then specify the desired key when running ssh from the command line:

  ssh -i $HOME/.ssh/network-a network-a-machine

If using ssh-agent, add each of these two additional keys and the agent will automatically handle selecting the correct key for the corresponding machines:

  ssh-add $HOME/.ssh/network-a
  ssh-add $HOME/.ssh/network-b
  ssh network-a-machine         # automatically picks the key for network-a

If multiple valid keys exist for one host, it's best not to load those keys into an agent. The agent always selects the first key that authenticates -- regardless of whether or not it was the desired key.


What's Next?

In the next article, I'll look at using ssh for system administration tasks. I'll cover restricting privileges on public key authentication using the authorized_hosts file, task-specific keys, using the local and remote port forwarding features, and using ssh from cron.


Resources

For further information about OpenSSH and the Secure Shell provided with Solaris, visit the following resources:


Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) is provided under this License.


Left Curve
Popular Downloads
Right Curve
Left Curve
More Systems Downloads
Right Curve