ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


FreeBSD Basics The SSH Cryptosystem

by Dru Lavigne
11/14/2002

In the last article, you learned that a cryptosystem is used to protect the privacy, integrity, and authenticity of data as it traverses a network. In today's article, we'll see how the SSH cryptosystem provides these features.

If you're using at least FreeBSD version 4.0, your FreeBSD system uses OpensSSH and it is installed and ready to go. As the name implies, this is an open source implementation of the SSH cryptosystem. You can read more about it at the OpenSSH website.

In a previous article (see IP Packets Revealed), I demonstrated that the telnet utility can be used to login to a remote computer from another system. Once logged in, a user can do anything on that remote system as if he were physically sitting in front of it. That is, every keystroke is sent to the remote system and interpreted as if it had come from the keyboard attached to that remote system (even though that keyboard input first had to travel over a network). We also saw in that article that every single keystroke and response was sent in clear text, meaning that a sniffer could watch the entire session.

Related Reading

SSH, The Secure Shell: The Definitive Guide
By Daniel J. Barrett, Richard E. Silverman

Any SSH cryptosystem will allow a user to login to a remote system and work just as if he were physically there. However, before the user is given a login prompt, a key will be generated to encrypt and decrypt all of the data that will be passed between the two computers. That is, more is happening behind the scenes.

Since SSH is used to access another computer, a user account must exist on the computer to be accessed. Additionally, the computer being accessed is known as the SSH server and must be running the SSH daemon; by default, this daemon listens on TCP port 22. The machine you are sitting at is known as the SSH client; it will contact the daemon on the other machine.

Your FreeBSD system has default configurations that allow you to use SSH as is. I'll demonstrate the default configuration first, then move on to some changes you may wish to make to increase the security of SSH.

I'll be using two computers. 10.0.0.1 will be the SSH daemon, the computer I wish to access, and 10.0.0.2 will be the SSH client, the computer I'm sitting at. On both systems, I have created a user account called "genisis". You'll note that the cryptosystem is called OpenSSH. It uses a protocol usually written as uppercase SSH, and the commands you type, ssh and sshd, are written in lowercase. Also, you can use the ssh command to access either an IP address or a hostname. In this week's article, I'll purposefully use IP addresses. In the next article I'll take a closer look at name resolution issues when using SSH.

First, I need to check if the host keys have been created on the system that will be the server. At 10.0.0.1, I'll run this command:

ls /etc/ssh

If I get this output:

moduli			ssh_host_dsa_key.pub	ssh_host_rsa_key
ssh_config		ssh_host_key		ssh_host_rsa_key.pub
ssh_host_dsa_key	ssh_host_key.pub	sshd_config

I have the necessary keys. However, if I instead get this output:

moduli		ssh_config	sshd_config

there aren't any host keys and I will need to generate them before I can start the SSH daemon. If I'm impatient and try to start the SSH daemon before creating the keys, it will refuse to start and I'll instead receive this error message:

sshd
Could not load host key: /etc/ssh/ssh_host_key
Could not load host key: /etc/ssh/ssh_host_dsa_key
Disabling protocol version 1. Could not load host key
Disabling protocol version 2. Could not load host key
sshd: no hostkeys available -- exiting.

There are several ways to generate those missing keys. If you are an advanced user who is comfortable with reading startup scripts, search for ssh in /etc/rc.network to see which commands your FreeBSD system uses to generate the host keys. I'll instead demonstrate the results of running that script. The easiest way to ensure the necessary keys are generated and that SSH starts whenever the system reboots is to add the following line to /etc/rc.conf:

sshd_enable="YES"

Once I've saved my changes, I'll type:

shutdown now

When I get a prompt back, I'll press enter and then type the word exit. As my startup scripts are reinitialized, I see the following message:

Starting final network daemons: creating ssh1 RSA host key
Generating public/private rsa1 key pair.
Your identification has been saved in /etc/ssh/ssh_host_key.
Your public key has been saved in /etc/ ssh/ssh_host_key.pub.
The key fingerprint is:
12:d9:3d:f3:95:92:0e:e7:6b:54:09:80:77:a0:3e:cf root@hostname
creating ssh2 RSA host key
Generating public/private rsa key pair.
Your identification has been saved in /etc/ssh/ssh_host_rsa_key.
Your public key has been saved in /etc/ssh/ssh_host_rsa_key.pub.
The key fingerprint is:
4b:cf:7e:af:f1:a8:01:08:64:1b:c0:79:e3:a2:58:78 root@hostname
creating ssh2 DSA host key
Generating public/private dsa key pair.
Your identification has been saved in /etc/ssh/ssh_host_dsa_key.
Your public key has been saved in /etc/ssh/ssh_host_dsa_key.pub.
The key fingerprint is:
22:69:d7:05:23:c6:db:d9:55:2a:20:a3:34:bd:f4:ef root@hostname

Let's take a look at that output. You'll note that three separate key pairs were generated: one for rsa1, one for rsa, and one for dsa. You should recognize the RSA and DSA acronyms from the last article on cryptographic terms. But why so many key pairs? There are two versions of the SSH protocol, and OpenSSH supports them both. Not surprisingly, the rsa1 keypair is used by SSH version 1. You can see from the output that ssh2 (version 2) supports both RSA and DSA.

Each key in a key pair is stored in a separate file. You can identify the public key files, as they have a .pub extension. Additionally, each public key has an associated fingerprint which is unique to that key. We'll see that fingerprint again.

Not only were the necessary keys generated, the SSH daemon was also started. This can be verified with the sockstat command:

sockstat |grep ssh

root     sshd     69820    3 tcp4   *:22                  *:*                  
root     sshd     69820    3 tcp46  *:22                  *:*

Okay, now that 10.0.0.1 is listening on port 22, let's see what happens when I use the ssh command from 10.0.0.2 as the user genisis:

ssh 10.0.0.1
The authenticity of host '10.0.0.1 (10.0.0.1)' can't be established.
DSA key fingerprint is 22:69:d7:05:23:c6:db:d9:55:2a:20:a3:34:bd:f4:ef.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.0.1' (DSA) to the list of known hosts.
Password:

Once I type the correct password for the user genisis, I'll receive my motd and customized prompt. I'll then type "exit" to leave the session:

exit
logout
Connection to 10.0.0.1 closed.

I'll now repeat a second time:

ssh 10.0.0.1
Password:

Let's pick apart what happened here. The very first time I used SSH, I was asked to verify the fingerprint of the server's DSA public key. Once I doublechecked that it was correct and typed yes, a copy of the server's public key was placed on the client or 10.0.0.2:

more ~genisis/.ssh/known_hosts
10.0.0.1 ssh-dss AAAAB3NzaC1kc3MAAACBAPiOFgV4PpsbXfkaxGD+hCr02Cv9P3OJDKfaXge059
cSohLN/n/kd2Nz/E1mDvT4Y8nSAQL7M667iMeqJ0WTpcdI59ktuPtvOsYBc7SNoJ6aPqqoKo682mAfC
NpUFZ3jirbWGFnaF3WpJsWFyeOY6vyD4hVT6CkunL2ovoYSJND7AAAAFQDjZ2TNBixZByXB+h00wxCN
tHZ8zQAAAIEAl4lePs+e5v9f1H93l2GLXtxXhXyasr+X42HnKgKQTMR+iLgxhtD0Eb/ftTMK+n2ECn9
3MwCNTgx5tdGX06dyBdK5xEfjV4tJnmnP42UweBwOHKpRkNLiMBN4onh7KKXjhXWmH0MpO5fhaHy6k0
f+yTTLckCKd2IO/TgGJitjlo4AAACBAM+3JMr8M+MQoa6D7BU0pNJVGoTmGdxrLotMNLmUdqM0xIFKr
3dBrgqY+gsDciQEG1CSqDDhusrkz3LRBmnuG68tE7WPPjzGZrT46ZYCmMeZume67xVN0dDd57BuxmhK
B7iKvmlM0v+EkvJ0XTlNCwBTWuU3cdTdhkWT7swxGhvf

The next time I used SSH, the server's public key was compared to the copy of that key on the client; since they were the same, SSH knew I was connecting to the correct server so I wasn't asked to re-verify a fingerprint. Instead, I simply received the login prompt on the server.

Let's recap what happens behind the scenes:

  1. The ssh client contacts the ssh server on port 22
  2. The ssh server sends the ssh client a copy of its public key to prove its identity
  3. The ssh client compares the server's public key to its copy of the server's public key. If it does not have a copy of the server's key, it prompts the user to verify the fingerprint
  4. Once the server is authenticated, a key is created that will be used to encrypt and decrypt the data sent between the client and the server
  5. Now it is the user's turn to be authenticated; by default, the server will prompt for the user's password which will be sent encrypted
  6. Once the user authenticates, he will receive his shell on the other system, and all data sent between the two systems will be encrypted

OpenSSH supports other authentication methods, but this is what happens in the default configuration on your FreeBSD system. You may have noticed that the server sent its DSA public key, meaning that it was using SSH version 2. This is a good default, as version 2 is much more secure than version 1.

You may have also noticed that the user doesn't require a key pair in the default configuration, only their password. Let's change that. First, I'll have to generate a key pair for the user genisis by using the ssh-keygen command at 10.0.0.2:

ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/genisis/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/genisis/.ssh/id_rsa.
Your public key has been saved in /home/genisis/.ssh/id_rsa.pub.
The key fingerprint is:
fd:5a:cc:cf:a9:f0:ea:9c:93:ea:1a:04:48:b1:47:14 genisis@hostname

