SDB:Secure installation sources

Jump to: navigation, search

Secure Installation Sources

You can get the installation media or online installation sources for SUSE Linux from many public mirrors, and various Internet resources offer additional packages as installation sources. This greatly increases the scalability of the openSUSE project and adds many interesting software packages to the openSUSE ecosystem.

But there always is a potential risk involved with using those sources. How do you know that the installation sources are unmodified, complete, and don't contain any malicious code?

Starting with SUSE Linux 10.1 this problem has been addressed by using a combination of cryptographic signatures and checksums.

Here is a brief outline of the metadata and package signing concept for SUSE Linux 10.1 and beyond:

We use detached GPG signatures to sign the most important metadata files in an installation source/repository. There are two flavors of installation sources that are addressed:

"Classic" SUSE-style installation sources

This is what we are using on the installation media. They are often called "YaST sources", although YaST supports other sources, too. There are two entry points:

The file "media.1/products"

This file lists the absolute paths (absolute from the root of the installation source file tree) to the products on a media. This is interesting for multi-product media. But usually there is only one line, e.g.

   / SUSE-Linux-Enterprise-Desktop 10

This file will be signed with a SUSE key on all products coming from SUSE. The public key (GPG public key, ascii armor protected) for this key that can be used to verify the signature is in the file "products.key" for convenience.

This key will also be imported from the initrd (the initial bootable Linux image that always starts first if you run an installation media), so usually YaST will already know about it. This is not the case yet on the current betas. The initial key is the one YaST always trusts without asking. The key is usually also on the installation media as

   /gpg-pubkey-9c800aca-40d8063e.asc

(This key may change. The one above is the one we currently use.)

The signature for "products" is in the file "products.asc".

When YaST detects an installation source it checks if the file "products" is there, and then checks if it is signed with a known key. If it is not signed at all or with an unknown key, or if the key is on the media, but not trusted (yet), the user will be asked what to do.

We sign the "products" file to make sure nobody can add products to an installation source that don't belong there.

The file "content"

For every product there is a "content" file. If there is no "products" file that tells us where the products are, we look for the "content" file in the installation source's root.

The "content" file is signed in the same manner as the "products" file, so there is a "content.key" (usually, but not necessarily the same as "products.key").

Compared to "content" files on older releases we have additional data. There are two new keys: META and KEY. Here are two examples:

   META SHA1 08579e4b28287d6aedd954098b64c6bb49d17367 packages
   KEY SHA1 a108c6aab19fe604fa98ef299cdce6e6ba275f09 gpg-pubkey-0dfb3188-41ed929b.asc

META keys are added for all files in the directory named in the key DESCRDIR, e.g.

   DESCRDIR suse/setup/descr

on a typical SUSE Linux.

Before YaST uses any file from DESCRDIR it will look up the entry in "content". This entry is currently a SHA1 checksum followed by the package name. This may change to a SHA256 checksum.

The KEY entries list all the keys that YaST should import from the media. Those keys can be used for checking RPM signatures and metadata signatures and will be stored in the RPM database, so they can be used with "rpm --checksig" for package-level verification.

YaST trusts these KEYs by default because the list of KEYs is in a file that was signed by the initial key which by default is trusted by initrd.

The next step in the chain is the file "packages" in DESCRDIR.

If you are familiar with its syntax you will see that we added a new tag there, too, right after the "Pkg:" tag. Here is an example of the first two lines of the entry for the default kernel:

   =Pkg: kernel-default 2.6.16 13 i586
   =Cks: SHA1 8c8eb2b605e1d626c22bea8dd0c3b05885432b16

Again we have a SHA1 checksum.

So there is a consistent chain of trust from the initial key (that you need to verify on your own if you don't trust your installation media) via the "product" and "content" files to the individual packages. The chain makes sure that all those files belong there and haven't been manipulated.

On the package level we may or may not perform an additional "rpm --checksig".

Cryptographic keys for installation media

The installer will happily find keys on additional installation sources automatically and offer them for import.

Interesting however is the case where you create your own installation media. When the installation starts the rpm database is not available to store the keys yet, so no dialog is offered for import.

To get your public key accepted for this source is to put it along side the trusted master keys.

Those can be found in the "initial ramdisk" aka "initrd" which usually contains the /linuxrc and kernel modules to load before mounting the rootfs.

These initrds can be found on the UL media in /boot/architecture/loader/initrd (for x86 and x86_64) or in /suseboot/initrd32 / initrd64 on PowerPC.

To add your new trusted key to the initrd do (assuming $initrd points to your initrd):

   gunzip <$initrd >$initrd.uncomp
   gpg --export -u $keyid > gpg-$keyid.gpg
   echo "gpg-$keyid.gpg" | cpio -o -H newc -A -F $initrd.uncomp
   gzip --best <$initrd.uncomp >$initrd
   rm $initrd.uncomp gpg-$keyid.gpg

This will decompress the initrd, append the just extracted public key, and recompress it. Do this for all initrds found on the media (some have more than one).

The "repomd" or "YUM" format

Here we use the same basic concept. The initial file is "repomd.xml", which is again signed with a detached GPG signature in "repomd.xml.asc".

Usually repomd repositories will be used for updates and as an add-on source, so the keys are known to the the system already. But you can place the public key of the GPG key pair used for signing "repomd.xml.asc" next to it as "repomd.xml.key".

In case you are using a new key for the repository that is not in the RPM keyring yet, the user will be asked if he wants to accept that key before the repository is registered.

In repomd.xml and all the files referenced from there, a <checksum> tag again makes sure that the installation/update source is consistent. Here is an example snippet:

   
   <location href="repodata/patches.xml"/>
   <checksum type="sha">90ac427749079973d044a9398d6749f5f008</checksum>
   <timestamp>1144088097</timestamp>
   <open-checksum type="sha">90ac4044a9398d6749f5f008</open-checksum>
   

repomd uses those checksums by default. The only thing we added is signing the "repomd.xml" file.

This is very simple to do:

      cd <repository directory>
      createrepo .
      gpg -a --detach-sign repodata/repomd.xml

You can also use -b instead of --detach-sign for it is shorter.

To supply your GPG key right with the source:

      gpg -a --export <your key id> > repodata/repomd.xml.key