Merge branch 'fix/5-genkeyinput-default-type' into develop

* FIXES issues #5 and #11
   https://github.com/isislovecruft/python-gnupg/issues/5
   https://github.com/isislovecruft/python-gnupg/issues/11
 * ADD checks for and attribute GPG.binary_version
 * CHANGE to generating RSA keys for GnuPG 1.x, and 'default' keys for GnuPG
   2.x, because GnuPG 1.x doesn't understand the 'Key-Type: default' batch
   file directive.
fix/24-enc-to-file
Isis Lovecruft 2013-07-29 19:01:04 +00:00
commit 8f01040fa1
No known key found for this signature in database
GPG Key ID: A3ADB67A2CDB8B35
3 changed files with 78 additions and 23 deletions

22
TODO
View File

@ -19,7 +19,15 @@ see :compatibility:gen__key_input:
* Compatibility between GnuPG versions :compatibility:
** TODO GnuPG>=2.1.0 won't allow key generation with preset passphrase
*** TODO in GPG.gen__key_input() :compatibility:gen_key_input:
*** DONE add version detection for GPG.gen_key_input() :compatibility:gen_key_input:
DONE: use gnupg._util._is_gpg2() and gnupg.util._is_gpg1() to check versions
If we add a GnuPG version detection feature (the version string is already
obtained in GPG.___init___() [[gnupg.py:407]]), then we can automatically chain
GPG.gen__key_input() to another new feature for '--edit-key'. This chaining
would likely need to happen here [[gnupg.py:1146]].
*** TODO passphase setting for GnuPGv2.x in GPG.gen__key_input() :compatibility:gen_key_input:
In the docstring of GPG.gen__key_input() [[gnupg.py:1068]], for the parameter
'passphrase', it is explained that:
@ -34,16 +42,16 @@ In the docstring of GPG.gen__key_input() [[gnupg.py:1068]], for the parameter
passwordless key to be created, which can then
have its passphrase set later with '--edit-key'.
If we add a GnuPG version detection feature (the version string is already
obtained in GPG.___init___() [[gnupg.py:407]]), then we can automatically chain
GPG.gen__key_input() to another new feature for '--edit-key'. This chaining
would likely need to happen here [[gnupg.py:1146]].
*** TODO add '--edit-key' feature :editkey:
This would be necessary for adding a passphrase to the key after passwordless
generation in GnuPG>=2.1.0.
** TODO GnuPG==1.4.12 doesn't process "Key-Type: default" in batch files
** DONE GnuPG==1.4.12 doesn't process "Key-Type: default" in batch files
DONE: GnuPG version detection in gen_key_input() was added in commits
6eccbe704841cca90573dc554019712528d927a0 and
1e867d6e117f603cd9f2238641a1fb9cb87d4b51
(python-gnupg)∃!isisⒶwintermute:~/code/riseup/python-gnupg ∴ ipython
WARNING: Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv.

View File

@ -33,6 +33,7 @@ import encodings
import os
import threading
import random
import re
import string
import sys
@ -295,6 +296,28 @@ def _is_list_or_tuple(instance):
"""
return isinstance(instance, (list, tuple,))
def _is_gpg1(version):
"""Returns True if using GnuPG version 1.x.
:param tuple version: A tuple of three integers indication major, minor,
and micro version numbers.
"""
(major, minor, micro) = _match_version_string(version)
if major == 1:
return True
return False
def _is_gpg2(version):
"""Returns True if using GnuPG version 2.x.
:param tuple version: A tuple of three integers indication major, minor,
and micro version numbers.
"""
(major, minor, micro) = _match_version_string(version)
if major == 2:
return True
return False
def _make_binary_stream(s, encoding):
"""
xxx fill me in
@ -356,6 +379,17 @@ def _make_random_string(length):
chars = string.ascii_lowercase + string.ascii_uppercase + string.digits
return ''.join(random.choice(chars) for x in range(length))
def _match_version_string(version):
"""Sort a binary version string into major, minor, and micro integers.
:param str version: A version string in the form x.x.x
"""
regex = re.compile('(\d)*(\.)*(\d)*(\.)*(\d)*')
matched = regex.match(version)
g = matched.groups()
major, minor, micro = int(g[0]), int(g[2]), int(g[4])
return (major, minor, micro)
def _next_year():
"""Get the date of today plus one year.

View File

@ -137,14 +137,20 @@ class GPG(GPGBase):
self.temp_keyring = None
#: The secring used in the most recently created batch file
self.temp_secring = None
#: The version string of our GnuPG binary
self.binary_version = str()
## check that everything runs alright:
## check that everything runs alright, and grab the gpg binary's
## version number while we're at it:
proc = self._open_subprocess(["--list-config", "--with-colons"])
result = self._result_map['list'](self)
self._collect_output(proc, result, stdin=proc.stdin)
if proc.returncode != 0:
raise RuntimeError("Error invoking gpg: %s: %s"
% (proc.returncode, result.stderr))
self._read_data(proc.stdout, result)
if proc.returncode:
raise RuntimeError("Error invoking gpg: %s" % result.data)
version_line = str(result.data).partition(':version:')[2]
self.binary_version = version_line.split('\n')[0]
log.debug("Using GnuPG version %s" % self.binary_version)
def sign(self, data, **kwargs):
"""Create a signature for a message string or file.
@ -603,13 +609,14 @@ class GPG(GPGBase):
user ID is created.
:param str key_type: One of 'RSA', 'DSA', 'ELG-E', or 'default'.
(default: 'default') Starts a new parameter block by giving the
type of the primary key. The algorithm must be capable of
signing. This is a required parameter. The algorithm may either be
an OpenPGP algorithm number or a string with the algorithm
name. The special value default may be used for algo to create
the default key type; in this case a ``key_usage`` should not be
given and 'default' must also be used for ``subkey_type``.
(default: 'RSA', if using GnuPG v1.x, otherwise 'default') Starts
a new parameter block by giving the type of the primary key. The
algorithm must be capable of signing. This is a required
parameter. The algorithm may either be an OpenPGP algorithm number
or a string with the algorithm name. The special value default
may be used for algo to create the default key type; in this case
a ``key_usage`` should not be given and 'default' must also be
used for ``subkey_type``.
:param int key_length: The requested length of the generated key in
bits. (Default: 4096)
@ -694,18 +701,24 @@ class GPG(GPGBase):
http://www.gnupg.org/documentation/manuals/gnupg-devel/Unattended-GPG-key-generation.html
for more details.
"""
parms = {}
#: A boolean for determining whether to set subkey_type to 'default'
default_type = False
name_email = kwargs.get('name_email')
uidemail = _util.create_uid_email(name_email)
parms = {}
## if using GnuPG version 1.x, then set the default 'Key-Type' to
## 'RSA' because it doesn't understand 'default'
parms.setdefault('Key-Type', 'default')
if _util._is_gpg1(self.binary_version):
parms.setdefault('Key-Type', 'RSA')
log.debug("GnuPG v%s detected: setting default key type to %s."
% (self.binary_version, parms['Key-Type']))
parms.setdefault('Key-Length', 4096)
parms.setdefault('Name-Real', "Autogenerated Key")
parms.setdefault('Expire-Date', _util._next_year())
name_email = kwargs.get('name_email')
uidemail = _util.create_uid_email(name_email)
parms.setdefault('Name-Email', uidemail)
if testing: