Merge branch 'fix/2131-unittests' into develop

testing/mmn/mktime_takes_localtime_not_gmtime
Isis Lovecruft 2013-04-17 00:37:39 +00:00
commit 4706932275
No known key found for this signature in database
GPG Key ID: A3ADB67A2CDB8B35
6 changed files with 366 additions and 203 deletions

View File

@ -11,7 +11,7 @@ cleantest: clean
rm gnupg/tests/*.log
test: cleantest
python gnupg/tests/test_gnupg.py basic genkey sign
python gnupg/tests/test_gnupg.py parsers basic genkey sign
install:
python setup.py install --record installed-files.txt

View File

@ -137,26 +137,25 @@ def _copy_data(instream, outstream):
if len(data) == 0:
break
sent += len(data)
logger.debug("sending chunk (%d): %r", sent, data[:256])
logger.debug("_copy_data(): sending chunk (%d):\n%s" % (sent, data[:256]))
try:
outstream.write(data)
except UnicodeError:
try:
outstream.write(data.encode(enc))
except IOError:
logger.exception('Error sending data: Broken pipe')
logger.exception('_copy_data(): Error sending data: Broken pipe')
break
except IOError:
# Can sometimes get 'broken pipe' errors even when the
# data has all been sent
logger.exception('Error sending data: Broken pipe')
# Can get 'broken pipe' errors even when all data was sent
logger.exception('_copy_data(): Error sending data: Broken pipe')
break
try:
outstream.close()
except IOError:
logger.exception('Got IOError while trying to close FD outstream')
logger.exception('_copy_data(): Got IOError while closing %s' % outstream)
else:
logger.debug("closed output, %d bytes sent", sent)
logger.debug("_copy_data(): Closed output, %d bytes sent." % sent)
def _threaded_copy_data(instream, outstream):
"""Copy data from one stream to another in a separate thread.
@ -413,10 +412,6 @@ class GPG(object):
if isinstance(message, file):
result = self._sign_file(message, **kwargs)
elif not util._is_stream(message):
if isinstance(message, str):
if not util._py3k:
message = unicode(message, self.encoding)
message = message.encode(self.encoding)
f = util._make_binary_stream(message, self.encoding)
result = self._sign_file(f, **kwargs)
f.close()
@ -429,7 +424,7 @@ class GPG(object):
def _sign_file(self, file, keyid=None, passphrase=None, clearsign=True,
detach=False, binary=False):
"""Create a signature for a file."""
logger.debug("GPG._sign_file(): %s", file)
logger.debug("_sign_file(): %s", file)
if binary:
args = ['--sign']
else:
@ -438,10 +433,8 @@ class GPG(object):
if clearsign:
args.append("--clearsign")
if detach:
logger.warn(
"Cannot use --clearsign and --detach-sign simultaneously.")
logger.warn(
"Using default GPG behaviour: --clearsign only.")
logger.warn("Cannot use both --clearsign and --detach-sign.")
logger.warn("Using default GPG behaviour: --clearsign only.")
elif detach and not clearsign:
args.append("--detach-sign")
@ -449,8 +442,8 @@ class GPG(object):
args.append(str("--default-key %s" % keyid))
result = self._result_map['sign'](self)
#We could use _handle_io here except for the fact that if the
#passphrase is bad, gpg bails and you can't write the message.
## We could use _handle_io here except for the fact that if the
## passphrase is bad, gpg bails and you can't write the message.
p = self._open_subprocess(args, passphrase is not None)
try:
stdin = p.stdin
@ -458,7 +451,7 @@ class GPG(object):
_write_passphrase(stdin, passphrase, self.encoding)
writer = _threaded_copy_data(file, stdin)
except IOError:
logging.exception("error writing message")
logger.exception("_sign_file(): Error writing message")
writer = None
self._collect_output(p, result, writer, stdin)
return result
@ -483,50 +476,43 @@ class GPG(object):
f.close()
return result
def verify_file(self, file, data_filename=None):
"""
Verify the signature on the contents of a file or file-like
def verify_file(self, file, sig_file=None):
"""Verify the signature on the contents of a file or file-like
object. Can handle embedded signatures as well as detached
signatures. If using detached signatures, the file containing the
detached signature should be specified as the :param:data_filename.
detached signature should be specified as the ``sig_file``.
:param file file: A file descriptor object. Its type will be checked
with :func:util._is_file.
:param file data_filename: A file containing the GPG signature data for
:param:file. If given, :param:file is
verified via this detached signature.
with :func:`util._is_file`.
:param str sig_file: A file containing the GPG signature data for
``file``. If given, ``file`` is verified via this
detached signature.
"""
## attempt to wrap any escape characters in quotes:
safe_file = _fix_unsafe(file)
## check that :param:file is actually a file:
util._is_file(safe_file)
logger.debug('verify_file: %r, %r', safe_file, data_filename)
fn = None
result = self._result_map['verify'](self)
args = ['--verify']
if data_filename is None:
self._handle_io(args, safe_file, result, binary=True)
if sig_file is None:
logger.debug("verify_file(): Handling embedded signature")
args = ["--verify"]
proc = self._open_subprocess(args)
writer = _threaded_copy_data(file, proc.stdin)
self._collect_output(proc, result, writer, stdin=proc.stdin)
else:
safe_data_filename = _fix_unsafe(data_filename)
logger.debug('Handling detached verification')
fd, fn = tempfile.mkstemp(prefix='pygpg')
with open(safe_file) as sf:
contents = sf.read()
os.write(fd, s)
os.close(fd)
logger.debug('Wrote to temp file: %r', contents)
args.append(fn)
args.append('"%s"' % safe_data_filename)
try:
p = self._open_subprocess(args)
self._collect_output(p, result, stdin=p.stdin)
finally:
os.unlink(fn)
if not util._is_file(sig_file):
logger.debug("verify_file(): '%r' is not a file" % sig_file)
return result
logger.debug('verify_file(): Handling detached verification')
sig_fh = None
try:
sig_fh = open(sig_file)
args = ["--verify %s - " % sig_fh.name]
proc = self._open_subprocess(args)
writer = _threaded_copy_data(file, proc.stdin)
self._collect_output(proc, result, stdin=proc.stdin)
finally:
if sig_fh and not sig_fh.closed:
sig_fh.close()
return result
#
@ -659,13 +645,12 @@ class GPG(object):
>>> pubkeys = gpg.list_keys()
>>> assert print1 in pubkeys.fingerprints
>>> assert print2 in pubkeys.fingerprints
"""
which='public-keys'
if secret:
which='secret-keys'
args = "--list-%s --fixed-list-mode --fingerprint --with-colons" % (which,)
args = "--list-%s --fixed-list-mode --fingerprint --with-colons --no-show-photos" % (which,)
args = [args]
p = self._open_subprocess(args)
@ -692,6 +677,17 @@ class GPG(object):
getattr(result, keyword)(L)
return result
def list_sigs(self, *keyids):
"""xxx implement me
The GnuPG option '--show-photos', according to the GnuPG manual, "does
not work with --with-colons", but since we can't rely on all versions
of GnuPG to explicitly handle this correctly, we should probably
include it in the args.
"""
## we will want to include "--no-show-photos" in the args
raise NotImplemented("Functionality for '--list-sigs' not implemented.")
def gen_key(self, input):
"""
Generate a key; you might use gen_key_input() to create the control
@ -871,8 +867,7 @@ class GPG(object):
return result
def decrypt(self, message, **kwargs):
"""
Decrypt the contents of a string or file-like object :param:message .
"""Decrypt the contents of a string or file-like object ``message``.
:param message: A string or file-like object to decrypt.
"""
@ -967,9 +962,7 @@ class GPGWrapper(GPG):
passphrase=passphrase)
def send_keys(self, keyserver, *keyids):
"""
Send keys to a keyserver
"""
"""Send keys to a keyserver."""
result = self._result_map['list'](self)
gnupg.logger.debug('send_keys: %r', keyids)
data = gnupg.util._make_binary_stream("", self.encoding)

View File

@ -34,6 +34,7 @@ import util
ESCAPE_PATTERN = re.compile(r'\\x([0-9a-f][0-9a-f])', re.I)
HEXIDECIMAL = re.compile('([0-9A-F]{2})+')
class ProtectedOption(Exception):
@ -268,16 +269,13 @@ def _is_allowed(input):
## assertion will check that GPG will recognise them
##
## xxx checkout the --store option for creating rfc1991 data packets
## xxx also --multifile use with verify encrypt & decrypt
## xxx key fetching/retrieving options: [fetch_keys, merge_only, recv_keys]
##
## xxx which ones do we want as defaults?
## eg, --no-show-photos would mitigate things like
## https://www-01.ibm.com/support/docview.wss?uid=swg21620982
_allowed = frozenset(
['--list-keys', '--list-key', '--fixed-list-mode',
'--list-secret-keys', '--list-public-keys',
'--list-packets', '--with-colons',
'--no-show-photos',
'--delete-keys', '--delete-secret-keys',
'--encrypt', '--encrypt-files',
'--decrypt', '--decrypt-files',
@ -327,6 +325,17 @@ def _is_allowed(input):
return input
return None
def _is_hex(string):
"""Check that a string is hexidecimal, with alphabetic characters
capitalized and without whitespace.
:param str string: The string to check.
"""
matched = HEXIDECIMAL.match(string)
if matched is not None and len(matched.group()) >= 2:
return True
return False
def _sanitise(*args):
"""Take an arg or the key portion of a kwarg and check that it is in the
set of allowed GPG options and flags, and that it has the correct
@ -388,65 +397,93 @@ def _sanitise(*args):
if flag in ['--encrypt', '--encrypt-files', '--decrypt',
'--decrypt-file', '--import', '--verify']:
## Place checks here:
if _is_file(val):
if util._is_file(val):
safe_option += (val + " ")
else:
logger.debug("_check_option(): %s not file: %s"
% (flag, val))
elif flag in ['--default-key']:
if _is_hex(val):
safe_option += (val + " ")
else:
logger.debug("_check_option(): '%s %s' not hex."
% (flag, val))
else:
safe_option += (val + " ")
logger.debug("_check_option(): No checks for %s"
% val)
return safe_option
is_flag = lambda x: x.startswith('-')
checked = []
is_flag = lambda x: x.startswith('--')
def _make_filo(args_string):
filo = arg.split(' ')
filo.reverse()
logger.debug("_make_filo(): Converted to reverse list: %s" % filo)
return filo
def _make_groups(filo):
groups = {}
while len(filo) >= 1:
last = filo.pop()
if is_flag(last):
logger.debug("_make_groups(): Got arg: %s" % last)
if last == '--verify':
groups[last] = str(filo.pop())
## accept the read-from-stdin arg:
if len(filo) >= 1 and filo[len(filo)-1] == '-':
groups[last] += str(' - \'\'') ## gross hack
else:
groups[last] = str()
while len(filo) > 1 and not is_flag(filo[len(filo)-1]):
logger.debug("_make_groups(): Got value: %s"
% filo[len(filo)-1])
groups[last] += (filo.pop() + " ")
else:
if len(filo) == 1 and not is_flag(filo[0]):
logger.debug("_make_groups(): Got value: %s" % filo[0])
groups[last] += filo.pop()
else:
logger.debug("_make_groups(): Got solitary value: %s" % last)
groups["xxx"] = last
return groups
def _check_groups(groups):
logger.debug("_check_groups(): Got groups: %s" % groups)
checked_groups = []
for a,v in groups.items():
v = None if len(v) == 0 else v
safe = _check_option(a, v)
if safe is not None and not safe.strip() == "":
logger.debug("_check_groups(): appending option: %s" % safe)
checked_groups.append(safe)
else:
logger.debug("_check_groups(): dropped option '%s %s'" % (a,v))
return checked_groups
if args is not None:
option_groups = {}
for arg in args:
## if we're given a string with a bunch of options in it split them
## up and deal with them separately
if isinstance(arg, str):
logger.debug("_sanitise(): Got arg string: %s" % arg)
## if we're given a string with a bunch of options in it split
## them up and deal with them separately
if arg.find(' ') > 0:
filo = arg.split()
filo.reverse()
new_arg, new_value = str(), str()
while len(filo) > 0:
if not is_flag(filo[0]):
logger.debug("_sanitise(): Got non-flag arg %s"
% filo[0])
new_value += (filo.pop() + " ")
else:
logger.debug("_sanitise(): Got arg: %s" % filo[0])
new_arg = filo.pop()
if len(filo) > 0:
while not is_flag(filo[0]):
logger.debug("_sanitise(): Got value: %s"
% filo[0])
new_value += (filo.pop() + " ")
safe = _check_option(new_arg, new_value)
if safe is not None and not safe.strip() == "":
logger.debug("_sanitise(): appending option: %s"
% safe)
checked.append(safe)
filo = _make_filo(arg)
option_groups.update(_make_groups(filo))
else:
safe = _check_option(arg, None)
if safe is not None:
logger.debug("_sanitise(): appending args: %s" % safe)
checked.append(safe)
else:
logger.debug("_sanitise(): got None for safe")
option_groups.update({ arg: "" })
elif isinstance(arg, list):
logger.debug("_sanitise(): Got arg list: %s" % arg)
allow = _one_flag(arg)
if allow is not None:
checked.append(allow)
arg.reverse()
option_groups.update(_make_groups(arg))
else:
logger.debug("_sanitise(): got non string or list arg: %s"
% arg)
sanitised = ' '.join(x for x in checked)
return sanitised
logger.debug("_sanitise(): Got non str or list arg: %s" % arg)
checked = _check_groups(option_groups)
sanitised = ' '.join(x for x in checked)
return sanitised
else:
logger.debug("_sanitise(): Got None for args")
def _sanitise_list(arg_list):
"""A generator for iterating through a list of gpg options and sanitising
@ -474,30 +511,48 @@ class Verify(object):
TRUST_FULLY = 3
TRUST_ULTIMATE = 4
TRUST_LEVELS = {
"TRUST_UNDEFINED" : TRUST_UNDEFINED,
"TRUST_NEVER" : TRUST_NEVER,
"TRUST_MARGINAL" : TRUST_MARGINAL,
"TRUST_FULLY" : TRUST_FULLY,
"TRUST_ULTIMATE" : TRUST_ULTIMATE,
}
TRUST_LEVELS = { "TRUST_UNDEFINED" : TRUST_UNDEFINED,
"TRUST_NEVER" : TRUST_NEVER,
"TRUST_MARGINAL" : TRUST_MARGINAL,
"TRUST_FULLY" : TRUST_FULLY,
"TRUST_ULTIMATE" : TRUST_ULTIMATE, }
#: True if the signature is valid, False otherwise.
valid = False
#: A string describing the status of the signature verification.
#: Can be one of ``'signature bad'``, ``'signature good'``,
#: ``'signature valid'``, ``'signature error'``, ``'decryption failed'``,
#: ``'no public key'``, ``'key exp'``, or ``'key rev'``.
status = None
#: The fingerprint of the signing keyid.
fingerprint = None
#: The fingerprint of the corresponding public key, which may be different
#: if the signature was created with a subkey.
pubkey_fingerprint = None
#: The keyid of the signing key.
key_id = None
#: xxx I'm not sure how this is different to key_id.
signature_id = None
#: The creation date of the signing key.
creation_date = None
#: The timestamp of the purported signature, if we are unable to parse it.
timestamp = None
#: The userid of the signing key which was used to create the signature.
username = None
#: When the signing key is due to expire.
expire_timestamp = None
#: The timestamp for when the signature was created.
sig_timestamp = None
#: A number 0-4 describing the trust level of the signature.
trust_level = None
#: The string corresponding to the ``trust_level`` number.
trust_text = None
def __init__(self, gpg):
self.gpg = gpg
self.valid = False
self.fingerprint = self.creation_date = self.timestamp = None
self.signature_id = self.key_id = None
self.username = None
self.status = None
self.pubkey_fingerprint = None
self.expire_timestamp = None
self.sig_timestamp = None
self.trust_text = None
self.trust_level = None
def __nonzero__(self):
return self.valid
__bool__ = __nonzero__
def handle_status(self, key, value):
@ -521,7 +576,6 @@ class Verify(object):
self.creation_date,
self.sig_timestamp,
self.expire_timestamp) = value.split()[:4]
# may be different if signature is made with a subkey
self.pubkey_fingerprint = value.split()[-1]
self.status = 'signature valid'
elif key == "SIG_ID":
@ -574,7 +628,7 @@ class Crypt(Verify):
__bool__ = __nonzero__
def __str__(self):
return self.data.decode(self.gpg.encoding, self.gpg.decode_errors)
return self.data.decode(self.gpg.encoding, self.gpg._decode_errors)
def handle_status(self, key, value):
"""Parse a status code from the attached GnuPG process.
@ -676,19 +730,14 @@ class Sign(object):
#: The type of signature created.
sig_type = None
#: The algorithm used to create the signature.
sig_algo = None
#: The hash algorithm used to create the signature.
sig_hash_also = None
#: The fingerprint of the signing keyid.
fingerprint = None
#: The timestamp on the signature.
timestamp = None
#: xxx fill me in
what = None
@ -705,7 +754,7 @@ class Sign(object):
__bool__ = __nonzero__
def __str__(self):
return self.data.decode(self.gpg.encoding, self.gpg.decode_errors)
return self.data.decode(self.gpg.encoding, self.gpg._decode_errors)
def handle_status(self, key, value):
"""Parse a status code from the attached GnuPG process.

View File

@ -0,0 +1,87 @@
Privacy is necessary for an open society in the electronic age. Privacy is not
secrecy. A private matter is something one doesn't want the whole world to
know, but a secret matter is something one doesn't want anybody to
know. Privacy is the power to selectively reveal oneself to the world.
If two parties have some sort of dealings, then each has a memory of their
interaction. Each party can speak about their own memory of this; how could
anyone prevent it? One could pass laws against it, but the freedom of speech,
even more than privacy, is fundamental to an open society; we seek not to
restrict any speech at all. If many parties speak together in the same forum,
each can speak to all the others and aggregate together knowledge about
individuals and other parties. The power of electronic communications has
enabled such group speech, and it will not go away merely because we might want
it to.
Since we desire privacy, we must ensure that each party to a transaction have
knowledge only of that which is directly necessary for that transaction. Since
any information can be spoken of, we must ensure that we reveal as little as
possible. In most cases personal identity is not salient. When I purchase a
magazine at a store and hand cash to the clerk, there is no need to know who I
am. When I ask my electronic mail provider to send and receive messages, my
provider need not know to whom I am speaking or what I am saying or what others
are saying to me; my provider only need know how to get the message there and
how much I owe them in fees. When my identity is revealed by the underlying
mechanism of the transaction, I have no privacy. I cannot here selectively
reveal myself; I must always reveal myself.
Therefore, privacy in an open society requires anonymous transaction
systems. Until now, cash has been the primary such system. An anonymous
transaction system is not a secret transaction system. An anonymous system
empowers individuals to reveal their identity when desired and only when
desired; this is the essence of privacy.
Privacy in an open society also requires cryptography. If I say something, I
want it heard only by those for whom I intend it. If the content of my speech
is available to the world, I have no privacy. To encrypt is to indicate the
desire for privacy, and to encrypt with weak cryptography is to indicate not
too much desire for privacy. Furthermore, to reveal one's identity with
assurance when the default is anonymity requires the cryptographic signature.
We cannot expect governments, corporations, or other large, faceless
organizations to grant us privacy out of their beneficence. It is to their
advantage to speak of us, and we should expect that they will speak. To try to
prevent their speech is to fight against the realities of
information. Information does not just want to be free, it longs to be
free. Information expands to fill the available storage space. Information is
Rumor's younger, stronger cousin; Information is fleeter of foot, has more
eyes, knows more, and understands less than Rumor.
We must defend our own privacy if we expect to have any. We must come together
and create systems which allow anonymous transactions to take place. People
have been defending their own privacy for centuries with whispers, darkness,
envelopes, closed doors, secret handshakes, and couriers. The technologies of
the past did not allow for strong privacy, but electronic technologies do.
We the Cypherpunks are dedicated to building anonymous systems. We are
defending our privacy with cryptography, with anonymous mail forwarding
systems, with digital signatures, and with electronic money.
Cypherpunks write code. We know that someone has to write software to defend
privacy, and since we can't get privacy unless we all do, we're going to write
it. We publish our code so that our fellow Cypherpunks may practice and play
with it. Our code is free for all to use, worldwide. We don't much care if you
don't approve of the software we write. We know that software can't be
destroyed and that a widely dispersed system can't be shut down.
Cypherpunks deplore regulations on cryptography, for encryption is
fundamentally a private act. The act of encryption, in fact, removes
information from the public realm. Even laws against cryptography reach only so
far as a nation's border and the arm of its violence. Cryptography will
ineluctably spread over the whole globe, and with it the anonymous transactions
systems that it makes possible.
For privacy to be widespread it must be part of a social contract. People must
come and together deploy these systems for the common good. Privacy only
extends so far as the cooperation of one's fellows in society. We the
Cypherpunks seek your questions and your concerns and hope we may engage you so
that we do not deceive ourselves. We will not, however, be moved out of our
course because some may disagree with our goals.
The Cypherpunks are actively engaged in making the networks safer for
privacy. Let us proceed together apace.
Onward.
Eric Hughes <hughes@soda.berkeley.edu>
9 March 1993

View File

@ -17,6 +17,7 @@ import os
import shutil
import sys
import tempfile
import time
## Use unittest2 if we're on Python2.6 or less:
if sys.version_info.major == 2 and sys.version_info.minor <= 6:
@ -45,6 +46,8 @@ def _make_tempfile(*args, **kwargs):
*args, **kwargs)
logger = logging.getLogger('gnupg')
_here = os.path.join(os.path.join(util._repo, 'gnupg'), 'tests')
_files = os.path.join(_here, 'files')
KEYS_TO_IMPORT = """-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (MingW32)
@ -146,6 +149,26 @@ class GPGTestCase(unittest.TestCase):
self.pubring = os.path.join(self.homedir, 'pubring.gpg')
self.secring = os.path.join(self.homedir, 'secring.gpg')
def test_parsers_fix_unsafe(self):
"""Test that unsafe inputs are quoted out and then ignored."""
shell_input = "\"&coproc /bin/sh\""
fixed = parsers._fix_unsafe(shell_input)
print fixed
test_file = os.path.join(_files, 'cypherpunk_manifesto')
self.assertTrue(os.path.isfile(test_file))
has_shell = self.gpg.verify_file(test_file, fixed)
self.assertFalse(has_shell.valid)
def test_parsers_is_hex_valid(self):
"""Test that valid hexidecimal passes the parsers._is_hex() check"""
valid_hex = '0A6A58A14B5946ABDE18E207A3ADB67A2CDB8B35'
self.assertTrue(parsers._is_hex(valid_hex))
def test_parsers_is_hex_invalid(self):
"""Test that invalid hexidecimal fails the parsers._is_hex() check"""
invalid_hex = 'cipherpunks write code'
self.assertFalse(parsers._is_hex(invalid_hex))
def test_gpghome_creation(self):
"""Test the environment by ensuring that setup worked."""
hd = self.homedir
@ -271,51 +294,39 @@ class GPGTestCase(unittest.TestCase):
self.assertGreater(key_input.find('Francisco Ferrer'), 0)
def test_rsa_key_generation(self):
"""
Test that RSA key generation succeeds.
"""
key = self.generate_key("Barbara Brown", "beta.com")
"""Test that RSA key generation succeeds."""
key = self.generate_key("Ralph Merkle", "xerox.com")
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
def test_rsa_key_generation_with_unicode(self):
"""
Test that RSA key generation succeeds with unicode characters.
"""
"""Test that RSA key generation succeeds with unicode characters."""
key = self.generate_key("Anaïs de Flavigny", "êtrerien.fr")
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
def test_rsa_key_generation_with_subkey(self):
"""
Test that RSA key generation succeeds with additional subkey.
"""
key = self.generate_key("Need Caffeine", "nowplea.se",
"""Test that RSA key generation succeeds with additional subkey."""
key = self.generate_key("John Gilmore", "isapu.nk",
subkey_type='RSA')
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
def test_dsa_key_generation(self):
"""
Test that DSA key generation succeeds.
"""
key = self.generate_key("DSA Signonly", "test.com")
"""Test that DSA key generation succeeds."""
key = self.generate_key("Ross Anderson", "bearli.on")
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
def test_dsa_key_generation_with_unicode(self):
"""
Test that DSA key generation succeeds with unicode characters.
"""
"""Test that DSA key generation succeeds with unicode characters."""
key = self.generate_key("破壊合計する", "破壊合計する.日本")
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
def test_dsa_key_generation_with_subkey(self):
"""
Test that RSA key generation succeeds with additional subkey.
"""
key = self.generate_key("OMG Moar Coffee", "giveitto.me",
"""Test that RSA key generation succeeds with additional subkey."""
key = self.generate_key("Eli Biham", "bearli.on",
subkey_type='ELG-E')
self.assertIsNotNone(key.type)
self.assertIsNotNone(key.fingerprint)
@ -505,49 +516,45 @@ class GPGTestCase(unittest.TestCase):
def test_signature_algorithm(self):
"""Test that determining the signing algorithm works."""
key = self.generate_key("Werner Koch", "gnupg.org")
message = "Damn, I really wish GnuPG had ECC support."
key = self.generate_key("Ron Rivest", "rsa.com")
message = "Someone should add GCM block cipher mode to PyCrypto."
sig = self.gpg.sign(message, keyid=key.fingerprint,
passphrase='wernerkoch')
passphrase='ronrivest')
print "ALGORITHM:\n", sig.sig_algo
self.assertIsNotNone(sig.sig_algo)
def test_signature_string_bad_passphrase(self):
"""Test that signing and verification works."""
key = self.generate_key("Ron Rivest", "rsa.com")
message = 'Hello, André!'
key = self.generate_key("Taher ElGamal", "cryto.me")
message = 'أصحاب المصالح لا يحبون الثوراتز'
sig = self.gpg.sign(message, keyid=key.fingerprint, passphrase='foo')
self.assertFalse(sig, "Bad passphrase should fail")
def test_signature_string_alternate_encoding(self):
key = self.generate_key("Adi Shamir", "rsa.com")
key = self.generate_key("Nos Oignons", "nos-oignons.net")
self.gpg.encoding = 'latin-1'
message = 'Hello, André!'
message = "Mêle-toi de tes oignons"
sig = self.gpg.sign(message, keyid=key.fingerprint,
passphrase='adishamir')
passphrase='nosoignons')
self.assertTrue(sig)
def test_signature_file(self):
"""Test that signing a message file works."""
key = self.generate_key("Leonard Adleman", "rsa.com")
message = "Someone should add GCM block cipher mode to PyCrypto."
message_fn = os.path.join(tempfile.gettempdir(), 'test_signature_file')
with open(message_fn, 'w+b') as msg:
msg.write(message)
message_file = buffer(open(message_fn, "rb").read())
mf = io.BytesIO(message_file)
sig = self.gpg.sign(mf, keyid=key.fingerprint,
passphrase='leonardadleman')
self.assertTrue(sig, "Good passphrase should succeed")
message_file = os.path.join(_files, 'cypherpunk_manifesto')
with open(message_file) as msg:
sig = self.gpg.sign(msg, keyid=key.fingerprint,
passphrase='leonardadleman')
self.assertTrue(sig, "I thought I typed my password correctly...")
def test_signature_string_verification(self):
"""Test verification of a signature from a message string."""
key = self.generate_key("Andrew Able", "alpha.com")
message = 'Hello, André!'
key = self.generate_key("Bruce Schneier", "schneier.com")
message = '...the government uses the general fear of '
message += '[hackers in popular culture] to push for more power'
sig = self.gpg.sign(message, keyid=key.fingerprint,
passphrase='andrewable')
passphrase='bruceschneier')
now = time.mktime(time.gmtime())
self.assertTrue(sig, "Good passphrase should succeed")
verified = self.gpg.verify(sig.data)
self.assertIsNotNone(verified.fingerprint)
@ -556,15 +563,18 @@ class GPGTestCase(unittest.TestCase):
logger.debug("ver: %r", verified.fingerprint)
self.assertEqual(key.fingerprint, verified.fingerprint,
"Fingerprints must match")
self.assertEqual(verified.trust_level, verified.TRUST_ULTIMATE)
self.assertEqual(verified.trust_text, 'TRUST_ULTIMATE')
self.assertEqual(verified.status, 'signature valid')
self.assertAlmostEqual(int(now), int(verified.timestamp), delta=1000)
self.assertEqual(
verified.username,
u'Bruce Schneier (python-gnupg tester) <bruceschneier@schneier.com>')
def test_signature_file_verification(self):
"""Test verfication of a signature on a message file."""
key = self.generate_key("Taher ElGamal", "cryto.me")
message = 'أصحاب المصالح لا يحبون الثوراتز'
def test_signature_verification_clearsign(self):
"""Test verfication of an embedded signature."""
key = self.generate_key("Johan Borst", "rijnda.el")
message = "You're *still* using AES? Really?"
sig = self.gpg.sign(message, keyid=key.fingerprint,
passphrase='taherelgamal')
passphrase='johanborst')
self.assertTrue(sig, "Good passphrase should succeed")
try:
file = util._make_binary_stream(sig.data, self.gpg.encoding)
@ -576,22 +586,41 @@ class GPGTestCase(unittest.TestCase):
logger.debug("ver: %r", verified.fingerprint)
self.assertEqual(key.fingerprint, verified.fingerprint,
"Fingerprints must match")
data_file = open('random_binary_data', 'rb')
sig = self.gpg._sign_file(data_file, keyid=key.fingerprint,
passphrase='andrewable', detach=True)
data_file.close()
self.assertTrue(sig, "File signing should succeed")
try:
file = gnupg._make_binary_stream(sig.data, self.gpg.encoding)
verified = self.gpg.verify_file(file, 'random_binary_data')
except UnicodeDecodeError: #happens in Python 2.6
verified = self.gpg.verify_file(io.BytesIO(sig.data))
if key.fingerprint != verified.fingerprint:
logger.debug("key: %r", key.fingerprint)
logger.debug("ver: %r", verified.fingerprint)
self.assertEqual(key.fingerprint, verified.fingerprint,
"Fingerprints must match")
logger.debug("test_signature_verification ends")
def test_signature_verification_detached(self):
"""Test that verification of a detached signature of a file works."""
key = self.generate_key("Paulo S.L.M. Barreto", "anub.is")
with open(os.path.join(_files, 'cypherpunk_manifesto'),
'rb') as manifesto:
sig = self.gpg.sign(manifesto, keyid=key.fingerprint,
passphrase='paulos.l.m.barreto',
detach=True, clearsign=False)
self.assertTrue(sig.data, "File signing should succeed")
sigfilename = os.path.join(_files, 'cypherpunk_manifesto.sig')
with open(sigfilename,'w') as sigfile:
sigfile.write(sig.data)
sigfile.seek(0)
verified = self.gpg.verify_file(manifesto, sigfilename)
if key.fingerprint != verified.fingerprint:
logger.debug("key: %r", key.fingerprint)
logger.debug("ver: %r", verified.fingerprint)
self.assertEqual(key.fingerprint, verified.fingerprint,
"Fingerprints must match")
def test_signature_verification_detached_binary(self):
"""Test that detached signature verification in binary mode fails."""
key = self.generate_key("Adi Shamir", "rsa.com")
with open(os.path.join(_files, 'cypherpunk_manifesto'),
'rb') as manifesto:
sig = self.gpg.sign(manifesto, keyid=key.fingerprint,
passphrase='adishamir',
detach=True, binary=True, clearsign=False)
self.assertTrue(sig.data, "File signing should succeed")
with self.assertRaises(UnicodeDecodeError):
print "SIG=", sig
def test_deletion(self):
"""Test that key deletion works."""
@ -639,7 +668,10 @@ class GPGTestCase(unittest.TestCase):
logger.debug("test_file_encryption_and_decryption ends")
suites = { 'basic': set(['test_gpghome_creation',
suites = { 'parsers': set(['test_parsers_fix_unsafe',
'test_parsers_is_hex_valid',
'test_parsers_is_hex_invalid',]),
'basic': set(['test_gpghome_creation',
'test_gpg_binary',
'test_gpg_binary_not_abs',
'test_gpg_binary_version_str',
@ -659,7 +691,9 @@ suites = { 'basic': set(['test_gpghome_creation',
'test_key_generation_with_empty_value',
'test_key_generation_override_default_value',
'test_key_generation_with_colons']),
'sign': set(['test_signature_file_verification',
'sign': set(['test_signature_verification_clearsign',
'test_signature_verification_detached',
'test_signature_verification_detached_binary',
'test_signature_file',
'test_signature_string_bad_passphrase',
'test_signature_string_alternate_encoding',

View File

@ -140,7 +140,7 @@ def _is_file(input):
"""
try:
assert os.lstat(input).st_size > 0, "not a file: %s" % input
except (AssertionError, TypeError) as error:
except (AssertionError, TypeError, IOError, OSError) as error:
logger.debug(error.message)
return False
else: