Verify a signature
Software distribution is often done by downloading an installer from a website. If you don't want to rely on the integrity of the website, you cannot be sure that the installer in not tempered with.
To help you asserting the authenticity of the downloaded file, the provider of the file can create a downloadable signature of it, which you can verify. A successful verification means that the downloaded file was not manipulated after the signature was created.
This tutorial contains a very verbose walk through a verification, explaining each step.
1. Getting the files
The Tails project offers an integrity check via signature, so we will use it as an example.
First, download the ISO-image and the signature from the tails website. You can use your browser or any other suitable tool. This example uses wget
.
To get the software from the website, go to tails.net/install, choose your OS and follow the instructions to download tails and the OpenPGP signature.
For using wget
, go to your working directory and download the files as follows (replace folder and file names with current version):
$ wget https://download.tails.net/tails/stable/tails-amd64-6.2/tails-amd64-6.2.img
$ wget https://tails.net/torrents/files/tails-amd64-6.2.img.sig
2. Inspect the signature
If you look at the directory, you can see the two files that you downloaded. The first one is the tails image and the second is the detached signature.
$ ls -l
total 1431572
-rw-r--r-- 1 alice alice 1465909248 Apr 22 12:35 tails-amd64-6.2.img
-rw-r--r-- 1 alice alice 833 Apr 23 13:20 tails-amd64-6.2.img.sig
By using sq inspect
, you can now have a closer look into the signature file:
$ sq inspect tails-amd64-6.2.img.sig
tails-amd64-6.2.img.sig: Detached signature.
Alleged signer: 05469FB85EAD6589B43D41D3D21DAD38AF281C0B, Tails developers (offline long-term identity key) <tails@boum.org> (UNAUTHENTICATED)
Note: Signatures have NOT been verified!
What you got here is the signing key's fingerprint. Now check what the web of trust tells about this alleged signer:
$ sq network search 05469FB85EAD6589B43D41D3D21DAD38AF281C0B
Importing 13 certificates into the certificate store:
1. 09F6BC8FEEC9D8EE005DBAA41D2975EDF93E735F Tails developers (Schleuder
mailing-list)
<tails@boum.org> (partially authenticated, 1/120)
2. 0109B6D7680FEEFDCE783EEE750AE75857622766 Tails APT repository <tails@boum.org>
(UNAUTHENTICATED)
3. 0D24B36AA9A2A651787876451202821CBE2CD9C1 Tails developers (signing key) <tails@boum.org> (UNAUTHENTICATED)
4. 2ED1191631B0B60CB27DA90A4C3DB83F3F50D2D9 gpg --check-sigs A490D0F4D311A4153E2BB7CADBB802B258ACD84F <tails@boum.org> (UNAUTHENTICATED)
5. 317026534CCC841EF92EB5D4F370463ECD68841B Tails developers <tails@boum.org> (UNAUTHENTICATED)
6. 3E97E609FC8DAE546FB6DF005C20D5DCAECAEF90 Tails developers <tails@boum.org> (UNAUTHENTICATED)
7. 98D080F83122CB4A3F45663825BF6AAECF914C38 Tails <tails@boum.org>
(UNAUTHENTICATED)
8. 9BF8721D77F0242C8A6D0507D911B4A137BD2413 Tails developers (offline long-
term identity key) <tails@boum.org> (UNAUTHENTICATED)
9. A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers (offline long-
term identity key) <tails@boum.org> (UNAUTHENTICATED)
10. B6C645C871D595069ED1AE33DB1573A449F1F400 gpg --check-sigs
A490D0F4D311A4153E2BB7CADBB802B258ACD84F <tails@boum.org> (UNAUTHENTICATED)
11. C3BAA4BFE369B2B86018B5150E08AC7806C069C8 BIGHEAD2 <TAILS@BOUM.ORG> (UNAUTHENTICATED)
12. D55A59A2CAFC5EAB7AA4777010C2D872BFBAF237 Tails <tails@boum.org> (UNAUTHENTICATED)
13. EB24960079A3E2B93BFE48B505F8BB78B38F4311 Amsesia <amnesia@boum.org> (UNAUTHENTICATED)
Imported 0 new certificates, updated 0 certificates, 13 certificates > unchanged, 0 errors.
After checking that a certificate really belongs to the stated owner, you can > mark the certificate as authenticated using:
sq pki link add FINGERPRINT
What you can see from this result is that the 9th certificate is the one mentioned on the tails website, which is a first step in the right direction. But you can also notice that none of the enumerated certificates has the fingerprint 05469FB85EAD6589B43D41D3D21DAD38AF281C0B
.
If this is the case, it is a reason to further investigate. When you have a look at the Fingerprint by using 'sq pki list', you will see that it is a subkey of the certificate that we have already noticed above:
$ sq pki list 05469FB85EAD6589B43D41D3D21DAD38AF281C0B
Certificate A490D0F4D311A4153E2BB7CADBB802B258ACD84F contains the subkey 05469FB85EAD6589B43D41D3D21DAD38AF281C0B.
A490D0F4D311A4153E2BB7CADBB802B258ACD84F will expire on 2025-01-25T09:24:54Z
[ 0/120 ] Tails developers (offline long-term identity key) <tails@boum.org>
[ 0/120 ] Tails developers <tails@boum.org>
To view why a user ID is considered valid, pass `--show-paths`
To see more details about a certificate, run:
$ sq inspect --cert FINGERPRINT
After checking that a user ID really belongs to a certificate, use `sq pki
link add` to mark
the binding as authenticated, or use `sq network search FINGERPRINT|EMAIL` to
look for new certifications.
3. Verify the signature
Check the detached signature:
$ sq verify --signature-file tails-amd64-6.2.img.sig tails-amd64-6.2.img
Authenticating A490D0F4D311A4153E2BB7CADBB802B258ACD84F ("Tails developers (offline long-term identity key) <tails@boum.org>") using the web of trust:
A490D0F4D311A4153E2BB7CADBB802B258ACD84F: "Tails developers (offline long-term identity key) <tails@boum.org>" is unauthenticated and may be an impersonation!
A490D0F4D311A4153E2BB7CADBB802B258ACD84F: "Tails developers <tails@boum.org>" > is unauthenticated and may be an impersonation!
Unauthenticated checksum from D21DAD38AF281C0B ("Tails developers (offline long-term identity key) <tails@boum.org>")
After checking that D21DAD38AF281C0B belongs to "Tails developers (offline
long-term identity key)
<tails@boum.org>", you can authenticate the binding using:
$ sq pki link add D21DAD38AF281C0B "Tails developers (offline long-term identity key) <tails@boum.org>"
1 unauthenticated checksum.
Error: Verification failed: could not fully authenticate any signatures
So far all is known is that the signature was made from the image file and the key with the fingerprint A490D0F4D311A4153E2BB7CADBB802B258ACD84F
. At this point nothing is known about the authenticity. The key has bindings to the displayed User IDs - it looks authentic, but for now these are just unfounded claims.
4. Authenticate the signature
Tails suggests to import its signing key and the key of Chris Lamb from the debian keyring. The idea is that there is trust in the debian developers. Chris is one of them and he signed the tails signing key.
5. Get the signing key
Get the signing key from the tails project and import it into your local cert store:
$ wget https://tails.net/tails-signing.key
$ sq cert import tails-signing.key
Imported A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers (offline long-term identity key) <tails@boum.org> (UNAUTHENTICATED)
Imported 0 new certificates, updated 0 certificates, 1 certificates unchanged, 0 errors.
The key is already in the local cert store. This shows that the key fetched by sq network search
and the one downloaded from the site are the same.
6. Export and inspect the certificate
Export Chris certificate from the debian keyring and inspect it:
$ sq cert export --keyring /usr/share/keyrings/debian-keyring.gpg --no-cert-store --userid "Chris Lamb <chris@chris-lamb.co.uk>" | sq inspect
-: OpenPGP Certificate.
Fingerprint: C2FE4BD271C139B86C533E461E953E27D4311E58
Public-key algo: RSA
Public-key size: 4096 bits
Creation time: 2009-07-12 19:43:47 UTC
Key flags: certification, signing
Subkey: 0E08C16E029D46527FA2FB4C72B3DBA98575B3F2
Public-key algo: RSA
Public-key size: 4096 bits
Creation time: 2009-07-12 19:49:01 UTC
Key flags: transport encryption, data-at-rest encryption
UserID: Chris Lamb <chris@chris-lamb.co.uk>
Certifications: 28, use --certifications to list
UserID: Chris Lamb <lamby@debian.org>
Certifications: 31, use --certifications to list
UserID: Chris Lamb <lamby@gnu.org>
Certifications: 29, use --certifications to list
Besides other information this shows the fingerprint of the key.
7. Examine the signing key
Next examine the tails signing key with respect to certifications, especially the one found in the debian keyring:
$ sq inspect --cert A490D0F4D311A4153E2BB7CADBB802B258ACD84F --certifications | grep C2FE4BD271C139B86C533E461E953E27D4311E58
WARNING: sq does not have a stable CLI interface. Use with caution in scripts.
Alleged certifier: C2FE4BD271C139B86C533E461E953E27D4311E58
Alleged certifier: C2FE4BD271C139B86C533E461E953E27D4311E58
The tails signing key was certified by a key contained in the debian keyring. This gives the trust path debian keyring
-> C2FE4BD271C139B86C533E461E953E27D4311E58
-> tails signing key
. For a one-time verification this might be sufficient - assuming that you want to rely on the debian keyring to contain valid and authenticated keys.
For future verifications the workflow described so far can be memorized, thus saving a few steps.
8. Export certificate and import it into cert store
Export Chris certificate from the debian keyring and import it into the cert store of sequioa-pgp. This step makes future dealing with the debian keyring superflous:
$ sq cert export --keyring /usr/share/keyrings/debian-keyring.gpg --no-cert-store --userid "Chris Lamb <chris@chris-lamb.co.uk>" | sq cert import
Imported C2FE4BD271C139B86C533E461E953E27D4311E58, Chris Lamb <chris@chris-lamb.co.uk> (UNAUTHENTICATED)
Imported 1 new certificates, updated 0 certificates, 0 certificates unchanged, 0 errors.
The key - or more precise: the certificate of the key - is now in the cert store. It's still unauthenticated, meaning that the bindings to User IDs, which are contained in the certificate, are still treated as unsubstantiated claims.
9. Assigning reliance on the validity of the key
Assuming that the bindings in the certificate are valid, adding a link
between the certificate's fingerprint and a User ID will store this assumption in the cert store.
It's possible to explicitly name the User ID that should be linked, or pass --all
to link all User IDs within the certificate in one step.
$ sq pki link add C2FE4BD271C139B86C533E461E953E27D4311E58 --all
Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb <chris@chris-
lamb.co.uk>".
Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb
<lamby@debian.org>".
Linking C2FE4BD271C139B86C533E461E953E27D4311E58 and "Chris Lamb
<lamby@gnu.org>".
The tails signing key contains a certification by Chris. What is still missing is the information that certifications made by Chris should be honoured. Without that, the certification has no special meaning and will be ignored.
10. Mark certificate as a trusted introducer
Marking a certificate as a trust introducer will make certifications created by the corresponding key effective. Certificates containing a certification by this key will be treated as authenticated.
The trust introducer acts as a certification authority (CA). Sequoia-PGP allows to restrict the range of domains for which the trust introducer will be regarded as authorative. Certifications made for certificates of domains that are not in this range will be ignored.
The range of domains is passed via --ca
when adding a link with sq pki link add
:
$ sq pki link authorize --domain boum.org --cert C2FE4BD271C139B86C533E461E953E27D4311E58 --all
11. Check the authentication
To check whether sequoia-pgp regards a binding as authenticated, you can use sq pki authenticate
:
$ sq pki authenticate A490D0F4D311A4153E2BB7CADBB802B258ACD84F --email tails@boum.org
A490D0F4D311A4153E2BB7CADBB802B258ACD84F will expire on 2025-01-25T09:24:54Z
[ ✓ ] Tails developers (offline long-term identity key) <tails@boum.org>
[ ✓ ] Tails developers <tails@boum.org>
To view why a user ID is considered valid, pass `--show-paths`
To see more details about a certificate, run:
$ sq inspect --cert FINGERPRINT
Adding --show-paths
will print out more information, especially the trust path which makes the certificate considered as authentic:
$ sq pki authenticate A490D0F4D311A4153E2BB7CADBB802B258ACD84F --email tails@boum.org --show-paths
[✓] A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers (offline long-term identity key)
<tails@boum.org>: fully authenticated (100%)
◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
│ certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
│ unconstrained)
├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
│ certified the following binding on 2020-03-19
└ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers (offline long-term identity key)
<tails@boum.org>"
[✓] A490D0F4D311A4153E2BB7CADBB802B258ACD84F Tails developers <tails@boum.org>: fully authenticated
(100%)
◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
│ certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
│ unconstrained)
├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
│ certified the following binding on 2020-03-19
└ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers <tails@boum.org>"
12. Verify the downloaded file (again)
With everything in place, verifying a file with a detached signature is simply:
$ sq verify --signature-file tails-amd64-6.2.img.sig tails-amd64-6.2.img
Authenticating A490D0F4D311A4153E2BB7CADBB802B258ACD84F ("Tails developers (offline long-term
identity key) <tails@boum.org>") using the web of trust:
Fully authenticated (120 of 120) A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers
(offline long-term identity key) <tails@boum.org>
◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
│ certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
│ unconstrained)
├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
│ certified the following binding on 2020-03-19
└ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers (offline long-term identity key)
<tails@boum.org>"
Fully authenticated (120 of 120) A490D0F4D311A4153E2BB7CADBB802B258ACD84F, Tails developers
<tails@boum.org>
◯ C746308CCC319B78998247210B986BAF950E297A ("Local Trust Root")
│ certified the following certificate on 2024-05-07 as a fully trusted meta-introducer (depth:
│ unconstrained)
├ C2FE4BD271C139B86C533E461E953E27D4311E58 ("Chris Lamb <chris@chris-lamb.co.uk>")
│ certified the following binding on 2020-03-19
└ A490D0F4D311A4153E2BB7CADBB802B258ACD84F "Tails developers <tails@boum.org>"
Good signature from D21DAD38AF281C0B ("Tails developers (offline long-term identity key)
<tails@boum.org>")
1 good signature.
Addition
Verify a signature that is not detached is very similar to the command described in paragraph 3. Instead of explicitly specifying the file name of the signature hash, only the file that was signed is specified.
$ sq verify signed_file.pgp
Note that technically it's also possible to skip the automatic check of authentication while verifying a file. This in done by specifying the signer certificate as a file instead of using an imported certificate. This method is only safe if you are sure the certificate in the file you are using is authentic.
$ sq verify --signer-file alice.cert file.txt
To verify a detached signature:
$ sq verify --signer-file alice.cert --signature-file file.sig file.txt