isislovecruft / python-gnupg

A modified version of python-gnupg, including security patches, extensive documentation, and extra features.
Other
424 stars 172 forks source link

Problem with importing secret keys #205

Open MarSoft opened 7 years ago

MarSoft commented 7 years ago

Steps to reproduce:

  1. Create empty directory for gpg home, say /tmp/gh
  2. gpg = gnupg.GPG(homedir='/tmp/gh')
  3. gpg.import_keys("""my secret key data""")

Expected result: key should be import Actual result: key is not imported. Debug logs:

...
DEBUG:gnupg:Wrote data type <type 'str'> to outstream.
DEBUG:gnupg:Closed outstream: 3643 bytes sent.
GNUPG:gnupg:KEY_CONSIDERED 21DB430AE124F662E5489109663A21FC89D2C195 0
GNUPG:gnupg:IMPORTED 663A21FC89D2C195 somebody@kasasa.local
GNUPG:gnupg:IMPORT_OK 1 21DB430AE124F662E5489109663A21FC89D2C195
GNUPG:gnupg:KEY_CONSIDERED 21DB430AE124F662E5489109663A21FC89D2C195 0
GNUPG:gnupg:PINENTRY_LAUNCHED 4090 gtk2:curses 1.0.0 ? ? ?
DEBUG:gnupg:Finishing reading from stream "<open file '<fdopen>', mode 'rb' at 0x7f9e71e379c0>"...
DEBUG:gnupg:Read    0 bytes total
Exception in thread Thread-3:
Traceback (most recent call last):
  File "/usr/lib64/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib64/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/tmp/tmp.fBlN57xSCj/lib/python2.7/site-packages/gnupg/_meta.py", line 650, in _read_response
    result._handle_status(keyword, value)
  File "/tmp/tmp.fBlN57xSCj/lib/python2.7/site-packages/gnupg/_parsers.py", line 1294, in _handle_status
    raise ValueError("Unknown status message: %r" % key)
ValueError: Unknown status message: u'PINENTRY_LAUNCHED'

The import_keys call itself returns a successful result with all zeroes, as if there was no key in the data block passed.

Background: According to this topic on gnupg site, since gpg 2.1 it requires the user to either provide passphrase when importing secret key or to use --batch mode. See the topic for details.

So there could be two possible fixes:

  1. Use --batch mode when importing, like it is seemingly done in python-gnupg package
  2. Allow the user to specify passphrase(s) when calling gpg.import_keys, with some way to specify which of the should belong to which key.
JAnderson1122 commented 6 years ago

Hi! Any further developments on this issue, or work-around or monkey patches figured out?

My app currently works on a server running gpg 2.0, but I am expecting the server to be upgraded any time now...

aepiccolo7 commented 5 years ago

There is already support for using passphrases for other io calls so a quick work-around is straightforward:

-   def import_keys(self, key_data):
+   def import_keys(self, key_data, passphrase=False):

        result = self._result_map['import'](self)
        log.info('Importing: %r', key_data[:256])
        data = _make_binary_stream(key_data, self._encoding)
-       self._handle_io(['--import'], data, result, binary=True)
+       self._handle_io(['--import'], data, result, passphrase=passphrase, binary=True)
        data.close()
        return result

This quickly solved my issue for importing secret keys with gpg >= 2.1. You can still omit the passphrase for public key importing.

Note that there may still be issues with other key functionality like delete_keys, though list_keys is fine. A similar fix should be applicable.