When using ssh-keygen, you need to use the t switch to specify which type of key pair to create. Since SSH version 2 is more secure than version 1, and since RSA is more secure than DSA, I chose to create a SSH version 2 RSA keypair. I was also prompted for a passphrase which will be used in the future to prove that I am the owner of the key pair, or, more importantly, the private key. A passphrase is similar to a password, but should be longer yet memorable. Whenever I wish to use the private key, I will be prompted for the passphrase. If I ever forget the passphrase, I will need to generate a new key pair.

Remember that the public key in a key pair is meant to be public and it is up to you to ensure the private key is kept private. Let's take a look at the default permissions on those keys:

ls ~genisis/.ssh
total 4
-rw-------  1 genisis  genisis  951 Nov  9 15:00 id_rsa
-rw-r--r--  1 genisis  genisis  247 Nov  9 15:00 id_rsa.pub

The private key, id_rsa, is only accessible by the user genisis. The public key, id_rsa.pub, is readable by anyone. If I use the file utility, I'll see that both files are ASCII text, meaning they can be viewed with a pager:

file ~genisis/.ssh/*
id_rsa:     ASCII text
id_rsa.pub: ASCII text

more id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA1gfc4NRnq9K17TLqhhKT3L6feKUttHTJvM054k+WhjI
vsdt4YoeNa3m6lplnOxwOh2w6o+xu+xuiHa/CQkvkAdxFU1ZGtnxtQWV06QJdodUEk55U/0y417TaDF
H1aYjsgPPSpjulKCLQv263C9KOSpjDrjZ74ZLOlQHtsJINY2c= genisis@hostname

Note that I only showed you my public key, not my private key.

Creating the key pair is not enough. I still need to copy my public key into my home directory on the SSH server. Once the server has a copy of my public key, whenever I use SSH it will ask for my public key so it can compare it to its copy. If they match, I will be authenticated.

I'll use the scp or secure copy command to copy the key to the server. This utility comes with OpenSSH and allows you to transfer files over an encrypted session. Its syntax is similar to the regular old cp command; the only difference is that the destination file starts with the IP address of the machine you want to copy the file to, followed by a full colon, followed by the name you want the file to have once it is copied over.

So, at 10.0.0.2, I'll issue this command to copy my public key to the server:

scp ~/.ssh/id_rsa.pub 10.0.0.1:~/.ssh/authorized_keys
Password:
id_rsa.pub:	100% |***************************|   247	00:00

Note that I was careful to copy over the public key, not the private key; that is, I chose the file with the .pub extension. I also had to change the name of the destination file to ~/.ssh/authorized_keys. I was prompted for my password on the destination system before the actual copy occurred.

Now that my public key is copied over, I'll try another SSH:

ssh 10.0.0.1

This time, I wasn't prompted for a password. Instead, since my public key was correct, I immediately received my shell prompt on the server machine. While it may seem less secure to not be prompted for anything, being authenticated by a public key is more secure than being authenticated by a password. However, the security of the system still depends upon you. Just like you don't give other users your password, don't give other users your private key or your passphrase. If you ever suspect that your private key has been compromised, generate a new key pair using a different passphrase and copy over the new public key to the SSH server.

When using ssh, you don't have to be logged in to the same account on the client machine as you want to access on the server machine. For example, if I'm currently logged in as biko but want to access genisis on the server machine, I can use the l switch or login switch at the client:

ssh -l genisis 10.0.0.1

I could also use this equivalent command:

ssh genisis@10.0.0.1

Since there isn't a copy of genisis' public key in biko's home directory, I'll be prompted for a password. I need to input the password for genisis, not for biko. While it's a little bit harder to remember who I am on each system, it does mean that I don't have to create a user account called genisis on both machines.

Let's see what happens if I try to use SSH from the superuser account:

ssh 10.0.0.1
Password:
Password:
Password:
root@10.0.0.1's password:
Permission denied. Please try again.
root@10.0.0.1's password:
^c

Even though I gave the correct password for the superuser account, access was denied. This is a very good default. Just like you should never login directly as root, you should never ssh into another system from the root account. If you need superuser access on the remote system, ssh using a regular user account which has permission to become the superuser once logged in to the remote system.

In order to change the other defaults, we'll have to take a close look at the parameters in the SSH configuration files. Let's save that for next time. In the meantime, you can get a sneak peek by reading the manpages for ssh_config and sshd_config. You might also find the ssh FAQ interesting.

Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.


Read more FreeBSD Basics columns.

Return to the BSD DevCenter.


Copyright © 2009 O'Reilly Media, Inc.