The secure shell (SSH) is a popular replacement for earlier remote login tools such as telnet and rlogin. The biggest advantages of SSH over these earlier tools is that all traffic between client and server is encrypted, and the server's identity is securely verified. The implementation of secure shell used on Linux is called OpenSSH.

The OpenSSH server (sshd) listens on port 22 by default. On some Linux distributions the server is installed and running by default; on others it will need to be installed using the package management tools. The client-side pieces of ssh (commands such as ssh, ssh-keygen, ssh-agent, and ssh-add) are usually installed by default.

SSH uses public/private key encryption technology to securely authenticate the server when a connection is made. This authentication handshake also performs a secure exchange of a shared secret key that is used to encrypt all subsequent traffic between the client and the server. The figure below illustrates the difference between symmetric cryptography (using a shared secret key) and asymmetric cryptography (using a public and private key pair).

Figure 110.3-1: Symmetric and asymmetric cryptography

SSH Host Authentication

When the openssh server is installed, a public/private key pair is generated for that machine. Actually, two key pairs are generated: a DSA key pair and an RSA key pair. (DSA and RSA are just the names of two asymmetric cryptography technologies.) The private keys are stored in /etc/ssh/ssh_host_rsa_key and /etc/ssh/ssh_host_dsa_key; these files are readable only by root. The public keys are stored in /etc/ssh/ssh_host_rsa_key.pub and /etc/ssh/ssh_host_dsa_key.pub. These keys are summarised in the figure below.

Figure 110.3-2: Public and private server keys

These keys are used to securely verify the identity of the server machine, and to set up an encrypted channel via a key exchange protocol. The server's public key needs to be available on any client that needs to connect. It can be copied into place on the client by the system administrator (into the file /etc/ssh/ssh_known_hosts). Your distribution may have a utility called ssh-keyscan to help with this. Alternatively, when an ssh client connects to a server, the server will offer the host's public key. At this stage the user will be prompted with something like this:

# ssh chris@192.168.81.1

The authenticity of host '192.168.81.1 (192.168.81.1)' can't be established.

However, most users simply trust that they are connecting to the correct server (and not an imposter) and simply answer yes to accept and continue the connection. At this point, the server’s public key will be added to the local ~/.ssh/known_hosts file. Obviously, this file is "per-user" – it only applies to the user who logged in.

Once the server's public key is known to the client, the "are you sure you want to continue" message will not appear again.

OpenSSH supports several mechanisms to authenticate the user. By default, on most Linux distributions ssh is configured to support simple password-based authentication – the user is prompted for the password for his account on the remote server and logs in. Note, however, that this password travels across an encrypted channel to the server and is not subject to being stolen by an eavesdropper.

A user can also be authenticated using a public/private key pair, in much the same way that an SSH server authenticates to the client when the initial connection is made. For this to work, the user must first generate himself a key pair, then he must copy the public key of the pair onto any server on which he needs to authenticate.

will generate a DSA key. By default these keys will be saved in ~/.ssh/id_dsa and ~/.ssh/id_dsa.pub If RSA keys are generated they would be stored in ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub . Note that the user has the option to protect the private key with a pass-phrase. He may choose not to use a passphrase by simply pressing 'Enter' at this prompt.

The file containing the public key will need to be copied onto the server (using scp for example) and added to the file ~/.ssh/authorized_keys in the user's home directory on the server, as shown in the figure below. Your distribution may include a handy script called ssh-copy-id which automates this process:

$ ssh-copy-id -i .ssh/id_dsa.pub chris@192.168.81.1

chris@192.168.81.1's password:

Now try logging into the machine, with "ssh 'chris@192.168.81.1'", and check in:

.ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

This script will create the ~/.ssh directory and the authorized_keys file on the remote machine if necessary, and set their permissions correctly. If the authorized_keys file already exists, the key will be appended to it.

The management of user keys is summarised in the figure below.

Figure 110.3-3: SSH user public and private keys

With this key in place, if the user did not set a pass-phrase on his private key he can now perform a password-less ssh login to the server. However, if he did set a passphrase, he will be prompted for it at this point:

