Page Body

GNU/Linux Security

Table of Contents

GNU/Linux security is multi-faceted. Understanding, implementing, and interacting with the technologies that underlie GNU/Linux security will make you a better GNU/Linux user and administrator.

Note: If you are not familiar with the GNU/Linux command line interface, review the Conventions page before proceeding.

File and Access Permissions

A GNU/Linux file system can be described as follows:

  1. Everything is a file.
  2. There is a system of access permissions that is fairly simple, yet sufficient for most purposes.

Security consequences that follow from these points are as follows:

  • Device files work anywhere in the file system, not just in /dev/. If an attacker manages to create a device file of the proper type (e.g., /dev/sda or /dev/kmem), the system is compromised. The file does not even have to have the same name as the official device file, it just needs to have the correct type and major/minor device numbers.
  • Users can make any of their own files executable by setting their files' x bits. Usually, this is not a problem. Occasionally, problems are found in GNU/Linux that enable an unprivileged user to gain administrator privileges by executing a normal program, and that path is also available to programs that a user downloaded from the Internet.
  • The set-UID and set-GID mechanisms allow ordinary users to run programs with the permissions of other users (usually the root user). Set-UID and set-GID programs can also be located anywhere in the file system.

Minimizing Risk

You can attempt to minimize risk by restricting unusual file types to areas of the file system where such files are to be expected. However, you should also actively look out for possibly problematic files. Here are some recommendations.

Removable Media

Removable media are an obvious way to introduce unusual files to a system. This includes files of types that a user would not be allowed to create using their local account. For instance, an unprivileged user may not run a command like # mknod /home/amnesia/vacation.jpg c 1 2, but if they manage to mount a USB stick that contains an ext4 file system with such a file, then they have succeeded.

GNU/Linux avoids this scenario by not letting ordinary users mount removable media at all. The only secure way to allow this is to add specific mount points to /etc/fstab that contain the user or users mount option.

Both of these options imply the nodev option, which makes the system ignore device files on the mounted media (it also imples that SUID/SGID files on the associated media will not be functional). At this point, we could consider this issue resolved, but an /etc/fstab entry like /dev/sda1 /media/usbstick auto noauto,user,dev 0 0 should not be created without considering its consequences.

Set-UID/Set-GID

Set-UID programs pose a similar problem. As ordinary users may not create device files, they many create set-UID files owned by root, and this is fine. However, just as a user might introduce a device file on a removable medium, they might introduce a small set-UID root program that will launch a shell.

Common shells like Bash are reluctant to let themselves be started as set-UID root processes. However, an attacker will likely not be stopped by this. They can also bring in their own shell that they compiled themselves with the set-UID detection code removed.

The way that GNU/Linux avoids this issue is essentially the same as the one that is used to handle device files. The user and users options to mount also imply the nosuid option, which prevents the execution of set-UID programs on the file system in question. To be precise, nosuid does not prevent the programs from being executed, it just makes the system ignore the set-UID and set-GID bits.

The noexec mount option can prevent the execution of programs (including scripts) from the file system in question. This option is also implied by the user and users options. However, it does not present a big obstacle because a user can still copy the file to their home directory and execute it from there.

The nosuid and nodev options only protect against suspicious files on removable media (at first). They do not help against files created by clever attackers that exploit security holes in network services and create convenient backdoors, so that they can come back later. A set-UID shell with an innocuous name like .foo_bar_rc would be sufficient.

There is nothing to keep you from enabling the nosuid and nodev options explicitly for all file systems where users can create files. Besides removable media, this mainly applies to the /home/, /tmp/, and /var/tmp/ directories.

You can scan your system for such files on a regular basis. The tool of choice for this task is the find command. To find all set-UID and set-GID files on your system, you can use find's -perm test.

The full command is:

# find '/' -perm /6000 -type f -ls

You should be aware of all of the set-UID and set-GID programs on your system. It is best to prepare a list that you manually check and later compare automatically (e.g., using a systemd timer or cron) to the list of actual set-UID and set-GID programs on the system.

Ensure that you are notified if a program on the list is missing from the system, or a program appears on the system that is not on the list. Some GNU/Linux distributions may do this by default.

Device files can be located in a similar way. Scan you system for files that are block or character devices:

# find '/' \( -type b -o -type c \) -ls

To run the command and skip the /dev/ directory, use the following form:

# find '/' -path '/dev' -prune -o \( -type b -o -type c \) -ls

The find command can also be used to search for and remove rhosts files from your home directory:

# find '/home' -iname .rhosts -exec rm -f '{}' \;

Having these files present can be a security risk, i.e., if you have a user that has a hostname in their .rhosts file and that host also has the user's hostname in its /etc/hosts.equiv file (this file contains a list of trusted hosts for a remote system, one per line), that user can log in without a password by using the rlogin command.

Audit Automation

The auditing of your file system can be implemented more efficiently. Tools like Tripwire or AIDE are used to detect and report changes to important system files (both programs and configuration files). Typically, such modifications happen when rootkits are installed on a system.

Restricting Access to Resources With Pluggable Authentication Modules (PAM)

When multiple users share the same system, it is important that no single user is able to monopolize the system's resources to the detriment of other users. Even if you are the only user on a system, it may make sense to rein in single processes if they appear greedy.

To facilitate this, GNU/Linux offers a mechanism called resource limits. Resource limits let you specify upper bounds for various resources that users (or single processes belonging to them) may consume.

User access to GNU/Linux resources can be limited using a Pluggable Authentication Modules (PAM) module called pam_limits. pam_limits is configured using the /etc/security/limits.conf file, which is used to apply ulimit.

The /etc/security/limits.conf file contains resource limits that you can configure using the following syntax:

ex_domain ex_type ex_item ex_value

ex_domain
The entity to which the limit applies (e.g., user, @group_name, *).
ex_type
Set soft or hard limit.
Hard limits are set by the root user and enforced by the kernel. The user cannot raise their requirement of system resources above such a value.
Soft limits are ones that a user can move up or down within the permitted range by any pre-existing hard limits. These values can be thought of as default values for normal system usage.
ex_item
The resource being limited.
ex_value
A value for the limit.

Resource limit items include:

core
Restricts the size of core files (in KB).
cpu
Restricts the CPU time of a single process (in minutes).
data
Restricts the size of a program’s data area in RAM (in KB).
fsize
Restricts the size of files created by the user (in KB).
locks
Sets the maximum number of locked files.
maxlogins
Sets the maximum number of simultaneous logins for users.
nice
Sets the maximum nice priority a user is allowed to raise a process to.
nofile
Restricts the number of data files a user may have concurrently open.
nproc
Restricts the number of concurrent processes a user may run.
priority
Sets the priority to run user processes with.
stack
Restricts the stack size (in KB).

For example, the following line in /etc/security/limits.conf sets a hard limit on the number of concurrent processes users in the guests group can run to 10:

@guests hard nproc 10

Documentation

For more information on on pam_limits, run:

  • man 5 pam_limits
  • man 8 pam_limits

Run man 5 limits.conf for more on the /etc/security/limits.conf file.

ulimit

The ulimit command sets or reports user process resource limits:

# ulimit ex_options ex_username

The ulimit -a command is used to check the current user's ulimit settings:

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15623
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15623
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

A specific username can be passed to ulimit -a as an argument to view that user's ulimit settings.

For each of these resource limits, there is a soft limit and a hard limit. Administrator privileges are required to raise the hard limit. Regular users can lower a hard limit and set arbitrary soft limits, but only up to the current hard limit.

Hard limits and soft limits are modified using ulimit's -H and -S options, respectively. When neither one or the other are specified, both the hard and soft limits are set to the same value. When no value is specified for a resource limit, its current value is displayed.

$ ulimit -n 512
$ ulimit -n
512

Above, ulimit's -n option specifies the limit on the number of file descriptors a process may have.

All resource limits can be interactively set using the ulimit shell command. Then, they apply to the shell in which the command was entered, as well as to all processes that will be started by that shell (and their children).

In order to impose restrictive resource limits on users, you have to set them before the users gain system access.

Helpful ulimit options include:

