Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions pretty_bad_protocol/_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,20 +792,30 @@ def _handle_io(self, args, file, result, passphrase=False, binary=False):
self._collect_output(p, result, writer, stdin)
return result

def _recv_keys(self, keyids, keyserver=None):
def _recv_keys(self, keyids, keyserver=None, keyserver_certs=None):
"""Import keys from a keyserver.

:param str keyids: A space-delimited string containing the keyids to
request.
:param str keyserver: The keyserver to request the ``keyids`` from;
defaults to `gnupg.GPG.keyserver`.
:param str keyserver_certs: A file passed as the CA cert file for the
keyserver.
"""
if not keyserver:
keyserver = self.keyserver

args = ['--keyserver {0}'.format(keyserver),
'--recv-keys {0}'.format(keyids)]
log.info('Requesting keys from %s: %s' % (keyserver, keyids))
if keyserver_certs:
args.insert(0, '--keyserver-options ca-cert-file={0}'.format(
keyserver_certs)
)
log.info('Requesting keys from %s (using CA file %s): %s' % (
keyserver,keyserver_certs, keyids)
)
print('%s args: %s' % (self.binary, ' '.join(args)))
print('make_args: %s' % (self._make_args(args, False)))

result = self._result_map['import'](self)
proc = self._open_subprocess(args)
Expand Down
78 changes: 78 additions & 0 deletions pretty_bad_protocol/_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
except ImportError:
from ordereddict import OrderedDict

try:
import urlparse
except ImportError:
from urllib import parse as urlparse

import os
import re

from . import _util
Expand Down Expand Up @@ -74,6 +80,67 @@ def _check_keyserver(location):
return keyserver
return None


def _check_keyserver_option(ks_option):
"""Check that the provided keyserver option is valid and safe.

:param str ks_option: A valid argument to --keyserver-option.
:rtype: :obj:`str` or :obj:`None`
:returns: A string of the keyserver option or None.
"""
def _is_valid_file(option_value):
"""Verify option value is a file."""
return _util._is_file(option_value)

def _is_valid_integer(option_value):
"""Verify option value is an integer."""
return str.isdigit(option_value)

def _is_valid_http_proxy(option_value):
"""Verify option value looks like a proxy URL."""
if not (option_value.startswith('http://') or
option_value.startswith('https://')):
proxy = 'http://{0}'.format(option_value)
else:
proxy = option_value
parsed_url = urlparse.urlparse(proxy)
if parsed_url.scheme and parsed_url.hostname:
return True
else:
return False

boolean_options = {
'auto-key-retrieve',
'check-cert',
'honor-keyserver-url',
'honor-pka-record',
'keep-temp-files',
'include-disabled',
'include-revoked',
'include-subkeys',
'use-temp-files',
}
no_prefixed_options = set(['no{}'.format(opt) for opt in boolean_options])
options_with_validators = {
'ca-cert-file': _is_valid_file,
'http-proxy': _is_valid_http_proxy,
'max-cert-size': _is_valid_integer,
'timeout': _is_valid_integer,
}
valid_simple_options = (set(['debug', 'verbose']) |
boolean_options |
no_prefixed_options)
if ks_option in valid_simple_options:
return ks_option
opt, opt_arg = ks_option.split('=', 1)
if opt in options_with_validators:
arg_ok = options_with_validators[opt](opt_arg)
if arg_ok:
return ks_option
log.debug('Dropping invalid keyserver option: {}'.format(ks_option))
return None


def _check_preferences(prefs, pref_type=None):
"""Check cipher, digest, and compression preference settings.

Expand Down Expand Up @@ -333,6 +400,16 @@ def _check_option(arg, value):
checked += (v + " ")
else: log.debug("Dropping keyserver: %s" % v)
continue
elif flag in ['--keyserver-options']:
print('found keyserver options: %s' % v)
keyserver_option = _check_keyserver_option(v)
if keyserver_option:
log.debug('Setting keyserver option: %s' %
keyserver_option)
checked += (keyserver_option + " ")
else:
log.debug('Dropping keyserver option: %s' % v)
continue

## the rest are strings, filenames, etc, and should be
## shell escaped:
Expand Down Expand Up @@ -514,6 +591,7 @@ def _get_options_group(group=None):
#: These have their own parsers and don't really fit into a group
other_options = frozenset(['--debug-level',
'--keyserver',
'--keyserver-options',

])
#: These should have a directory for an argument
Expand Down
8 changes: 8 additions & 0 deletions pretty_bad_protocol/gnupg.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,18 @@ def recv_keys(self, *keyids, **kwargs):
>>> key = gpg.recv_keys('3FF0DB166A7476EA', keyserver='hkp://pgp.mit.edu')
>>> assert key

>>> ssl_keyserver = 'hkps://hkps.pool.sks-keyservers.net'
>>> ca_cert = '/home/user/hkps.pool.sks-keyservers.netCA.pem'
>>> gpg.recv_keys('6F682D87',
>>> keyserver=ssl_keyserver,
>>> keyserver_certs=ca_cert)

:param str keyids: Each ``keyids`` argument should be a string
containing a keyid to request.
:param str keyserver: The keyserver to request the ``keyids`` from;
defaults to `gnupg.GPG.keyserver`.
:param str keyserver_certs: A file passed as the CA cert file for the
keyserver.
"""
if keyids:
keys = ' '.join([key for key in keyids])
Expand Down