summaryrefslogtreecommitdiff
path: root/yarns/0060-encryption.yarn
blob: 6985f1ffa34ac12692da94583c355d66037aeafd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
Encrypted repositories
======================

Obnam repositories may be encrypted. The encryption is based on public
keys, using GnuPG specifically. Internally, symmetric encryption is
also used, but that is not visible, nor relevant, to the user. All
encryption requires some level of key management, so the encryption
plugin in Obnam provides a number of subcommands for that.

We need to test, at minimum, that key management works. Ideally, we'd
also test that encryption works, but that's trickier to achieve
without making assumptions about the repository format.

Test setup
----------

We need two PGP keys for these tests, and they need to be independent
of each other so that tests can meaningfully use the different keys to
pretend they're different users. We have, in the Obnam source tree,
two GnuPG keyrings (`test-data/keyring-1` and `test-data/keyring-2`),
which we use for this purpose. We use pre-generated keys instead of
generating new ones for each test run, since key generation is a
fairly heavy operation that easily depletes the host of entropy.

However, to avoid inadvertent changes to the keys, keyrings, random
data seeds, or other files, we make a copy of the data into `$DATADIR`
for the duration of the test.

The keys have usernames `Test Key One` and `Test Key Two` (no e-mail
addresses). They have no passphrase. Otherwise, they are generated
using GnuPG defaults (as of 1.4.12 in Debian wheezy).

Encrypted backup and restore
----------------------------

We'll make a simple backup and restore using encryption. If this
works, we can probably assume that any other normal repository
operations (those not part of encryption management) also work, given
that encryption is done at the I/O abstraction level.

    SCENARIO basic encrypted backup and restore
    GIVEN user U uses encryption key "Test Key One" from test-data/keyring-1
    AND 128kB of new data in directory L
    AND a manifest of L in M
    WHEN user U backs up directory L to repository R
    AND user U restores their latest generation in repository R into X
    THEN L, restored to X, matches manifest M

Keys provided by a custom directory
-----------------------------------

We'll make a simple backup and restore using encryption. If this
works, we can probably assume that any other normal repository
operations (those not part of encryption management) also work, given
that encryption is done at the I/O abstraction level.

    SCENARIO encrypted backup and restore with a separate keyring
    GIVEN user U separately uses encryption key "Test Key One" from test-data/keyring-1
    AND 128kB of new data in directory L
    AND a manifest of L in M
    WHEN user U backs up directory L to repository R
    AND user U restores their latest generation in repository R into X
    THEN L, restored to X, matches manifest M

Adding and removing keys to clients
-----------------------------------

Each client specifies the key they want to use with the
`--encrypt-with` setting. This is the primary key for the client. The
client may additionally use other keys to encrypt to: this allows, for
example, having a repository-wide encryption key that can run fsck or
forget.

We test these by having two keys: one for the primary one, and a
second one, and verifying that we can, or can't, access the backup
with the second key, depending on whether it has or hasn't been added
to the client.

First of all, we make a simple encrypted backup as the first client.

    SCENARIO adding and removing encryption keys to clients
    GIVEN user U1 uses encryption key "Test Key One" from test-data/keyring-1
    AND 16kB of new data in directory L1
    WHEN user U1 backs up directory L1 to repository R
    THEN user U1 uses key "Test Key One" in repository R 

Then we add the key of the second client to the repository. This is
necessary, because by now the client list is already encrypted using
only the first client's key, meaning the second client has no access
to the client list, and thus can't add itself.

    WHEN user U1 imports public key "Test Key Two" from test-data/keyring-2
    AND user U1 adds key "Test Key Two" to repository R only

Then we make a backup as the second client.

    GIVEN user U2 uses encryption key "Test Key Two" from test-data/keyring-2
    AND 32kB of new data in directory L2
    WHEN user U2 backs up directory L2 to repository R
    THEN user U2 uses key "Test Key Two" in repository R

Let's make sure both clients can still restore their own data.

    GIVEN a manifest of L1 in M1
    WHEN user U1 restores their latest generation in repository R into X1
    THEN L1, restored to X1, matches manifest M1

    GIVEN a manifest of L2 in M2
    WHEN user U2 restores their latest generation in repository R into X2
    THEN L2, restored to X2, matches manifest M2

An unrelated client, which happens to use the same name as the first
client, should not be able to access the data.

    GIVEN a user U3 calling themselves U1
    WHEN user U3 attempts to restore their latest generation in repository R into X3
    THEN the attempt failed with exit code 1
    AND the error message matches "R0C79EX: gpg failed"
    AND the error message matches "secret key not available\|No secret key"

(The error message above indicates that there's a bug in Obnam, which
is that the error message, when an encryption is not provided but the
repository uses encryption, is not very clear. This should be FIXME'd
some day.)

Likewise, even if a client has access to their own data, they should
not have access to another client's data.

    GIVEN a user U2 calling themselves U1
    WHEN user U2 attempts to restore their latest generation in repository R into X4
    THEN the attempt failed with exit code 1
    AND the error message matches "secret key not available\|No secret key"

Replace a key for a client
--------------------------

If we replace the key for a client in a repository, and then the
client gets rid of the old key, the new key should be able to restore
old backups.

First, backup using the old key.

    SCENARIO replace client key
    GIVEN user U uses encryption key "Test Key One" from test-data/keyring-1
    AND 1kB of new data in directory L
    AND a manifest of L in M
    WHEN user U backs up directory L to repository R

Then, replace the old key with the new one and get rid of the old key.

    GIVEN user U uses encryption key "Test Key Two" from test-data/keyring-2
    WHEN user U adds key "Test Key Two" to repository R and self
    AND user U removes key "Test Key One" from repository R
    WHEN user U no longer has key "Test Key One"

Finally, verify that restores still work with the new key.

    WHEN user U restores their latest generation in repository R into X
    THEN L, restored to X, matches manifest M

Key queries
-----------

Obnam has a couple of commands to list the keys in the repository and
what they have access to (`list-keys`, `list-toplevels`). These are
primarily useful for debugging, and not not worth writing tests for
(at least for now).

Removing a client
-----------------

Obnam has a `obnam remove-client` command which currently only works
when encryption is used. This is a wart, a bug, and a disgrace.
However, it will be fixed some day, and until then the command is
tested in this chapter.

First we make a backup as one client, then we add a second key to the
repository. Finally, we remove the client and verify no clients
remain.

    SCENARIO remove a client
    GIVEN user U1 uses encryption key "Test Key One" from test-data/keyring-1
    AND user U2 uses encryption key "Test Key Two" from test-data/keyring-2
    AND 48kB of new data in directory L
    WHEN user U1 backs up directory L to repository R
    THEN user U1 uses key "Test Key One" in repository R
    WHEN user U1 imports public key "Test Key Two" from test-data/keyring-2
    AND user U1 adds key "Test Key Two" to repository R only
    AND user U2 removes user U1 from repository R
    THEN user U2 can't see user U1 in repository R