-c
Limit the size of core files (i.e., crash dumps).
-d
Limit the size of the user's process data.
-f
Limit the maximum size of files created in the shell.
-H
Set a hard resource limit.
-m
Limit the maximum resident size (in KB) of a process in RAM.
-n
Limit the number of open file descriptors or open files allowed.
-s
Limit the maximum stack size (in KB).
-S
Set a soft resource limit (e.g., # ulimit -S -u 50).
-t
Limit the amount of CPU time allowed to the user (expressed in seconds).
-u
Limit the number of processes that a given user can run.
-v
Limit the maximum amount of virtual memory available to the shell.

Documentation

Run ulimit --help for more information on ulimit.

Commands to Monitor System Users and Files

There are several commands that can be used to gauge which users are on a system, what they are doing, and which processes are using which files.

whoami

The whoami command prints the effective UID to the standard output.

$ whoami
amnesia

Essentially, the command is displaying the content of the LOGNAME or USER shell variables.

who

The who command prints information about users that are logged on to the system to the standard output.

$ who
amnesia  :0           2021-08-11 22:43 (:0)

The first column shows the username. The second column displays the terminal on which the user is logged in. :0 denotes the X11 server with that display name. Other names (e.g., pts/0) refer to the device file below /dev/. Terminal names of the form pts/ denote pseudo-terminals, typically terminal windows in a graphical environment or Secure Shell sessions.

The remainder of the line in the example above shows the date and time at which the session started. After that, the remote end of the session may be listed in parentheses. If you have several terminal windows or one terminal window with several tabs, it is likely that all of these sessions will be counted as separate users.

who supports a few command-line options of interest:

-a, --all
Display everything that who can output.
-b, --boot
Output the date and time of the last system reboot.
-H, --heading
Output a header line with column titles.
-m
Only display the hostname and user associated with who's standard input.
-r, --runlevel
Display the current runlevel.

w

Like the who command, the w command prints information about users that are logged in, but also displays what they are doing and the system load averages. Specifically, the header includes:

  • The current time
  • How long the system has been running
  • How many users are currently logged on
  • The system load averages for the past 1, 5, and 15 minutes
$ w
 22:44:19 up 1 min,  1 user,  load average: 1.54, 0.86, 0.33
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
amnesia  :0       :0               22:43   ?xdm?  21.03s  0.00s /bin/sh /usr/lib/gdm3/gdm-x-session

Then, there is one line for every logged-in user, in the manner of who.

Columnar data includes:

USER
Login name.
TTY
The TTY (teletype) name.
FROM
The remote host.
LOGIN@
Login time.
IDLE
Idle time, i.e., the amount of time the user has been doing nothing.
JCPU
The total CPU time used by all processes in this session (excluding finished background jobs, but including currently-running background jobs).
PCPU
The CPU time used, so far, by the currently-running process.
WHAT
The command line of the user's current process.

If you specify a user name as an argument for w, then only information about that user will be output.

Helpful options include:

-h, --no-header
Suppress the header line.
-s, --short
Use the short format, i.e., do not print the login time, JCPU, or PCPU times.

last

The last command searches the /var/log/wtmp file and displays a list of all users logged in (and out) since /var/log/wtmp was created.

$ last
amnesia  :0           :0               Tue Aug  4 22:43   still logged in
reboot   system boot  5.7.0-1-amd64    Tue Aug  4 22:42   still running

wtmp begins Tue Aug  4 22:42:46 2021

One or more login names and/or ttys can be provided to last to only view entries for those login names.

The output last produces includes the user, the terminal (or :0, i.e., the graphical screen, specifically the first X server), the remote end, the start date and time, the end time, and the session duration for every session. If the session end time is crash, then the computer did not have the opportunity to log the actual end of the session (which may happen with virtual machines).

The reboot lines refer to system reboots, and in those cases, the third column (where the remote end of the session would otherwise be displayed) gives the name of the operating system kernel being booted.

The information output of last can be viewed as sensitive. It lets you retroactively check who was logged on where and when, which is sometimes useful for debugging, but could be a cause of concern. It is probably best to be cautious and not keep this data for too long.

If you do not want anyone to be able to read this file with the last command, run # chmod o-r '/var/log/wtmp', which removes read permissions for Other.

faillog

For GNU/Linux distributions like Debian, the faillog command displays the contents of the failure log database (/var/log/faillog), which shows failed authentication attempts. It can also be used to set failure counters and limits.

For example, the following command sets a maximum number of failed login attempts before disabling user accounts using the -m (--maximum) option:

# faillog -m ex_number

The -l ex_seconds (--lock-secs ex_seconds) and -u (--user) options are used to lock an account for ex_seconds after a failed login:

# faillog -l ex_seconds -u ex_username

If your system is using systemd for its initialization system and you have the audit subsystem engaged (run man 8 systemd-journald-audit.socket and check out the Linux Audit Project for more information), you can run the following command as an alternative to view failed login attempts:

journalctl -q _AUDIT_TYPE=1112 _TRANSPORT=audit | grep 'failed'

Every audit subsystem message type has an associated _AUDIT_TYPE. Above, the 1112 _AUDIT_TYPE corresponds to AUDIT_USER_LOGIN.

pkill

The pkill command can be used to brute-force log out a user(s):

# pkill -SIGKILL -u ex_username...

The -u (--euid) option can be provided a comma-separated list of values as arguments.

If the /etc/nologin file exists, no one but the root user can log into the system. This behavior is configured in the /etc/pam.d/login file. The line that reads auth requisite pam_nologin.so causes PAM to check and see if a file named nologin exists in /etc/.

lsof

lsof lists open files belonging to all active processes on a system:

# lsof

You can give lsof an object as an argument to narrow down your search, as well (e.g., # lsof ex_name..., where ex_name is a file system object).

An open file may be a regular file, a directory, a block special file, a character special file, an executing text reference, a library, a stream, or a network file (e.g., Internet socket, NFS file, or UNIX domain socket).

Options of interest include:

-s
Display file sizes at all times.
-t
Specify that lsof should produce terse output with process identifiers only and no header.
-u ex_user...
Display only open files associated with the specified user. ex_user can be a username or UID, and multiple values can be specified via a comma-separated list (e.g., ex_user_1,ex_user_1).

fuser

Sometimes, you may want to find out which process or user is currently using some resource on the system. fuser identifies processes using files or sockets:

fuser ex_file_or_file_system...

Useful options include:

-a, --all
Show all files specified on the command line. By default, only files that are accessed by at least one process are shown.
-k, --kill
Kill processes accessing the file.
-i, --interactive
Ask the user for confirmation before killing a process. Used with the -k option.
-m ex_file_or_file_system, --mount ex_file_or_file_system
ex_file_or_file_system specifies a file on a mounted file system or a block device that is mounted. All processes accessing files on that file system are listed.
-n ex_name_space, --namespace ex_name_space
Select a different name space. ex_name_space can be file (the default), tcp, or udp. For ports, either the port number or symbolic name may be specified.
-u, --user
Append the username of the process owner to each PID.

The following example passes in the home directory of the amnesia user as an argument for fuser:

$ cd '/home/amnesia'
$ "$(echo hello; sleep 600)" > 'test.txt'

Then, in a different terminal:

$ fuser `/home/amnesia` `/home/amnesia/test.txt`
/home/amnesia: 767c 1360c 1465c 1467c 1488c 1489c
/home/amnesia/test.txt: 1488 1489

fuser's output is, by default, a list of PIDs followed by a letter that specifies how the process in question is using the resource. The possible letters are:

  • c Current directory.
  • e Executable being run.
  • f Open file. f is omitted in the default display mode.
  • F Open file for writing. F is omitted in the default display mode.
  • r Root directory.
  • m mmap'ed file or shared library.
  • . Placeholder. . is omitted in the default display mode.

The -v (--verbose) option gives you more complete output:

$ fuser -v '/home/amnesia/test.txt'
                        USER        PID ACCESS COMMAND
/home/amnesia/test.txt: amnesia     1488 F.... bash
                        amnesia     1489 F.... sleep

The ACCESS column uses the codes from the table described above.

The -m option widens the search from the named file or directory to some file or directory on the same file system as the named file or directory. For example, the command # fuser -m '/srv' will list all processes that access any file (or directory) on the file system where /srv resides. This is extremely useful if, on your system, /src is on its own file system and you would like to unmount it.

To be able to more efficiently deal with situations where you need to unmount a file system, but GNU/Linux will not let you, you can use the -k option to send a signal (SIGKILL by default, unless you specify otherwise) to the processes in question (e.g., # fuser -mk -SIGTERM '/srv'; sleep 10; fuser -mk '/srv' leaves the process ten seconds to gracefully exit, after which they, or whichever processes are left, get forcefully killed.

If you add the -w option, only those processes that write to the resource(s) will be terminated. With -i, you will be asked, for every process, whether you really want to kill it or not.

fuser will not only identify the users of files, but also those of TCP and UDP ports:

# fuser -n tcp ssh
ssh/tcp: 428 912 914

The -n ex_name_space option chooses the name space, after which you may specify port numbers or symbolic port names (from /etc/services). As long as there is no ambiguity, you may leave off the -n option and specify port numbers in the ex_service_port_or_name/ex_name_space format (e.g., # fuser 80/tcp), as well.

fuser for TCP and UDP ports works best as the root user. Usually, ordinary users do not have access to the required data structures.

shred

The shred command overwrites a file to hide its contents and can optionally delete it (using the -u option).

shred ex_file...

If the argument provided to shred is a dash -, it instructs the command to shred the standard output (e.g., shred - > ex_file).

If you want shred to recursively overwrite and delete files in a directory tree, you can do so with the following command:

find ex_directory -type f -exec shred -u {} +

Pretty Good Privacy (PGP)/GNU Privacy Guard (GPG)

GNU Privacy Guard (GPG) is an implementation of the OpenPGP standard RFC4880, which is based on a program called Pretty Good Privacy (PGP) by Phil Zimmermann. GPG allows you to encrypt and sign files and email messages.

An encrypted file is a file containing data that is scrambled in such a way that only authorized people can view or process it. Authorized people have to decrypt the file with the correct key in order to access it.

By signing data, you can document the fact that you created or approved of the data. When the data are changed afterwards, the signature becomes invalid. GPG signatures are an inherent part of package management tools like APT and DNF, i.e., they play an important role in the verification of package data in GNU/Linux distributions.

It is up to you to access the value of digital GPG signatures. For example, Debian developers have to sign their packages before uploading them to the Debian FTP server, where they are accessible by the public.

The signature does not tell you anything about the quality of the package. Its only purpose is to make sure that the developers themselves uploaded the packages and that no malicious packages were introduced to the software collection by third parties.

GNU Privacy Guard (GPG) Configuration

GPG keeps its configuration files in the ${HOME}/.gnupg/ directory. Some of the files that can typically be found in that directory include:

dirmngr.conf
The standard configuration file read by dirmngr (i.e., the Certificate Revocation List (CRL) and Online Certificate Status Protocol (OCSP) daemon) on startup. dirmngr takes care of accessing the OpenPGP keyservers.
Keyservers can be specified in this file with the --keyserver ex_keyserver_name option.
gpg.conf
This file contains various options and parameters used by gpg. If it does not exist, you will need to create it.

Some parameters that you might want to set in gpg.conf include:

group
Defines groups that can save time when encrypting files. For example, imagine the following entry in your gpg.conf file group beatles = john paul 0x12345678 ringo (when you specify the --recipient beatles option, GPG interprets this as three individual --recipient options with names and one with a key ID).
Groups only work one level deep, i.e., you cannot have groups that contain other groups.
keyserver
Specifies your favorite keyserver, e.g., keyserver hkp://keys.gnupg.net.
no-greeting
Suppresses the copyright notice that is initially printed by gpg.
pubring.gpg
The ring of public keys. This file contains the public keys that you have generated or imported.
random_seed
This file is used by GPG to keep track of the state of the random number generator.
secring.gpg
The ring of secret keys. This file contains the private keys of your key pairs.
trustdb.gpg
This file contains the owner trust levels of the keys on your public key ring. Since these are private data reflecting your personal views, they are kept in a separate file and not in the public key ring file (which you may want to make available to others).

GPG is an important program, but it is not straightforward. A good starting point is to study its documentation, which you can view by running man 1 gpg. More extensive documentation can be found at https://www.gnupg.org/.

Symmetric and Asymmetric Cryptography

Cryptography is a method for encrypting and decrypting data. Basically, there are two approaches to cryptography.

  1. Symmetric cryptography
  2. Asymmetric cryptography

Symmetric Cryptography

Symmetric cryptography uses the same key for encrypting and decrypting data. When a hypothetical Diana and Bruce wish to exchange private data using a symmetric method, they have to invent a key first. The same key has to be known to both of them.

When Clark enters the picture, three different keys are needed:

  1. One for communication between Diana and Bruce
  2. One for Diana and Clark
  3. One for Bruce and Clark

Four parties need 6 keys, ten parties need 55 keys, one hundred parties need 5,050 keys, and so on. All of the keys are secret, so they have to be distributed in such a way that no third party can come to know them.

The major issue with symmetric cryptography is key distribution. First, keys have to be transmitted in a secure way, so cryptography would be useful for distributing them in the first place. Second, on the Internet, with billions of potential users, the number of keys required for every user to be able to confidentially communicate with every other user would be astronomical, so much so that possibly no other data could be stored.

These problems are addressed by asymmetric cryptography.

Asymmetric Cryptography (Public-Key Cryptography)

Asymmetric cryptography (Public-Key Cryptography) uses different keys for encrypting and decrypting data. A set of asymmetric keys is called a key pair.

Each key pair consists of a public key and a private key. The public key can safely be made public, while the private key must be kept secret. Now, Diana can privately send content to Bruce by encrypting it with Bruce's public key. Bruce then uses his private key to decrypt the content. Since only Bruce knows his private key, the content is safe during transmission.

Virtually all known asymmetric cryptographic methods are too slow and cumbersome to use to transfer large amounts of private data. This is why asymmetric methods are often used to exchange the keys used to encrypt and decrypt data symmetrically (symmetric cryptography is fast and efficient, and can easily process vast amounts of data).

Private/public key pairs should be much longer than those used for symmetric encryption.

Signatures

Signatures work the other way around. Diana signs content by encrypting it with her private key. Bruce can verify that Diana signed the content by decrypting it with Diana's public key. When the decryption results in consistent data, the content must have been signed using Diana's private key.

Verifying Public Key Authenticity and the Web of Trust

Asymmetric cryptography solves the problem of key distribution, but introduces another problem. How does Bruce know that the key that he uses to verify Diana's signature is really Diana's public key? What is missing in this process is a means of verifying the authenticity of public keys.

The Secure Shell sidesteps this problem by letting the user authenticate the keys. Whenever the ssh program contacts an unknown server, it asks whether you want to include its public key in your list of known hosts. At this point, it is up to you to verify the authenticity of the key presented to you.

The Secure Sockets Layer (SSL) and Transport Layer Security (TLS) infrastructures as used by secure web sites solve this problem by introducing a hierarchy of certification authorities.

The entire construct is called a public key infrastructure (PKI). The certification authorities assert that a specific key belongs to a specific person and attest to this claim by means of a digital signature. A set consisting of a public key (the owner of a digital signature), and the signature and name of the certification authority is called a certificate.

As a user, you can verify the signature on the certificate using the certification authority's public key (which you have obtained from a trustworthy source; typically, the most important ones come from your web browser). For example, to view the trusted certificate authorities for version 78 of the Firefox ESR (extended support release) web browser, you can navigate to Preferences > Privacy & Security > Certificates > View Certificates....

The question of whether or not you trust the signature on a given certificate comes down to the question of whether or not you trust the people and the work of the certification authority (1, 2, 3).

GPG deliberately does not use the hierarchical structure explained above. It uses an approach that is known as the web of trust.

Web of Trust
"Web of Trust-en.svg" by Kku is licensed under a Creative Commons Attribution-Share Alike 4.0 International license

In the web of trust, there are no central certification authorities that all users must trust. Instead, the concept assumes that users of GPG sign the public keys of people they personally know, thereby documenting that the key belongs to a specific person.

For example, assume that you want to send a private message to Clark, whom you do not know in person. Somewhere, you dig up a public GPG key that claims to be Clark's.

Whether you can trust this key or not depends on the question of whether you or your GPG program can form a chain of trust from yourself to the key in question. When all signatures in a chain of trust are valid, you can assume, with reasonable certainty, that the key of Clark actually belongs to Clark, i.e., it is valid.

GPG supports a concept called owner trust. For each public key that you have available, you can set the degree of pedantry you believe their owners apply when they are dealing with GPG keys.

There are four trust levels:

  1. unknown Nothing is known about the owner's judgment in key signing. Keys on your public keyring that you do not own initially have this trust level.
  2. none The owner is known to improperly sign other keys.
  3. marginal The owner understands the implications of key signing and properly validates keys before signing them.
  4. full The owner has an excellent understanding of key signing, and their signature on a key would be as good as your own.

Keep in mind, trust levels should not depend on how much you care for a person, but only how much they care about GPG keys.

GPG will consider a public key valid if it meets two conditions:

  1. It is signed by enough valid keys, meaning:

    • You have personally signed it.
    • It has been signed by one fully trusted key, or
    • It has been signed by three marginally trusted keys, and
  2. The path of signed keys leading from the public key to your own key is five steps or shorter.

More information on GPG and the web of trust can be found in the The GNU Privacy Handbook.

As a GPG user that wants to take part in the web of trust, you should abide by several rules. Most importantly, you should sign other people's keys only if you are absolutely positive about their identity. When in doubt, ask the person for a piece of official photo identification (or two). Never sign keys based on hearsay.

In principle, you do not need your own GPG key pair in order to send encrypted messages to other people or to verify their signatures. All you have to do is to obtain the public keys in question. However, a successful signature check merely indicates that a file has not been tampered with.

To verify that the signature was generated by the person who claims to have created it, you have to take part in the web of trust. This is the only way to make sure that a signature is valid, according to the rules previously outlined.

So, the first step to seriously using GPG is the generation of your own key pair (when you use GPG to check the integrity of distribution packages, your distributor normally ships a set of public keys that can be used for verification).

Generating an Asymmetric Key Pair

A key pair is generated by running the gpg program with the --full-generate-key option:

$ gpg --full-generate-key
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits

The default option, RSA and RSA generates two key pairs:

  1. A RSA key pair for signing data.
  2. A RSA key pair for encrypting and decrypting data.

Next, you have to assign a life time to the key. You can change the life time of the key afterwards, but in this case you will have to redistribute the key in order to make this change known to the public.

Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y

The next step is to assign a User ID to your key. This ID consists of a name, an email address, and an optional comment:

GnuPG needs to construct a user ID to identify your key.

Real name: amnesia
Email address: amnesia@example.org
Comment:
You selected this USER-ID:
    "amnesia <amnesia@example.org>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

Finally, you have to specify a passphrase that will be used to encrypt your private key. A good passphrase is essential to the security of GPG. It is your only protection should the key pair, especially the private key, ever fall into the wrong hands.

In the last step, the key pairs themselves will be generated. This step requires high-quality random numbers. GNU/Linux generally generates those numbers by measuring the times between I/O events, like key presses and movements of the mouse.

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 749DDC030A1077C7 marked as ultimately trusted
gpg: revocation certificate stored as '/home/amnesia/.gnupg/openpgp-revocs.d/72F6EECB923CA1DE8F762FE6749DDC030A1077C7.rev'
public and secret key created and signed.

pub   rsa4096 2020-10-02 [SC]
      72F6EECB923CA1DE8F762FE6749DDC030A1077C7
uid                      amnesia <amnesia@example.org>
sub   rsa4096 2020-10-02 [E]
Creating a Revocation Certificate

Often, it is wise to create a revocation certificate, which can be used to declare a public key invalid in case the corresponding private key is compromised or lost. The revocation certificate states that the key that it invalidates should no longer be used to encrypt data. The revoked key can still be used for verifying existing signatures.

In the key generation example above, a revocation certificate was automatically created during the key generation process. However, you can also manually create a revocation certificate.

A revocation certificate is created using the -o ex_file (--output ex_file) and --gen-revoke options:

$ gpg -o 'revoke.asc' --gen-revoke 'amnesia'

sec  rsa4096/749DDC030A1077C7 2020-10-02 amnesia <amnesia@example.org>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 1
Enter an optional description; end it with an empty line:
> My private key was stolen.
>
Reason for revocation: Key has been compromised
My private key was stolen.
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

At this point, you will be asked for your key's passphrase. After entering it, the revocation certificate will be stored in the file revoke.asc in the current directory.

The revocation certificate generated here is intended for use in a worst-case scenario, i.e., for the case where your key becomes permanently unusable. If you decide to revoke your key for a different reason some day, feel free to create a fresh revocation certificate that more accurately reflects your reason.

The revocation certificate should be stored on a medium that you can lock away, and not on your computer. When an attacker gets their hands on the certificate, they can use it to make your key unusable. It may be wise to store a printed copy of the certificate, too, so that you can type it in by hand, if necessary.

Exporting and Publishing a Public Key

The next step would be to publish your public key in order to make it available. To do so, you will have to export the key first.

The -k (--list-public-keys) option makes GPG list all public keys that you can use:

$ gpg -k
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/amnesia/.gnupg/pubring.kbx
------------------------------
pub   rsa4096 2020-10-02 [SC]
      72F6EECB923CA1DE8F762FE6749DDC030A1077C7
uid           [ultimate] amnesia <amnesia@example.org>
sub   rsa4096 2020-10-02 [E]

Above, the 72F6EECB923CA1DE8F762FE6749DDC030A1077C7 value is the key's fingerprint and the last eight (or sixteen) characters of this value are the key's key ID.

Your public key is exported by the --export option of GPG. As in the command creating the revocation certificate, the -o option can be used to specify a filename to which the output will be written. The -a (--armor) option generates output in ASCII format, so that it can be sent via email or published on a web site:

$ gpg -o 'amnesia.gpg' -a --export 'amnesia'
$ cat amnesia.gpg | head
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBF93iLABEAC3cq/PoC2VnOGGh622Rvj27ctYZMdz9H8u5RUoU365//S7X0QJ
GhdsYsf6QV/EWbhHDfPeqdZKB/0EMWT/PNJqPMpV0xD/ekyEpn49JtfIlOYiphJe
HQCEyaV76RCAZVfrTngcRUlCQzLXBz+3L2SpZK9XtD3iFlLZlRxDzgKVc8IcNyFn
QLxuJWuUScMa4UaGigelPfIET1F9u0kI7tO36tp9HuT2nO1h7Rx05yVpSFNCTIdV
Dp5WCHbMkOdgSd8bQWWTrcWlSiXSs00P5+c9tjU3fxjHiOQ8tG5lvv7pACcfefLp
WSMfj8w6i0APwiBJAFd0xyn9Gm2XzXlgpKaVHdQIt0+/Na0fHdB5NYkUwsAwD+Y9
E12fqNO5QBK/gi5QQuNFQt4TdfRPmwX/KtTKNs/OnfSJq9zqojAL+Smfuluv/rhQ
KSf1eFVB9GZ8MMGSC/1PD7JQEb0ouBPHouAmhkM5Jcd/MSvfMU14GvmFdR8iWRoT

A more efficient way of publishing your public key is to upload it to a key server. This is also done with the help of the gpg program, e.g., gpg --keyserver 'hkp://subkeys.pgp.net' --send-keys '0A1077C7'. Most key servers synchronize their data, so it is normally sufficient to upload your key to only one of them.

Instead of specifying a keyserver on the command line with --keyserver, you can specify a default gpg keyserver in your ${HOME}/.gnupg/dirmngr.conf file by adding a line like so:

--keyserver ex_keyserver_name

A list of common keyservers can be found in the ArchWiki.

Importing a Public Key

When you find a public key in an email message or on a web site, you will have to import it into your key ring before you can use it:

$ gpg --import '249CB3771750745D5CDD323CE267B052364F028D.asc'
gpg: key E267B052364F028D: public key "NIIBE Yutaka <gniibe@fsij.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1
$ gpg -k
/home/amnesia/.gnupg/pubring.kbx
------------------------------
pub   ed25519 2015-08-12 [SC]
      249CB3771750745D5CDD323CE267B052364F028D
uid           [ unknown] NIIBE Yutaka <gniibe@fsij.org>
uid           [ unknown] NIIBE Yutaka <gniibe@debian.org>
sub   ed25519 2015-08-12 [A]
sub   cv25519 2015-08-12 [E]
Verifying a Public Key (Fingerprint)

Now, the new key is part of your key ring, but you still need to verify that it is authentic. It is best to generate the fingerprint of the key and ask the key owner whether it is correct:

$ gpg --fingerprint 'NIIBE Yutaka'
pub   ed25519 2015-08-12 [SC]
      249C B377 1750 745D 5CDD  323C E267 B052 364F 028D
uid           [ unknown] NIIBE Yutaka <gniibe@fsij.org>
uid           [ unknown] NIIBE Yutaka <gniibe@debian.org>
sub   ed25519 2015-08-12 [A]
sub   cv25519 2015-08-12 [E]

You may consider printing the fingerprint of your GPG key on your business card or prepare some slips of paper containing the key data. This way, when you meet a person and want to swap signatures, you can hand them a copy of the fingerprint and, if necessary, identify yourself.

Then, the other person can fetch your public key from a key server and use the fingerprint to make sure that the key really belongs to you. Finally, they can sign the key and send you a copy, so that you can integrate the signature into your official public key (i.e., you import your newly signed public key into your keychain, and then re-submit the public key to your key server of choice).

Another popular means of verifying keys are key signing parties where, for example, members of open source projects perform mutual mass verification of their GPG keys. The user IDs and public key fingerprints of all participants are collected and distributed to all persons taking part in the event.

Afterwards, every participant checks the ID of each person on the list and marks the keys that they are willing to trust. Once the lists are complete, the keys can be later signed.

For example, say that you have successfully verified the authenticity of Yutaka's public key. Now, you can sign Yutaka's key. Yutaka benefits from your signing their key because their key is now considered to be valid by all people who consider your key to be valid.

You benefit from signing the key, too, because you are now connected to Yutaka's web of trust. You can assume that keys that have been signed by Yutaka are valid, too.

Owner trust also plays a role. In your key ring, you can make a note of the degree to which you trust Yutaka's knowledge of GPG and their diligence in handling keys. This note affects the validity of keys signed by Yutaka.

When you are not sure about Yutaka's skills, keys signed by Yutaka will have to be signed by other people in your web of trust in order to become valid. When you trust Yutaka fully, their signature alone is sufficient.

You can sign Yutaka's key as follows:

gpg --sign-key 'NIIBE Yutaka'

After you confirm that you want to sign Yutaka's key, gpg once more prompts for your key's passphrase.

The signatures on a key can be listed and checked at the same time by using the --check-signatures option:

$ gpg --check-signatures 'NIIBE Yutaka'
pub   ed25519 2015-08-12 [SC]
      249CB3771750745D5CDD323CE267B052364F028D
uid           [ unknown] NIIBE Yutaka <gniibe@fsij.org>
sig!3        E267B052364F028D 2015-08-13  NIIBE Yutaka <gniibe@fsij.org>
uid           [ unknown] NIIBE Yutaka <gniibe@debian.org>
sig!3        E267B052364F028D 2015-08-12  NIIBE Yutaka <gniibe@fsij.org>
sub   ed25519 2015-08-12 [A]
sig!         E267B052364F028D 2015-08-12  NIIBE Yutaka <gniibe@fsij.org>
sub   cv25519 2015-08-12 [E]
sig!         E267B052364F028D 2015-08-12  NIIBE Yutaka <gniibe@fsij.org>

gpg: 4 good signatures

An exclamation mark after the sig at the beginning of a line indicates that the signature was successfully verified. When a signature is bad, there would be a minus sign -, instead.

All of the above signatures can be checked by you because you own copies of all of the required public keys. When a signature cannot be checked because a public key is lacking, that signature will be ignored.

The gpg --list-signatures command lists all signatures without checking them. Signatures with missing public keys will appear as [User-ID not found].

Managing Keys

For managing keys, you can use the --edit-key option:

$ gpg --edit-key 'NIIBE Yutaka'
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.


pub  ed25519/E267B052364F028D
     created: 2015-08-12  expires: never       usage: SC  
     trust: unknown       validity: unknown
sub  ed25519/5F910521FAA805B1
     created: 2015-08-12  expires: never       usage: A   
sub  cv25519/850AF040D619F240
     created: 2015-08-12  expires: never       usage: E   
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2)  NIIBE Yutaka <gniibe@debian.org>

gpg>

At the gpg> prompt, you can enter commands. For example, fpr lists the fingerprint of a key and sign signs a key. There are many other commands. help prints a summary.

An important command is trust, which changes the owner trust level:

gpg> trust
pub  ed25519/E267B052364F028D
     created: 2015-08-12  expires: never       usage: SC  
     trust: unknown       validity: unknown
sub  ed25519/5F910521FAA805B1
     created: 2015-08-12  expires: never       usage: A   
sub  cv25519/850AF040D619F240
     created: 2015-08-12  expires: never       usage: E   
[ unknown] (1). NIIBE Yutaka <gniibe@fsij.org>
[ unknown] (2)  NIIBE Yutaka <gniibe@debian.org>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision?

The difference between full and ultimate is the difference between others and yourself. You might trust other people's keys fully, but should only trust your own keys ultimately.

The trust database of GPG is updated only when the program is started for the next time, so when you plan to change multiple trust levels, you should do this in a single session and then restart gpg.

Revoking a Public Key

If you ever want to revoke your public key, you have to first import the revocation certificate to your key ring:

gpg --import 'revoke.asc'

Then, you can send the revoked key to the usual key servers.

Encrypting Content

Content can be encrypted using symmetric or asymmetric cryptography.

Encrypting Content With Asymmetric Cryptography

In order to asymmetrically encrypt a file using GPG, you need the public key of the recipient of the file. A file can be encrypted via the -e (--encrypt) and -r (--recipient) options:

gpg -e -r ex_name ex_input_file

This command encrypts the file ex_input_file, such that only ex_name can read it. The encrypted version is created as a separate file, ex_output_file.gpg, in the current directory.

You can also use the -a (--armor) option to create an ASCII version of the encrypted message, which can be pasted into an email message. Furthermore, you can encrypt a message in such a way that multiple recipients can read it.

To do so, specify one -r option for each recipient. Note that this is implemented by including an individually encrypted copy for each recipient in the output file.

The encrypted file can be decrypted via use of ex_name's private key and the -d (--decrypt) option:

gpg -d ex_output_file.gpg

By default, gpg sends the decrypted content to the standard output, but you could save it as a separate file using the -o option (gpg -o ex_output_file -d ex_output_file.gpg).

The passphrase for ex_name's private key will need to be entered.

Encrypting Content With Symmetric Cryptography

If you wish to encrypt a file that you just want to keep to yourself, you do not need asymmetric cryptography. gpg's -c (--symmetric) option uses a symmetric key that is derived from a passphrase that you specify. The same passphrase is used to decrypt the file:

$ echo 'Hello World!' | gpg -o 'secret.gpg' -c
Enter passphrase: foobar
Repeat passphrase: foobar
$ gpg -d 'secret.gpg'
gpg: AES256 encrypted data
Enter passphrase: foobar
gpg: encrypted with 1 passphrase
Hello World!

The above example demonstrates how GPG reads encrypted data from the standard input stream and writes decrypted data to the standard output stream.

Digitally Signing Content

You can also use your key pair to sign a file. Signing a file annotates the content of the file with a time stamp and a digest.

When the file is modified after signing it, verifying the signature will fail. This mechanism is used to sign software packages of distributions, thereby allowing you to verify that it was the maintainer of a package who uploaded it, and not a malicious attacker.

You can be reasonably sure that properly signed packages will not introduce any malware, like viruses or trojans. You can also use a signature to sign a manuscript when sending it to your publisher, so that they can be sure that they receive the original work, and not a tampered with copy.

A side effect of this approach is that it is difficult for you to claim that a document with your digital signature was not signed by yourself. This would imply that your private key has been compromised.

There is a certain tendency toward giving digital signatures as created by GPG the same legal status as a signature on a sheet of paper. This is unfortunate or even dangerous, because there is a considerable difference between the act of signing your name on a piece of paper, and the act of typing a passphrase and pressing Enter.

On a sheet of paper, you sign exactly what is written on that sheet and nothing else. In cases of doubt, there is a strong presumption that you meant what you signed.

When signing a digital document, there is no guarantee that the computer really signs exactly the intended document (and only that document and not simultaneously, say, a purchase agreement). This is why in a legal dispute, destroying the claim that a digital signature is equal to a real-life signature should be facile for a competent expert.

To sign a file with GPG, run gpg with the -s (--sign) option:

gpg -o ex_output_file.sig -s ex_input_file

Here, ex_output_file.sig represents the ex_input_file file with an incorporated GPG signature.

Since the file is signed with your private key, you have to enter your key's passphrase. The signed file will be compressed, as well. It is written to the output file in binary format.

You can verify a signature with gpg's --verify option:

$ gpg --verify 'text.txt.sig'
gpg: Signature made Thu Feb 18 11:22:33 2016 CET using DSA key ID ed25519
gpg: Good signature from "NIIBE Yutaka <gniibe@fsij.org>"

gpg -d checks the signature, decompresses the file, and writes it to the standard output:

$ gpg -d 'text.txt.sig'
Hello World!
gpg: Signature made Thu Feb 18 11:22:33 2016 CET using DSA key ID ed25519
gpg: Good signature from "NIIBE Yutaka <gniibe@fsij.org>"

As usual, the -o option can be used to write the decompressed data directly to a file.

The compressed binary format is not practical for including in email messages. In this case, you would use the --clearsign option instead, which generates a plain text version of its output. The resulting file contains both the signed data and the signature in ASCII format:

gpg --clearsign ex_file

Such a file looks like this:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello World!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (FreeBSD)

psvOnpEbJkzRK2mavQQFyllXkkxKVk44buyNuCHeyr8ybFCOvmIAs23GbmgzrqFU
X9WSkdCNpjCs2Cdkn5yp2uls=
=UH8U
-----END PGP SIGNATURE-----

Plaintext messages are used in the Debian project. The .dsc files, which accompany source code packages, contain the checksums of the original source code (typically a .tar.gz file) and the patch containing Debian-specific changes, and are signed by the package maintainer. This allows you to check, upon installing a package, that the version you have is in fact created by the package maintainer.

Similarly, a new version of a package that is to be available on the Debian servers as part of a distribution must be accompanied by a GPG-signed .changes file listing the files the package consists of, together with their checksums. Files that are uploaded without a .changes file signed by a Debian developer will be discarded.

Sometimes, you may want to sign a file without changing it by adding the signature. For example, this is required, when submitting a package to a GNU/Linux distributor or when you want to guarantee the authenticity of a source code archive that you are publishing.

When annotating a tar archive with a signature, it would no longer be a valid tar archive, so you have to keep the signature in a separate file. This is called a detached signature.

In order to create a detached signature, use the -b (--detach-sign) option of gpg:

gpg -o ex_output_file.sig --detach-sign ex_input_file

Here, ex_output_file.sig does not represent the ex_input_file file. It is just a detached GPG signature.

To verify a file using a detached signature, you need the signature and the signed file to be in the same directory. The --verify option of gpg also verifies detached signatures:

gpg --verify ex_file.sig ex_file

The first file name following --verify is the name of the file containing the detached signature and the second file specifies the file associated with the detached siganture.

When only one file name is passed to --verify (e.g., gpg --verify ex_file.sig), the program assumes that the name specifies the name of the detached signature file, and that the name of the signed file is identical (but without the .sig suffix). When the -a option is used, gpg removes the .asc suffix, instead of .sig, in order to determine the name of the actual signed file.

The Pretty Good Privacy (PGP) / GNU Privacy Guard (GPG) Process

Often, GPG is used to securely send email messages. This process uses both asymmetric and symmetric cryptography.

On the sender's side:

  1. The plaintext message is hashed and the resulting checksum is digitally signed (encrypted) with the sender's private key (i.e., an encrypted checksum is created).
  2. The plaintext message and the signed checksum are combined/compressed, and then encrypted with a symmetric key that the sender randomly generates.
  3. The symmetric key is encrypted with the receiver's public key and is combined with the previously encrypted content.

On the receiver's side:

  1. The sender's symmetric key is decrypted with the receiver's private key.
  2. The decrypted symmetric key is used to decrypt the ciphertext message and the signed checksum. This leaves the receiver with the plaintext message and the signed checksum.
  3. The sender's public key is used to verify (decrypt) the signed checksum. The recipient generates their own hash (i.e., checksum) of the decrypted message and compares it to the decrypted checksum from the sender.

Regarding the use of asymmetric cryptography in this process, notice that when it comes to digital signatures, the private key is used for encryption and the public key is used for decryption. Yet, for the randomly generated symmetric key that the sender creates, the inverse is true, i.e., the public key is used for encryption and the private key is used for decryption.

GNU Privacy Guard (GPG) Commands

gpg --generate-key, gpg --gen-key
Generate a new key pair using the current default parameters. Key files are stored in ${HOME}/.gnupg/ and a revocation certificate is created and stored in the ${HOME}/.gnupg/openpgp-revocs.d/ directory.
gpg --full-generate-key, gpg --full-gen-key
Generate a new key pair with dialogs for all options. This is an extended version of --generate-key.
gpg --import ex_key_file...
Import/merge keys. This adds the given keys to the keyring.
ex_key_file can be a file like ex_key.gpg, ex_key.txt, or ex_key.key.
gpg --keyserver ex_key_server_url --receive-keys ex_user_id
Import a public key from a keyserver. ex_key_server_url is in the format of scheme:[//]keyservername[:port].
There are different ways to specify ex_user_id:
  • key ID (234567C4, 234AABBCC34567C4, 0x234AABBCC34567C4)
  • fingerprint (0E12343434343434343434EAB3484343434343434)
  • OpenPGP user ID (=Heinrich Heine <heinrichh@uni-duesseldorf.de>)
  • email address (<heinrichh@uni-duesseldorf.de>)
  • subject's Distinguished Name (DN) (/CN=Heinrich Heine,O=Poets,L=Paris,C=FR)
  • issuer's DN (#/CN=Root Cert,O=Poets,L=Paris,C=FR)
  • serial number and issuer's DN (e.g., #4F03/CN=Root Cert,O=Poets,L=Paris,C=FR)
  • keygrip (&D75F22C3F86E355877348498CDC92BD21010A480)
  • substring match (*Heine)
  • . and + prefixes (these are reserved for looking up mails anchored at the end and for a word search mode; they are not yet implemented and using them is undefined)

The key ID is either the last 16 (Long key ID) or 8 (Short key ID) characters in the fingerprint.

The fingerprint is a 160-bit SHA-1 hash of the octet 0x99, followed by the two-octet packet length, followed by the entire Public-Key packet starting with the version field. The fingerprint for each user ID can be viewed using the gpg -k command.

For example, for 0x9026DBBE1FC237AF, the value after 0x is the Long key ID. The corresponding fingerprint is 0BC4700A06E2072D3A77F8E29026DBBE1FC237AF.

Out of all the user ID options, the fingerprint is probably the best to use, as it removes any ambiguity. For more information on specifying user IDs, check out the GnuPG documentation.

wget -O - -q ex_key_url | gpg --import
Import a key from a URL.
gpg --export
Export all public keys from all keyrings.
If export is provided one or more user IDs (in a space separated list), only those public keys are exported (gpg --export ex_user_id_1 ex_user_id_2).
Exported public keys are written to the standard output or to the file specified with the -o option (gpg -o ex_public_key.pub --export ex_user_id).
gpg -a -o ex_public_key.txt --export ex_user_id,
gpg --armor --output ex_public_key.txt --export ex_user_id
Generate a plaintext version of a public key.
The -a option creates the ASCII armored output and the -o option writes the command output to a file.
gpg --export-secret-keys
Export all private keys from all keyrings.
If --export-secret-keys is provided one or more user IDs (in a space separated list), only those private keys are exported (gpg --export-secret-keys ex_user_id_1 ex_user_id_2).
Exported private keys are written to the standard output or to the file specified with the -o option (gpg -o ex_private_key.key --export-secret-keys ex_user_id).
gpg -a -o ex_private_key.txt --export-secret-keys ex_user_id,
gpg --armor --output ex_private_key.txt --export-secret-keys ex_user_id
Generate a plaintext version of a private key.
The -a option creates the ASCII armored output and the -o option writes the command output to a file.
gpg --keyserver ex_key_server_url --send-keys ex_user_id...
Export a public key to a keyserver. ex_key_server_url is in the format of scheme:[//]keyservername[:port].
gpg --delete-secret-and-public-key ex_user_id
Remove key from the public keyring. If a secret key exists, it will be removed first.
gpg -k, gpg --list-public-keys
List all keys from configured public keyrings. A specific key (or keys as a space separated list) can be passed to -k as an argument to list only that key(s).

Each key has a role that is represented by a character. These are the roles and their corresponding characters:

GNU Privacy Guard (GPG) Key Roles
Constant Character Explanation
PUBKEY_USAGE_SIG S Key is good for signing
PUBKEY_USAGE_CERT C Key is good for certifying other signatures
PUBKEY_USAGE_ENC E Key is good for encryption
PUBKEY_USAGE_AUTH A Key is good for authentication

Keys are marked with pub (public) or sub (public subkey).

gpg -K, gpg --list-secret-keys
List all known secret keys. A specific key (or keys as a space separated list) can be passed to -K as an argument to list only that key(s).
Keys are marked with either sec (secret) or ssb (secret subkey).
You can specify the location of a GPG directory with the --homedir ex_gpg_directory option, e.g., --homedir /media/encrypted_usb/.gnupg/. This is handy if you have your .gnupg/ directory saved someplace other than ${HOME}/.gnupg/.
gpg --fingerprint
List all keys from configured public keyrings, along with their fingerprints. A specific key (or keys as a space separated list) can be passed to --fingerprint as an argument to list only that key(s).
If --fingerprint is given twice (gpg --fingerprint --fingerprint), the fingerprints of all secondary keys are listed too.
gpg -a -o ex_user_id.asc --gen-revoke ex_user_id,
gpg --armor --output ex_user_id.asc --generate-revocation ex_user_id
Generate a revocation certificate for the complete key.
The -a option creates the ASCII armored output and the -o option writes the command output to a file.
You will need to specify a reason for the revocation and enter an optional description (e.g., 1 = Key has been compromised and This revocation certificate was generated when the key was created.). The revocation file should be stored someplace safe (e.g., on separate encrypted media). It can also be printed.
gpg --list-sigs, gpg --list-signatures
List all keys from configured public keyrings, along with their signatures. A specific key (or keys as a space separated list) can be passed to --list-sigs as an argument to list only that key(s).
The key signatures are not verified.
gpg --check-sigs, gpg --check-signatures
List all keys from configured public keyrings, along with their verified signatures. A specific key (or keys as a space separated list) can be passed to --check-sigs as an argument to list only that key(s).
A good signature will have a sig entry followed by a !.
A bad signature will have a sig entry followed by a -.
You will already need to have the public key of the signer imported into your keychain to properly perform this check (signatures where the public key is not available are not listed).
gpg -r ex_user_id -e ex_file, gpg --recipient ex_user_id --encrypt ex_file
Encrypt a file using a recipient's public key. ex_user_id can be an email address.
gpg will create an encrypted version of your file with the .gpg file extension in the current directory, e.g., ex_file.gpg. You can specify the exact name of the output file using the -o option (gpg -o ex_file.gpg -r ex_user_id -e ex_file).
You can add the -s (--sign) option to also sign the file. You will need to enter your private key's password to sign the file.
gpg -r ex_user_id --encrypt-files ex_file_1...,
gpg --recipient ex_user_id --encrypt-files ex_file_1...
Encrypt multiple files using a recipient's public key. Files are provided as a space separated list.
tar -czf - ex_dir | gpg -o ex_dir.tar.gz.gpg -r ex_user_id -e,
tar -czf - ex_dir | gpg --output ex_dir.tar.gz.gpg --recipient ex_user_id --encrypt
Encrypt a directory using a recipient's public key. ex_user_id can be an email address.
The - after -czf tells tar to write to the standard output, which is piped to the gpg command.
gpg -c ex_file, gpg --symmetric ex_file
Encrypt a file using symmetric encryption. You will need to specify an encryption password.
gpg will create an encrypted version of your file with the .gpg file extension in the current directory, e.g., ex_file.gpg. You can specify the exact name of the output file using the -o option (gpg -o ex_file.gpg -c ex_file).
You can specify the encryption algorithm to use with the --cipher-algo ex_algorithm option, e.g., gpg -c --cipher-algo AES256 ex_file. Run gpg --version to view the supported algorithms.
tar -czf - ex_dir | gpg -o ex_dir.tar.gz.gpg -c,
tar -czf - ex_dir | gpg --output ex_dir.tar.gz.gpg --symmetric
Encrypt a directory using symmetric encryption.
The - after -czf tells tar to write to the standard output, which is piped to the gpg command.
gpg -d ex_file, gpg --decrypt ex_file
Decrypt a file and write it to the standard output.
You will need to enter the password associated with the key/file. You can write the output to a file using the -o option, e.g., gpg -o ex_output_file -d ex_file.
gpg --decrypt-files ex_file_1...
Decrypt multiple files. Files are provided as a space separated list.
You will need to enter the password associated with the files.
gpg -d ex_output.tar.gz.gpg | tar -xf -,
gpg --decrypt ex_output.tar.gz.gpg | tar -xf -
Decrypt a directory.
You will need to enter the password associated with the key/directory. The - after -xf tells tar to use the standard input as the archive to operate on, which is piped in from the gpg command.
gpg --verify ex_file.gpg.asc, gpg --verify ex_file.gpg.sig
Assume that the first argument is a file with an incorporated signature and verify it without generating any file content output.
If more than one argument is given, the first argument should specify a file with a detached signature and the remaining file(s) should be the file(s) associated with the detached signature.
The public key of the individual that signed the file(s) should be in your keychain prior to verification.
gpg --verify-files ex_file.gpg.asc..., gpg --verify-files ex_file.gpg.sig...
Verify multiple files. Files are provided as a space separated list.
gpg --default-key old_user_id --sign-key new_user_id
Sign a new key with an old key.
Afterwards, write a transition statement and sign it with both the old and new key:
$ gpg -a -b -u old_user_id -o sig_1.txt gpg_transition.txt
$ gpg -a -b -u new_user_id -o sig_2.txt gpg_transition.txt

-a creates ASCII armored output, -b (--detach-sign) creates a detached signature, and -u (--local-user) is provided a user ID as the key to sign with. -o specifies the file to write the output to.

Finally, upload your transition statement and signatures (i.e., gpg_transition.txt, sig_1.txt, sig_2.txt) to a public place.

GPG Command Line Interface (CLI) Commands

The following commands can be used at the gpg> command prompt after running gpg --edit-key ex_user_id:

gpg> help
Display GPG CLI commands.
gpg> adduid
gpg> save

Add a user ID to a key.

gpg> uid ex_uid_number
gpg> primary
gpg> save

Set a user ID as the primary user ID for a key.

gpg> addkey
Add a new signing key to a master key.
After running addkey, you will need to choose a (sign only) option (e.g., (4) RSA (sign only)), as well as specify the length of the key (e.g., 4096), and a length of time before the key expires (e.g., 5y).
Make sure to run the save command after you are done.
gpg> revkey
gpg> save

Revoke a key.

gpg> trust
Trust a public key.

Documentation

For more on PGP/GPG, run the man 1 gpg command. Also, in-depth documentation is available online:

Checksums

A checksum a small-sized datum derived from a block of digital data that is used to verify data integrity.

Checksum Commands

sum ex_file...
Checksum and count the blocks in a file.
shasum ex_file...
Print or check Secure Hash Algorithm (SHA) checksums.
You can specify which algorithm to use with the -a ex_algorithm (--algorithm ex_algorithm) option. You will need to pass in a specific algorithm as an argument (e.g., 512, 512224, 512256).
shasum is a perl script that points to actual GNU/Linux commands, like sha512sum, that do the work.
shasum ex_file > ex_file.sha
Generate a checksum for a file and save the checksum to a .sha file.
shasum -c ex_file.sha, shasum --check ex_file.sha
Verify the checksum for a file from a .sha file.
ex_file.sha and ex_file should be located in the same directory.

Documentation

For more information on checksums, run the following commands:

  • man 1 sum
  • man 1 shasum

Secure Shell (SSH)

Secure Shell (SSH) is a Transmission Control Protocol/Internet Protocol (TCP/IP)-based networking protocol. It provides data transmission in a public network using strong authentication and encryption. Its applications include interactive sessions, file transfer, and the secure forwarding of other protocols (i.e., tunneling).

Encryption is important for preventing unauthorized people listening to network traffic from being able to read the content being transferred. Authentication ensures that you, as the user, are communicating with the correct server and that the server lets you access the correct user account.

OpenSSH, which comes with most GNU/Linux distributions, is a freely available implementation of SSH (on Debian, you can install the OpenSSH server with the # apt install openssh-server command). This implementation contains SSH clients, as well as an SSH server (sshd).

Used properly, SSH can prevent the following attacks:

  • Forged or adulterated DNS entries (DNS spoofing).
  • When an attacker sends datagrams from one host, which pretend that they come from another (trusted) host (IP spoofing).
  • When a host can pretend that datagrams come from another (trusted) host (IP source routing).
  • Sniffing of passwords and content transmitted in the clear on hosts along the transmission path.
  • Manipulation of transmitted data by hosts along the transmission path.
  • Attacks on the X11 server by means of sniffed authentication data and spoofed connections to the X11 server.

SSH offers a complete replacement for the insecure Teletype Network (TELNET), Remote Login (RLOGIN), and Remote Shell (RSH) protocols. In addition, it enables users to copy files from or to remote hosts, and is a secure replacement for Remote Copy (RCP) and the many applications of File Transfer Protocol (FTP).

There are two versions of the SSH protocol, 1 and 2. Most servers can accept connections using both versions. Avoid using version 1, which exhibits various security vulnerabilities.

OpenSSH

A Certificate Authority (CA) issues public key certificates. A public key certificate is a digital message signed with the private key that provides a cryptographic binding between the public key and the organization that owns the private key.

A certificate contains the following information:

  • The name of the organization
  • The public key of the organization
  • The expiration date of the certificate
  • The certificate's serial number
  • The name of the CA that signed the certificate
  • A digital signature from the CA

There are two types of CAs:

  1. Internal CA (OpenSSL, the library that OpenSSH relies on, is used to create a CA on your system)
  2. External CA

OpenSSH provides the following encryption-enabled components:

  • sshd Allows remote access to the shell prompt.
  • ssh The ssh client used to connect to sshd on another system.
  • scp Used to securely copy files between systems.
  • sftp Used to securely FTP files between systems.
  • slogin Used to access the shell prompt remotely (slogin is just a symbolic link to ssh).

System-Specific SSH Configuration

The SSH configuration directory is located at /etc/ssh/. Its permissions should be set to 755.

/etc/ssh/ contains several important files.

/etc/ssh/sshd_config

The main configuration file for the sshd daemon. Its options include:

AllowUsers
Restricts logins to the SSH server to only the users listed. Specify a list of users separated by spaces.
DenyUsers
Prevents the users listed from logging in through the SSH server. Specify a list of users separated by spaces.
HostKey
Specifies which private host key file should be used by SSH.
ListenAddress
If the host where sshd is running has multiple IP addresses assigned, you can restrict sshd to only listening on specific addresses using this parameter. The syntax is ex_listen_address ex_ip_address:ex_port.
PermitRootLogin
Specifies whether you can authenticate through the SSH server as the root user.
Port
Specifies the port on which sshd will listen for SSH requests.
Protocol
Specifies which version of SSH to use. Specify one of the following (1, 2, 2,1).
/etc/ssh/ssh_config

The main configuration file for the ssh client. Its options include:

Port
Specifies the port number to connect to on the SSH server system to initiate an SSH request.
Protocol
Specifies which version of SSH to use. Specify one of the following (1, 2, 2,1).
StrictHostKeyChecking
If set to a value of yes, the client can only establish connections to SSH servers whose public key has already been added to either the /etc/ssh/ssh_known_hosts or ${HOME}/.ssh/known_hosts file.
User
Specifies the user to log in to the SSH server as.

The precedence for SSH client configuration settings is as follows:

  1. Any command-line options included with the ssh command at the shell prompt.
  2. Settings in the ${HOME}/.ssh/config file.
  3. Settings in the /etc/ssh/ssh_config file.
/etc/ssh/ssh_known_hosts
This file is used to check the public key of a remote server you are attempting to connect to via SSH (i.e., it is a list of remote SSH server public keys).
/etc/ssh/ssh_host_ex_key
The private part of the host's key structure, where ex_key represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g., rsa, ecdsa).
/etc/ssh/ssh_host_ex_key.pub
The public part of the host's key structure, where ex_key represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g., rsa, ecdsa). Its permissions should be set to 644.

User-Specific SSH Configuration

The user-specific SSH configuration directory is ${HOME}/.ssh/. It contains several important files.

${HOME}/.ssh/config
The user configuration file for the ssh client.
${HOME}/.ssh/authorized_keys
Used to store the public keys for remote clients attempting to connect via SSH to a SSH server (i.e., this file is a list of remote SSH client public keys). These keys are matched with the keys presented by an ssh or scp client upon login request.
${HOME}/.ssh/known_hosts
Used to check the public key of a remote server you are attempting to connect to via SSH (i.e., this file is a list of remote SSH server public keys).
${HOME}/.ssh/ex_key
The private part of the host's key structure, where ex_key represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g., rsa, ecdsa).
${HOME}/.ssh/ex_key.pub
The public part of the host's key structure, where ex_key represents a specific cryptographic method that clients can use to check for the server's authenticity (e.g., rsa, ecdsa). Its permissions should be set to 644.

Logging Into a Host

To log into a remote host using SSH, invoke the ssh command:

ssh ex_host

ex_host can be either a hostname or an IP address.

ssh assumes that your username on the remote host is the same as the local username. If this is not the case, specify the remote user name:

ssh ex_username@ex_host

If /etc/nologin is present, no user can log in to the system except for the root user. Non-root users will see the contents of this file (or /etc/nologin.txt).

The SSH Connection

The following steps take place to establish a SSH connection:

  1. Client and server send each other information about their host keys and supported cryptographic schemes.

    The client negotiates a shared secret with the server, which then serves as the symmetric key to encrypt the connection. Simultaneously, the client checks the server's authenticity and breaks the connection if there is a discrepancy.

    The details of this process are outlined in RFC4253.

  2. The server checks the client's authenticity using one of several methods. The password is already sent over the encrypted connection and, unlike other protocols like FTP or TELNET, cannot be sniffed by people who listen in.

The first step is important. The following example shows what happens if you contact the remote host for the first time:

$ ssh io.example.com
The authenticity of host 'io.example.com (192.168.33.2)' can't be established.
RSA key fingerprint is 81:24:bf:3b:29:b8:f9:f3:46:57:18:1b:e8:40:5a:09.
Are you sure you want to continue connecting (yes/no)?

The host io.example.com is still unknown here and ssh asks you to verify its host key. If you skip this verification step, you lose the guarantee that no one is listening in to your connection.

After having established a connection using ssh, you can use the remote host as if you were in front of it. You can close the connection using the exit command or Control+d.

Unless you specify otherwise, during interactive ssh sessions, the tilde (~) is considered a special escape character if it occurs immediately after a newline character. This lets you control ssh during an ongoing session.

In particular, the ~. sequence will close the connection, which may be useful if a program has become stuck at the remote end. You can do other interesting things with escape characters. Run man 1 ssh for more information.

ssh does not restrict you to interactive sessions, but lets you execute single commands on a remote host:

$ ssh io.example.com hostname
io.example.com

Keep in mind, the shell on your computer will try to process the command line in order to replace shell wildcard patterns before it is transmitted to the remote host. Use backslashes or quotes to disable filename expansion if you are in doubt.

Verifying Remote Host Authenticity

Here, there is a danger that someone will intercept your connection request and pretend that they are a remote host that you are trying to connect to, like io.example.com. They can surreptitiously establish their own connection to io.example.com and pass everything along that you send to them.

Conversely, they can forward io.example.com's answers back to you. You will not see a difference, and the attacker can read everything that you transmit, i.e., a person-in-the-middle (PITM) attack.

To check for this type of attack, you need to contact the remote system's administrator (via an out-of-band connection method, e.g., a telephone call) and ask them to read their public key's fingerprint. This can be displayed using ssh-keygen -l -f ex_ssh_pub_key_file and must be identical to the key fingerprint from the SSH login dialogue.

SSH Key Pairs

The SSH key pairs of a host can be found in the ssh_host_ex_key and ssh_host_ex_key.pub files within the /etc/ssh/ and ${HOME}/.ssh/ directories. ex_key represents a specific cryptographic method that clients can use to check the server's authenticity.

Possible values of ex_key include:

dsa
The DSA algorithm. This only allows 1024-bit keys and should be avoided because it is susceptible to weaknesses in random number generation.
ecdsa
The DSA algorithm based on elliptic curves. This lets you pick between 256, 384, and 521 bits. Elliptic curves do not need as many bits, so the lower numbers are not problematic.
ed25519
A fast and secure method invented by Daniel J. Bernstein. Within the SSH context, this is still fairly new.
rsa
The RSA algorithm. This is secure, as long as you use keys that are longer than 2048 bits (4096 bits or higher is preferable).

An SSH key pair is a set of two matching keys, one private and one public. The public key may be told to everyone as long as the private key stays confidential. Whatever is encrypted using the public key can only be decrypted using the private key from the same pair, and vice versa (i.e., asymmetric cryptography).

Verifying Remote Server Authenticity

When connecting to a remote server via SSH and you have ensured that the remote host's public key is authentic, ssh will store the remote server's public key in the ${HOME}/.ssh/known_hosts file once you have agreed to accept the remote server's fingerprint. The ${HOME}/.ssh/known_hosts file is used as a base for comparison during future connection requests.

If you ever see a WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! message when trying to establish a ssh connection, you may be the subject of a PITM attack. The public key that the server presents does not match the one stored for the server in the ${HOME}/.ssh/known_hosts file. You should contact the remote host's administrator to find out what is going on (i.e., perhaps the host key needed to be changed for valid reasons).

How ssh behaves in regard to evaluating remote hosts' keys can be configured in the ${HOME}/.ssh/config (or the /etc/ssh/ssh_config file for system-wide changes).

StrictHostKeyChecking ask
The default setting.
StrictHostKeyChecking no
Always accept everything.
StrictHostKeyChecking yes
Never accept anything new.

When StrictHostKeyChecking yes is set, you can only establish connections to hosts that are already in your known_hosts file. All others will be refused.

Verifying Remote Client Authenticity

Normally, the SSH server will authenticate you as a user by means of a password that is assigned to your account on the server (usually in /etc/passwd or /etc/shadow). Since the password is queried only after the encrypted connection has already been established, this is, in principle, safe from unwanted listeners.

However, your password itself is stored on the server. Even though it is encrypted, the password file could be compromised. It would be better if nothing secret about you would be stored on the remote server at all.

You can achieve this by using public-key client authentication instead of the password-based client authentication. In short, you create a key pair for your SSH client consisting of a public and private key, and deposit the public key on the SSH server.

The public key does not need to be specially protected. You will need to keep the private key, which should never leave your computer (you can also put your private key on a USB stick or specialized hardware token).

Public Key Client Authentication

If you configure the SSH server to use public key authentication, the SSH client tells the SSH server which public key should be used for authentication when the SSH session is initially established. Then, the SSH server checks to see if it has that client’s public key (i.e., is the public key present in the authorized_keys file for the associated user). If it does, it generates a random number and encrypts it with that public key.

It then sends the encrypted number to the client, which decrypts it using the private key associated with the public key. The client then calculates a checksum of the number it received from the server.

It sends the checksum to the SSH server, which then calculates its own checksum of the number it originally sent. If the two checksums match, then the user is automatically logged in.

All of the above takes place across the encrypted connection and is secure from unwanted listeners that want to manipulate your data.

To use public-key client authentication, you first need to generate a key pair. This is done using the ssh-keygen command:

ssh-keygen -t rsa -b 4096

The -t ex_key_type option specifies the type of key to create. Accepted values are:

  • dsa
  • ecdsa
  • ed25519
  • rsa

The -b ex_bits option specifies the number of bits in the key to create.

First, the command asks where you want the key pair to be stored. The default location (i.e., ${HOME}/.ssh/) is reasonable. Next, ssh-keygen asks for a passphrase. This is used to encrypt the private key in order to prevent someone who happens to find your private key from impersonating you to a SSH server.

You must use keys without a passphrase for non-interactive SSH connections, e.g., for shell scripts and cron jobs. In this case, you just press Enter when you are asked for the passphrase.

It is possible to connect a public key on the server with a particular command. Then, client connections using this public key will not launch a shell session. Instead, the command in question will be directly started. This can significantly mitigate the security risk with unencrypted private keys for the use of scripts.

The result of ssh-keygen are the two files id_ex_key and id_ex_key.pub in the ${HOME}/.ssh/ directory (the exact key file names will depend on the type of key that you create). The former contains the private key and the latter the public key.

When you first generate a key pair, ssh-keygen also shows you the fingerprint of the public key and a randomart image. The latter is a graphical representation of the public key, i.e., a kind of graphical fingerprint. Theoretically, this should enable you to tell at a glance whether a public key has changed or not.

The next step is to deposit the public key (i.e., the content of the id_ex_key.pub file) in the ${HOME}/.ssh/authorized_keys file for your user account on the remote host. This is most easily done using the ssh-copy-id command:

ssh-copy-id ex_username@ex_remote_host

If you set the PasswordAuthentication entry in the /etc/ssh/sshd_config file on the remote server to no and PubkeyAuthentication to yes, then users can only authenticate via the public key method. Essentially, this is a good idea since attackers enjoy running automatic programs that try obvious passwords on SSH servers.

ssh-agent

If you are using a passphrase for your private SSH key, public-key authentication is not more convenient than password authentication, but more secure. If you want to log into the same host as the same user several times in a row, constantly re-entering your private SSH key's passphrase can be a nuisance. The ssh-agent was developed to help with this.

The ssh-agent program remembers your private SSH key's passphrase and passes it to SSH client programs, as needed. For example, the program is started using ssh-agent bash. This opens a new bash shell in which you must add the private SSH key passphrase using ssh-add:

$ ssh-add
Enter passphrase for /home/amnesia/.ssh/id_rsa: foobar
Identity added: /home/amnesia/.ssh/id_rsa (/home/amnesia/.ssh/id_rsa)

Every instance of ssh, scp, or sftp started from the new shell gets the passphrase from the SSH agent. The agent forgets the passphrase once you leave the shell using exit or instruct it to using ssh-add -D to forget all stored identities (with Debian, the login shell/GUI may be started with the ssh-agent active right away, so you can ssh-add your passphrase at the very beginning of your session).

ssh-agent increases convenience to the detriment of security. If you leave your computer unattended (or if you lose your suspended laptop), an unauthorized person might be able to use SSH programs without being asked for a passphrase. The same applies to programs that get access to your session.

Secure Copy (scp)

Using scp, you can copy files between two hosts via an SSH connection. scp's syntax is based on the cp command. Files and directories can be specified with either absolute or relative paths, and ex_host can be either a hostname or an IP address.

The following command copies remote files to a local directory:

scp ex_host:ex_source_file... ex_destination_directory

This command copies local files to a remote host:

scp ex_source_file... ex_host:ex_destination_directory

Directories can be recursively copied via scp's -r option. This example recursively downloads a remote directory to a local directory:

scp -r ex_host:ex_source_directory ex_destination_directory

It is possible to copy files between two remote hosts, as well. This example copies files from one remote host to another remote host:

scp \
    ex_username@ex_host_1:ex_file... \
    ex_username@ex_host_2:ex_destination_directory

Secure File Transfer Protocol (SFTP)

The sftp command is loosely inspired by common FTP clients, but needs an SSH connection. Otherwise, it has nothing to do with FTP. In particular, you cannot use it to communicate with an FTP server.

sftp ex_username@ex_host

ex_host can be either a hostname or an IP address.

After having established a connection using a command like sftp ex_username@ex_host, you can use commands like get or put to transfer files between your local host and the remote host, inspect the contents of a directory on the remote host using ls, and change into different directories on the remote server by means of cd.

At the beginning of a session, you will be placed in your home directory on the remote computer. To end a session, enter quit.

SSH Port Forwarding (Tunneling)

SSH can be used to encrypt clear-text traffic by tunneling it through a SSH connection. When client software for the tunneled protocol (e.g., an e-mail client using POP3) establishes a connection with the local SSH client, the traffic is encrypted using SSH and tunneled through to the SSH server.

On the SSH server's end, the traffic is decrypted and forwarded to the appropriate target service (e.g., the POP3 daemon). This is desirable because the information is encrypted before being transmitted, even though the original protocol (POP3) does not support encryption.

To utilize SSH port forwarding, ensure that AllowTcpForwarding yes is set in the /etc/ssh/sshd_config file.

To create a local SSH tunnel from a local high port to the port that you want to tunnel, you can use the following command (you may need to enter the remote user's password when prompted):

ssh -f -N -L \
    ex_local_port_number:ex_host:ex_port_number_to_tunnel ex_username@ex_host

The -f option tells ssh to go into the background just before command execution and the -N option prevents the execution of remote commands. Together, these options are useful for SSH port forwarding.

The -L option specifies three things:

  1. The local port to be used for the client end of the tunnel (e.g., 59823). If you want to use a port number less than 1024, you will need to switch to the root user, as these are privileged ports.
  2. The hostname or IP address of the remote server running the service that we want to tunnel (e.g., POP3).
  3. The port number on the remote server that will be used for the server end of the tunnel (i.e., the port number to tunnel, like port 110 for POP3).

The final argument in the above command, ex_username@ex_host, is the remote SSH user and host.

Next, configure the local client program to receive communications via the port that you configured for the client end of the SSH tunnel (i.e., port 59823). You can test the tunnel that you created using the netcat command from the client end of the tunnel. The syntax is netcat localhost ex_client_tunnel_port.

For example:

netcat localhost 59823

Afterwards, you should see a connection established with the remote system where the tunneled service daemon is running.

SSH can forward and tunnel nearly every other TCP-based protocol by using the -R and -L options. The following command tunnels connections to the local TCP port 10110 first via an SSH connection to the computer io.example.com. From there, it continues (unencrypted) to the TCP port 110 (POP3) on the mail.example.com host:

ssh -L 10110:mail.example.com:110 amnesia@io.example.com

There are benefits to this approach:

  • Imagine that your firewall blocks POP3, but allows SSH traffic. By means of the port redirection, you can enter the internal network via SSH and then connect from the io.example.com host to the mail server on the internal network. In your mail program, you need to specify localhost and the local TCP port 10110 as the POP3 server.
    • Theoretically, You could forward the local TCP port 110, but you need to be root to do it.
  • The name of the forwarding destination host (i.e., mail.example.com) is resolved from the perspective of the SSH server (io.example.com). This means that a redirection of the form ssh -L 10110:localhost:110 amnesia@io.example.com connects you to port 110 on io.example.com, rather than your own computer.
  • A port forwarding like -L 10110:mail.example.com:110 opens port 10110 on all IP addresses on your computer. This opens the redirection, in principle, to all other hosts that can reach this port over the network.

    To prevent this, you can use the fact that ssh allows you to specify a local address for the redirected port. With -L localhost:10110:mail.example.com:110, the redirection only applies to the local interface.

If you invoke ssh as shown in the ssh -L 10110:mail.example.com:110 amnesia@io.example.com command, you get an interactive session on top of the port forwarding. If you do not need this (e.g., because the forwarding takes place within a cron job), you can specify the previously mentioned -N option, which restricts ssh to do the port forwarding and not establish an interactive session.

Another technique for automatically forwarding services uses a ssh invocation like:

$ ssh -f -L 10110:mail.example.com:110 amnesia sleep 10
$ getmail_fetch -p10110 localhost amnesiamail Mail123 Maildir/

The -f option causes the ssh process to immediately go to the background before the sleep 10 command is executed. This means that a command that you immediately execute after the ssh command (here, getmail_fetch, which retrieves email via POP3) has 10 seconds to establish a connection to the local port 10110. The ssh process exists either after 10 seconds or else when the last connection via the local port 10110 is torn down, whichever occurs later.

Port forwarding also works the other way around. For example, ssh -R 10631:localhost:631 amnesia@io.example.com opens the TCP port 10631 on the SSH server, and connections that programs there make with that port are redirected across the SSH connection to your local host.

Your local host then takes care of redirecting the decrypted data to the destination, here port 631 on your local host. This type of port forwarding is considerably less important than the forwarding using -L.

Usually, the -R port forwarding binds the remote port to the localhost interface on the SSH server. In principle, you can pick another interface, but whether that works or not depends on the configuration of the SSH server.

You can add port forwarding after the fact using the ~C key combination, which gives you a command line:

$ ~C
ssh> -L 10025:localhost:25
Forwarding port

On the command line, you can add -L and -R options, as if you had typed them directly on the ssh command line. Using -KR, followed by the port number, you can also cancel a -R port forwarding.

With the ~# command, you can check the currently active connections:

$ ~#
The following connections are open:
  #2 client-session (t4 r0 i0/0 o0/0 fd 6/7 cfd -1)
  #3 direct-tcpip: listening port 10025 for localhost port 25,
    connect from 127.0.0.1 port 57250
    (t4 r1 i0/0 o0/0 fd 9/9 cfd -1)

X server traffic can also be tunneled to remote X clients using an SSH connection (i.e., you can execute graphical programs on a remote host, where graphics output and keyboard/mouse input take place on your local computer).

To configure a remote X client without encryption, you can use the following procedure:

  1. On the remote X client, enter xhost +ex_x_server_hostname. This tells the client to accept connections from the X server.
  2. On the X server, enter export DISPLAY=ex_x_client_hostname:0.0. This tells the X server to display its output on the remote X client.
  3. From the X client, use the ssh client to access the shell prompt on the X server and then run the graphical application that you want displayed on the X client.

To use SSH to tunnel the X server traffic between the X server and the X client:

  • Use the -X option with the ssh client program (e.g., ssh -X ex_username@ex_host). When logging in using -X, the DISPLAY variable is set up to point to a proxy X server provided by sshd. This directs X clients started on the remote host to this server.

    Everything a remote X client sends to the proxy X server is sent to the (real) X server on the SSH client. All the X11 traffic is encrypted so that eavesdroppers cannot listen in (i.e., it is tunneled).

  • Set the X11Forwarding option to yes in the /etc/ssh/sshd_config file on the X server system.

You can also globally enable X11 forwarding in order to avoid having to type the -X option. To do so, add ForwardX11 yes to your ${HOME}/.ssh/config SSH client configuration file (or the /etc/ssh/ssh_config SSH client configuration file for a system-wide default).

X11 forwarding is preferable to the standard X packet redirection (using DISPLAY) not only because of its increased security, but because it is more convenient. You pay for this with some extra effort for encryption (which, on modern hardware, is negligible).

X11 forwarding is not without security risks. Users that can circumvent file access rights on the remote host (e.g., because they are root) may access your local X11 display. For this reason, you should probably avoid globally enabling X11 forwarding. The same risk exists with conventional X11 redirection using DISPLAY.

More information on ssh configuration can be found by running man 5 sshd_config.

SSH Commands

ssh-keygen -t ex_key_type -b ex_bits
Generate authentication keys for ssh.
The -t option specifies the type of key and the -b option specifies the number of bits in the key to create (e.g., ssh-keygen -t rsa -b 4096).
ssh-keygen -l -f ex_public_key
Show fingerprint of specified public key file.
The -l option tells ssh-keygen to display a public key file fingerprint and the -f option is used to specify the filename of the public key file.
Add the -v option to display a visual ASCII art representation of the key along with the fingerprint (e.g., ssh-keygen -l -f "${HOME}/.ssh/id_rsa.pub" -v).
ssh-copy-id ex_host
Use locally available keys to authorize logins on a remote machine, i.e., upload your user's public keys to a remote server (this command assumes that you already have access to ex_host). ex_host can be either a hostname or an IP address.
ssh-copy-id assembles a list of one or more fingerprints and tries to log in with each key to see if any of them are already installed. Then, it assembles a list of those that failed to log in and, using ssh, enables logins with those keys on the remote server. By default, it adds the keys by appending them to the remote user's ${HOME}/.ssh/authorized_keys file.
The alternative ssh-copy-id ex_username@ex_host form can be used to specify a specific user.
ssh ex_destination
Connect and log into ex_destination, which may be specified as ex_host, ex_username@ex_host, or a URI of the form ssh://[user@]hostname[:port], where [user@] and [:port] are optional.
Add the -p ex_port option to ssh ex_destination to specify the port to connect to on the remote host (ssh -p ex_port ex_destination).
Add the -i ex_identity_file option to ssh ex_destination to select the file from which the identity (i.e., private key) for public key authentication is read (ssh -i ex_identity_file ex_destination).
Append ex_command to ssh ex_destination to specify a command to execute on the remote host, instead of being provided with a login shell (ssh ex_destination ex_command).
To log out of a SSH session, use the exit command or Control+d.
ssh-agent "${SHELL}"
Invoke the ssh-agent as a wrapper to your shell. This command puts you in a shell that is spawned by ssh-agent.
The ssh-agent resides in memory and places a security wrapper around your shell session, answering any SSH-related security requests for you. After entering a private SSH key's passphrase once, ssh-agent will remember it and automatically apply it for you, when necessary.
ssh-add
Add your user's private SSH key to ssh-agent. When prompted, enter the key file’s passphrase. Once done, ssh-agent stores the passphrase in memory. Then, it listens for SSH requests and automatically provides the key passphrase for you, when requested.
This command needs to be run after ssh-agent "${SHELL}". It tries to add the standard key identity to the key manager.
A key with a different location can be added by entering ssh-add ex_key_path.
scp ex_source... ex_target
Copy objects between network hosts.
ex_source and ex_target can be specified as a local path, a remote host with optional path in the form [user@]host:[path] (e.g., scp ex_file... ex_username@ex_host:ex_directory or scp ex_username@ex_host:ex_file... ex_directory), or a URI in the form scp://[user@]host[:port][/path].
Add the -r option to copy directories recursively.
Add the -P ex_port option to specify the port to connect to on the remote host.
Add the -i ex_identity_file option to select the file from which the identity (i.e., private key) for public key authentication is read.
Make sure that all used options come before the hosts in question in your scp commands.

Documentation

For more information on SSH, run the following commands:

  • man 8 sshd
  • man 1 ssh
  • man 5 ssh_config
  • man 1 ssh-keygen
  • man 1 ssh-add
  • man 1 ssh-agent
  • man 1 scp
  • man 1 sftp

These manual pages can also be viewed online.

Enjoyed this post?

Subscribe to the feed for the latest updates.