$ ssh 192.168.81.1

Enter passphrase for key '/home/chris/.ssh/id_dsa':

Last login: Tue Sep 28 12:01:42 2010 from m1530-rhel.local

Note: The permissions on the files are important. All files holding private keys should be mode 600. The ~/.ssh directory should have mode 700. ssh will refuse to use these files if the permissions are too lax.

To avoid the inconvenience of having to supply a passphrase to unlock your private key during ssh login, the program ssh-agent can be used to hold the passphrase and supply it automatically when required. You supply your passphrase to the agent just once, and the agent will give the keys out to other processes owned by you on request.

The following dialog starts ssh-agent and adds your identities to it:

$ eval $(ssh-agent)

Agent pid 22305

$ ssh-add

Enter passphrase for /home/chris/.ssh/id_dsa:

Identity added: /home/chris/.ssh/id_dsa (/home/chris/.ssh/id_dsa)

Now, you should be able to perform a secure but password-free login to any server that has a copy of your public user key.

The strange use of command substitution and the eval command to start ssh-agent arises because ssh-agent reports some environment variables on its standard output which the process needs to know in order to contact the agent. This 'trick' allows us to propagates these variable back into the shell. Note that the older command substitution syntax uses back-quotes like this: eval `ssh-agent`

Client-side ssh commands

Once configured, the end-user experience of SSH is straightforward. Some sample commands are shown in the table below.

Table: Sample ssh commands

Command

What it does

$ ssh neptune

Log in on machine neptune using the local user account name

$ ssh brian@neptune

Log in on machine neptune as user brian

$ ssh neptune date

Run a single command on neptune

$ scp foo neptune:

Copy the local file foo into your home directory on neptune

$ scp foo neptune:/tmp/foo

Copy local file foo to the specified path name on neptune

$ scp neptune:/tmp/foo .

Copy /tmp/foo from neptune into your home directory on the local machine

ssh has a useful feature called remote port forwarding, that allows the remote ssh server to listen for connections on any specified port and forward the traffic through an encrypted ssh tunnel to a specified port on the local machine. In the top half of the figure shown below, a user on machine mercury has run the command:

$ ssh -R 4023:mercury:23 venus

Then on machine earth, a user runs telnet, connecting to port 4023 on venus. Port forwarding means that the traffic is secure, and that the only port that needs to be open for connections on the server is port 22. In practice, 'venus' and 'earth' are often the same machine.

Local port forwarding is similar but it's the client that forwards the traffic, not the server. In the bottom half of the figure a user on mercury has run the command:

$ ssh -L 8080:earth:80 venus

(Again, 'venus' and 'earth' are often the same machine.) We can then browse securely through an encrypted channel by directing our browser to localhost:8080.

Figure 110.3-4: Local and remote port forwarding

As a "special case" of port forwarding, ssh can arrange to carry X traffic from a remote graphical application back to the X server on the local machine. This is known as X11 forwarding. The following command:

$ ssh -X neptune xcalc

runs xcalc on the machine neptune and arranges for it to display on the X server on the local machines. Behind the scenes, sshd acts as a proxy X server and forwards all X traffic down the encrypted channel back to the client. In addition, the DISPLAY environment variable is set to direct the xcalc program to the proxy server. The operation is illustrated below:

GPG (Gnu Privacy Guard) is a re-write of the original PGP software. It uses a combination of symmetric and asymmetric cryptography to provide secure communication between two parties. GPG also provides tools for key management.

At the heart of GPG is a command line tool called gpg, that handles the basic tasks of signing, encrypting and decrypting messages, and also handles key management. (Many email programs have plugins to encrypt, sign and decrypt email that use this command-line tool behind the scenes.) To illustrate its use, suppose Alex wants to communicate securely with Beth.

Here, we have chosen DSA and Elgamal keys and a DSA key size of 2048 bits. We have supplied a passphrase to protect our secret key. We have provided a name, email address and comment which were used to construct a "User ID" which identifies whose key this is in a human-friendly way.

The public and private keys are placed in files in the .gnupg directory:

$ ls -l .gnupg

total 32

-rw------- 1 alex alex 9207 Sep 28 13:28 gpg.conf

-rw------- 1 alex alex 1178 Sep 28 13:35 pubring.gpg

-rw------- 1 alex alex 1178 Sep 28 13:35 pubring.gpg~

-rw------- 1 alex alex 600 Sep 28 13:35 random_seed

-rw------- 1 alex alex 1327 Sep 28 13:35 secring.gpg

-rw------- 1 alex alex 1280 Sep 28 13:35 trustdb.gpg

Alex then exports his public key to an ascii file like this:

$ gpg --export --armor -o alex.pub Alex

"Armoring" a key simply means representing it in an ascii form that could (for example) be printed out or transmitted as the text of an email. The final argument of the command ('Alex') is a fragment of the key's User ID, sufficient to identify the key. The file he ended up with, alex.pub, is the one he plans to give to Beth.

Beth goes through the same process, generating her own key pair and her own passphrase, and exporting the public key into a file call beth.pub ready to give to Alex.

Alex and Beth now exchange their public GPG keys. Alex copies Beth's file to his computer and imports it into his GPG keyring like this:

$ gpg --import beth.pub

Beth similarly imports Alex's public key into her keyring.

At this point, if Alex lists his keys he will see the public half of his own key, and the one he imported from Beth:

$ gpg --list-keys

/home/alex/.gnupg/pubring.gpg

-----------------------------

pub 2048D/B4DF979C 2010-08-02 [expires: 2010-08-30]

uid Alex Example (Demo User A) <alex@example.com>

sub 2048g/626C246D 2010-08-02 [expires: 2010-08-30]

pub 2048D/F6CA4978 2010-08-02 [expires: 2010-08-30]

uid Beth Example (Demo User B) <beth@example.com>

sub 2048g/07DFB736 2010-08-02 [expires: 2010-08-30]

There's one more thing Alex needs to do before he can use Beth's public key to send her a confidential message. He needs to sign Beth's key to say that he believes it really is hers:

$ gpg --sign-key Beth

Alex can now use Beth's public key to send her an encrypted message:

$ gpg --encrypt --armor --recipient Beth secret.txt

In this command Beth is any part of the key ID, sufficient to identify this key uniquely. At this point Alex has an encrypted file called secret.txt.asc which he can email to Beth. He knows that only Beth can read it, because only she knows the private key corresponding to the public key Alex encrypted it with.

Alex's key pair is also important. He has already used his private key to sign (declare his trust in) Beth's public key. His public key, of course, would be used to encrypt a reply from Beth back to Alex.

Alex signs his message by creating a hash of the message and encrypting it with his private key. On receipt, Beth can decrypt the hash (using Alex's public key), compute her own hash of the message, and compare the two. If they match, Beth has high confidence that the message came from Alex and that it has not been modified since it was signed. Note that digital signatures do not provide confidentiality – that is, they do not encrypt the message. gpg hides the complexity behind a simple command option (--sign). It's possible for Alex to both encrypt and sign the message:

$ gpg --encrypt --sign --armor --recipient Beth secret.txt

Then, when Beth decrypts it, the signature will automatically be checked. (At the end of the earlier example, note the report of whose public key the message was encrypted with, whose private key it was signed with, and that the signature matches the message.

GPG also supports its own public key infrastructure using a "web of trust" but that is beyond our present scope.

How PGP works

PGP uses a hybrid of symmetric and asymmetric cryptography. A random session key (used only for this one message) is chosen and is encrypted with the recipient's public key. The result is sent as part of the message. The session key is then used to encrypt the sender's plain text using a symmetric cipher (IDEA, by default) and the result is attached to the message. The recipient decrypts the session key using her private key, then uses it to decrypt the body of the message.

This approach has several advantages: first, symmetric ciphers are much faster to compute, and don't need such long keys. Also, if an eavesdropper does crack the session key, it won't help him read any subsequent messages. Finally, because the asymmetric cipher is used only to encrypt a short (and random) value, a cryptanalyst would have very little hope of cracking it.

Figure 110.3-6: How PGP works

The following is a partial list of the used files, terms and objectives: