diff options
-rw-r--r-- | obnam.1.in | 5 | ||||
-rw-r--r-- | obnamlib/plugins/encryption_plugin.py | 27 | ||||
-rw-r--r-- | yarns/0060-encryption.yarn | 16 | ||||
-rw-r--r-- | yarns/9000-implements.yarn | 26 |
4 files changed, 68 insertions, 6 deletions
@@ -426,6 +426,11 @@ and then tell about it using the .B \-\-encrypt\-with option. +You may optionally use a separate home directory using the +.B \-\-gnupghome +option. By default, the default directory for +.BR gpg(1) +will be used. .SS "Configuration files" .B obnam will look for configuration files in a number of locations. diff --git a/obnamlib/plugins/encryption_plugin.py b/obnamlib/plugins/encryption_plugin.py index ec3bccab..8c8eecf3 100644 --- a/obnamlib/plugins/encryption_plugin.py +++ b/obnamlib/plugins/encryption_plugin.py @@ -49,6 +49,12 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): 'size of symmetric key, in bits', metavar='BITS', group=encryption_group) + self.app.settings.string( + ['gnupghome'], + 'home directory for GPG', + metavar='HOMEDIR', + group=encryption_group, + default=None) self.tag = "encrypt1" @@ -87,7 +93,8 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): @property def pubkey(self): if self._pubkey is None: - self._pubkey = obnamlib.get_public_key(self.keyid) + self._pubkey = obnamlib.get_public_key(self.keyid, + gpghome=self.gnupghome) return self._pubkey @property @@ -98,6 +105,10 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): return '/dev/random' @property + def gnupghome(self): + return self.app.settings['gnupghome'] + + @property def symmetric_key_bits(self): return int(self.app.settings['symmetric-key-bits'] or '256') @@ -127,19 +138,22 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): def filter_read(self, encrypted, repo, toplevel): symmetric_key = self.get_symmetric_key(repo, toplevel) - return obnamlib.decrypt_symmetric(encrypted, symmetric_key) + return obnamlib.decrypt_symmetric(encrypted, symmetric_key, + gpghome=self.gnupghome) def filter_write(self, cleartext, repo, toplevel): if not self.keyid: return cleartext symmetric_key = self.get_symmetric_key(repo, toplevel) - return obnamlib.encrypt_symmetric(cleartext, symmetric_key) + return obnamlib.encrypt_symmetric(cleartext, symmetric_key, + gpghome=self.gnupghome) def get_symmetric_key(self, repo, toplevel): key = self._symkeys.get(repo, toplevel) if key is None: encoded = repo.get_fs().cat(os.path.join(toplevel, 'key')) - key = obnamlib.decrypt_with_secret_keys(encoded) + key = obnamlib.decrypt_with_secret_keys(encoded, + gpghome=self.gnupghome) self._symkeys.put(repo, toplevel, key) return key @@ -222,7 +236,8 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): def _get_key_string(self, keyid): verbose = self.app.settings['key-details'] if verbose: - user_ids = obnamlib.get_public_key_user_ids(keyid) + user_ids = obnamlib.get_public_key_user_ids(keyid, + gpghome=self.gnupghome) if user_ids: return "%s (%s)" % (keyid, ", ".join(user_ids)) return str(keyid) @@ -260,7 +275,7 @@ class EncryptionPlugin(obnamlib.ObnamPlugin): self.app.settings.require('keyid') repo = self.app.get_repository_object() keyid = self.app.settings['keyid'] - key = obnamlib.get_public_key(keyid) + key = obnamlib.get_public_key(keyid, gpghome=self.gnupghome) clients = self._find_clientdirs(repo, args) for toplevel in repo.get_shared_directories() + clients: self.add_to_userkeys(repo, toplevel, key) diff --git a/yarns/0060-encryption.yarn b/yarns/0060-encryption.yarn index acbade88..6985f1ff 100644 --- a/yarns/0060-encryption.yarn +++ b/yarns/0060-encryption.yarn @@ -46,6 +46,22 @@ that encryption is done at the I/O abstraction level. 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 ----------------------------------- diff --git a/yarns/9000-implements.yarn b/yarns/9000-implements.yarn index 204611cf..4a03f3d8 100644 --- a/yarns/9000-implements.yarn +++ b/yarns/9000-implements.yarn @@ -231,6 +231,32 @@ use. We store that. add_to_config "$MATCH_1" encrypt-with "$MATCH_2" +Scenarios involving encryption may also use a private keyring directory. + + IMPLEMENTS GIVEN user (\S+) separately uses encryption key "(.*)" from (\S+) + if [ ! -e "$DATADIR/$MATCH_1.gnupg" ] + then + mkdir "$DATADIR/$MATCH_1.gnupg" + cp -a "$SRCDIR/$MATCH_3/." "$DATADIR/$MATCH_1.gnupg/." + add_to_config "$MATCH_1" gnupghome "$DATADIR/$MATCH_1.gnupg" + else + # Export public and secret keys from new keyring. + export GNUPGHOME="$SRCDIR/$MATCH_3" + gpg --export "$MATCH_2" > "$DATADIR/public.key" + gpg --export-secret-keys "$MATCH_2" > "$DATADIR/secret.key" + + # Import into the keyring uses for tests. + export GNUPGHOME="$DATADIR/$MATCH_1.gnupg" + gpg --import "$DATADIR/public.key" + gpg --import "$DATADIR/secret.key" + + # Use the configuration rather than the environment. + add_to_config "$MATCH_1" gnupghome "$GNUPGHOME" + unset GNUPGHOME + fi + + add_to_config "$MATCH_1" encrypt-with "$MATCH_2" + Encryption scenarions, at least, also need users that pretend to be someone else. |