summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Górny <mgorny@gentoo.org>2018-01-16 13:18:53 +0100
committerMichał Górny <mgorny@gentoo.org>2018-01-16 13:18:53 +0100
commit3d282360742212fc3670003943a0e41788e7b795 (patch)
tree8ac068a132577b8a7be5f48a51326642740efa81
parent8e150e18bc0617102e53c353d5ee300afee5a704 (diff)
downloadgemato-3d282360742212fc3670003943a0e41788e7b795.tar.gz
openpgp: Refactor to use class for system environment as well
-rw-r--r--gemato/cli.py36
-rw-r--r--gemato/manifest.py16
-rw-r--r--gemato/openpgp.py141
-rw-r--r--gemato/recursiveloader.py4
4 files changed, 122 insertions, 75 deletions
diff --git a/gemato/cli.py b/gemato/cli.py
index 6b3ab9e..7459841 100644
--- a/gemato/cli.py
+++ b/gemato/cli.py
@@ -43,11 +43,19 @@ def do_verify(args, argp):
kwargs['fail_handler'] = verify_failure
if not args.openpgp_verify:
init_kwargs['verify_openpgp'] = False
- with gemato.openpgp.OpenPGPEnvironment() as env:
+
+ # use isolated environment if key is specified;
+ # system environment otherwise
+ if args.openpgp_key is not None:
+ env_class = gemato.openpgp.OpenPGPEnvironment
+ else:
+ env_class = gemato.openpgp.OpenPGPSystemEnvironment
+
+ with env_class() as env:
if args.openpgp_key is not None:
with io.open(args.openpgp_key, 'rb') as f:
env.import_key(f)
- init_kwargs['openpgp_env'] = env
+ init_kwargs['openpgp_env'] = env
start = timeit.default_timer()
try:
@@ -113,11 +121,19 @@ def do_update(args, argp):
args.profile)
if args.sign is not None:
init_kwargs['sign_openpgp'] = args.sign
- with gemato.openpgp.OpenPGPEnvironment() as env:
+
+ # use isolated environment if key is specified;
+ # system environment otherwise
+ if args.openpgp_key is not None:
+ env_class = gemato.openpgp.OpenPGPEnvironment
+ else:
+ env_class = gemato.openpgp.OpenPGPSystemEnvironment
+
+ with env_class() as env:
if args.openpgp_key is not None:
with io.open(args.openpgp_key, 'rb') as f:
env.import_key(f)
- init_kwargs['openpgp_env'] = env
+ init_kwargs['openpgp_env'] = env
start = timeit.default_timer()
try:
@@ -204,11 +220,19 @@ def do_create(args, argp):
args.profile)
if args.sign is not None:
init_kwargs['sign_openpgp'] = args.sign
- with gemato.openpgp.OpenPGPEnvironment() as env:
+
+ # use isolated environment if key is specified;
+ # system environment otherwise
+ if args.openpgp_key is not None:
+ env_class = gemato.openpgp.OpenPGPEnvironment
+ else:
+ env_class = gemato.openpgp.OpenPGPSystemEnvironment
+
+ with env_class() as env:
if args.openpgp_key is not None:
with io.open(args.openpgp_key, 'rb') as f:
env.import_key(f)
- init_kwargs['openpgp_env'] = env
+ init_kwargs['openpgp_env'] = env
start = timeit.default_timer()
try:
diff --git a/gemato/manifest.py b/gemato/manifest.py
index 37d5288..39a8655 100644
--- a/gemato/manifest.py
+++ b/gemato/manifest.py
@@ -356,8 +356,8 @@ class ManifestFile(object):
in text mode, and oriented at the beginning.
If @verify_openpgp is True and the Manifest contains an OpenPGP
- signature, the signature will be verified. Provide @openpgp_env
- to perform the verification in specific environment.
+ signature, the signature will be verified. In that case,
+ @openpgp_env needs to be provided.
If the verification succeeds, the openpgp_signed property will
be set to True. If it fails or OpenPGP is not available,
@@ -434,8 +434,9 @@ class ManifestFile(object):
"Manifest terminated early, inside signature")
if verify_openpgp and state == ManifestState.POST_SIGNED_DATA:
+ assert openpgp_env
with io.StringIO(openpgp_data) as f:
- gemato.openpgp.verify_file(f, env=openpgp_env)
+ openpgp_env.verify_file(f)
self.openpgp_signed = True
def dump(self, f, sign_openpgp=None, openpgp_keyid=None,
@@ -449,8 +450,9 @@ class ManifestFile(object):
If it is None (the default), the file will be signed if it
was originally signed with a valid signature.
- @openpgp_keyid and @openpgp_env specify the key
- and the environment to use for signing.
+ If @openpgp_keyid is not None, it specifies the key to use
+ for signing. If @sign_openpgp is not False, @openpgp_env must
+ provide an OpenPGP environment for signing.
If @sort is True, the entries are sorted prior to dumping.
"""
@@ -462,12 +464,12 @@ class ManifestFile(object):
self.entries = sorted(self.entries)
if sign_openpgp:
+ assert openpgp_env
with io.StringIO() as data:
# get the plain data into a stream
self.dump(data, sign_openpgp=False)
data.seek(0)
- gemato.openpgp.clear_sign_file(data, f,
- keyid=openpgp_keyid, env=openpgp_env)
+ openpgp_env.clear_sign_file(data, f, keyid=openpgp_keyid)
else:
for e in self.entries:
f.write(u' '.join(e.to_list()) + '\n')
diff --git a/gemato/openpgp.py b/gemato/openpgp.py
index aadc9e5..2d6dd84 100644
--- a/gemato/openpgp.py
+++ b/gemato/openpgp.py
@@ -42,7 +42,76 @@ def _spawn_gpg(options, env_instance, stdin):
return (p.wait(), out, err)
-class OpenPGPEnvironment(object):
+class OpenPGPEnvironmentBase(object):
+ """
+ Base class for OpenPGP environment.
+ """
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, exc_cb):
+ pass
+
+ def close(self):
+ pass
+
+ def import_key(self, keyfile):
+ """
+ Import a public key from open file @keyfile. The file should
+ be open for reading in binary mode, and oriented
+ at the beginning.
+ """
+
+ raise NotImplementedError('import_key() is not implemented by this OpenPGP provider')
+
+ def verify_file(self, f):
+ """
+ Perform an OpenPGP verification of Manifest data in open file @f.
+ The file should be open in text mode and set at the beginning
+ (or start of signed part). Raises an exception if the verification
+ fails.
+ """
+
+ raise NotImplementedError('verify_file() is not implemented by this OpenPGP provider')
+
+ def clear_sign_file(self, f, outf, keyid=None):
+ """
+ Create an OpenPGP cleartext signed message containing the data
+ from open file @f, and writing it into open file @outf.
+ Both files should be open in text mode and set at the appropriate
+ position. Raises an exception if signing fails.
+
+ Pass @keyid to specify the key to use. If not specified,
+ the implementation will use the default key.
+ """
+
+ raise NotImplementedError('clear_sign_file() is not implemented by this OpenPGP provider')
+
+
+class OpenPGPSystemEnvironment(OpenPGPEnvironmentBase):
+ """
+ The system environment for OpenPGP routines.
+ """
+
+ def verify_file(self, f):
+ exitst, out, err = _spawn_gpg(['--verify'], None, f.read().encode('utf8'))
+ if exitst != 0:
+ raise gemato.exceptions.OpenPGPVerificationFailure(err.decode('utf8'))
+
+ def clear_sign_file(self, f, outf, keyid=None):
+ args = []
+ if keyid is not None:
+ args += ['--local-user', keyid]
+ exitst, out, err = _spawn_gpg(['--clearsign'] + args, None,
+ f.read().encode('utf8'))
+ if exitst != 0:
+ raise gemato.exceptions.OpenPGPSigningFailure(err.decode('utf8'))
+
+ outf.write(out.decode('utf8'))
+
+
+class OpenPGPEnvironment(OpenPGPEnvironmentBase):
"""
An isolated environment for OpenPGP routines. Used to get reliable
verification results independently of user configuration.
@@ -64,9 +133,6 @@ class OpenPGPEnvironment(object):
disable-scdaemon
''')
- def __enter__(self):
- return self
-
def __exit__(self, exc_type, exc_value, exc_cb):
if self._home is not None:
self.close()
@@ -95,30 +161,25 @@ disable-scdaemon
self._home = None
def import_key(self, keyfile):
- """
- Import a public key from open file @keyfile. The file should
- be open for reading in binary mode, and oriented
- at the beginning.
- """
-
exitst, out, err = _spawn_gpg(['--import'], self, keyfile.read())
if exitst != 0:
raise RuntimeError('Unable to import key: {}'.format(err.decode('utf8')))
def verify_file(self, f):
- """
- A convenience wrapper for verify_file(), using this environment.
- """
-
- verify_file(f, env=self)
+ exitst, out, err = _spawn_gpg(['--verify'], self, f.read().encode('utf8'))
+ if exitst != 0:
+ raise gemato.exceptions.OpenPGPVerificationFailure(err.decode('utf8'))
def clear_sign_file(self, f, outf, keyid=None):
- """
- A convenience wrapper for clear_sign_file(), using this
- environment.
- """
+ args = []
+ if keyid is not None:
+ args += ['--local-user', keyid]
+ exitst, out, err = _spawn_gpg(['--clearsign'] + args, self,
+ f.read().encode('utf8'))
+ if exitst != 0:
+ raise gemato.exceptions.OpenPGPSigningFailure(err.decode('utf8'))
- clear_sign_file(f, outf, keyid=keyid, env=self)
+ outf.write(out.decode('utf8'))
@property
def home(self):
@@ -126,43 +187,3 @@ disable-scdaemon
raise RuntimeError(
'OpenPGPEnvironment has been closed')
return self._home
-
-
-def verify_file(f, env=None):
- """
- Perform an OpenPGP verification of Manifest data in open file @f.
- The file should be open in text mode and set at the beginning
- (or start of signed part). Raises an exception if the verification
- fails.
-
- Note that this function does not distinguish whether the key
- is trusted, and is subject to user configuration. To get reliable
- results, prepare a dedicated OpenPGPEnvironment and pass it as @env.
- """
-
- exitst, out, err = _spawn_gpg(['--verify'], env, f.read().encode('utf8'))
- if exitst != 0:
- raise gemato.exceptions.OpenPGPVerificationFailure(err.decode('utf8'))
-
-
-def clear_sign_file(f, outf, keyid=None, env=None):
- """
- Create an OpenPGP cleartext signed message containing the data
- from open file @f, and writing it into open file @outf.
- Both files should be open in text mode and set at the appropriate
- position. Raises an exception if signing fails.
-
- Pass @keyid to specify the key to use. If not specified,
- the implementation will use the default key. Pass @env to use
- a dedicated OpenPGPEnvironment.
- """
-
- args = []
- if keyid is not None:
- args += ['--local-user', keyid]
- exitst, out, err = _spawn_gpg(['--clearsign'] + args, env,
- f.read().encode('utf8'))
- if exitst != 0:
- raise gemato.exceptions.OpenPGPSigningFailure(err.decode('utf8'))
-
- outf.write(out.decode('utf8'))
diff --git a/gemato/recursiveloader.py b/gemato/recursiveloader.py
index befda32..35c304a 100644
--- a/gemato/recursiveloader.py
+++ b/gemato/recursiveloader.py
@@ -28,8 +28,8 @@ class ManifestLoader(object):
@root_directory specifies top directory of Manifest tree.
If @verify_openpgp is True and a Manifest contain an OpenPGP
- signature, the signature will be verified. Provide @openpgp_env
- to perform the verification in specific environment.
+ signature, the signature will be verified. @openpgp_env
+ is the OpenPGP environment to use.
"""
self.root_directory = root_directory
self.verify_openpgp = verify_openpgp