Commit 4c67d4fb authored by ale's avatar ale

stricter error detection on import; add more tests

Check that exactly one new public key has been imported.
parent 90ea5402
......@@ -93,12 +93,8 @@ default-key %s\n
# keyring. We would really like to call gpg with the
# --hidden-recipients-file option, to avoid importing the
# public key, but we can't do it with the gnupg module.
import_result = gpg.import_keys(public_key)
fp = [x['fingerprint'] for x in import_result.results]
if not fp:
raise Error('no valid keys found')
s = gpg.encrypt(msg_str, fp[0], passphrase=self.passphrase,
fp = _import_one_key(gpg, public_key)
s = gpg.encrypt(msg_str, fp, passphrase=self.passphrase,
throw_keyids=True, always_trust=True)
if not s:
raise Error('gpg --encrypt failed (no result)')
......@@ -236,12 +232,29 @@ def parse_public_key(public_key):
pass
gpg = gnupg.GPG(homedir=tmpdir)
gpg.encoding = 'utf-8'
import_result = gpg.import_keys(public_key)
if not import_result:
raise Error('Generic GPG import error')
fp = [x['fingerprint'] for x in import_result.results]
if not fp:
raise Error('No valid keys found in input')
if len(fp) > 1:
raise Error('More than one valid key found in input')
return fp[0]
return _import_one_key(gpg, public_key)
def _import_one_key(gpg, public_key):
"""Import a single PGP key and return its fingerprint."""
import_result = gpg.import_keys(public_key)
if not import_result:
raise Error('Generic GPG import error')
# Error handling is conservative: we are looking for exactly
# one new key. We also want to report meaningful error
# messages, so we are just going to bail out on the first bad
# status returned by gpg.
fp = None
for res in import_result.results:
if res['status'].strip() != 'Entirely new key':
raise Error('no valid keys found in input: %s' % res['status'])
if not res['fingerprint']:
continue
if fp:
raise Error('more than one public key found in input')
fp = res['fingerprint']
if not fp:
raise Error('no valid keys found in input')
return fp
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mI0EV7Cj/wEEAOcMywwAlYrx7u1/GEZ5whD+NXBzq9N8QnfAjDv+r1cwOUw9yqN3
FFOi4YbIZ3f3MGe+p4MJSDNFbl15sabTGFap88VoqjtRK2+3Uc9ZnQtL4+EhHmRE
KSPvCtj+t4Dk5I7C8CRslm8Lv7vIyf4gkLM6C0gcMAlQ8zBKWnNnu9vJABEBAAG0
InRlc3R1c2VyICh0ZXN0KSA8dGVzdEBleGFtcGxlLmNvbT6IuAQTAQIAIgUCV7Cj
/wIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQVqHjWZK8tc/3bgP/Qyks
zP0BDhGKG7yO24tqzn+MTUX+P00tOFGBqMcX1uDBf4LBlNdoc0k8vyuhiblm6xN4
nqRBJD+NNMJB0KdOgsPsqbjc2samRmmrL3SVlCWfUpgCfKFq98jDPWOX1szfqzJz
KcNpFmqNXkwF7tV+TzouC00pCatrelQIrA1v/3K4jQRXsKP/AQQA0gOF2S5aBsfI
/wJiTp7Jh+R5nAf8EAMQbPkprOuK9jWG+cb596CvWut5OUICkR2X2UYOVY8xbuyX
E6cK3AmDNoV40aiWLOC2OR9Jh2VvhqXOPg6sgc/0eu9AlsHk/18rgGjK01EtBMV1
8wqQxf+lLwNj5KYzzAUH3U5I9LSp+pUAEQEAAYifBBgBAgAJBQJXsKP/AhsMAAoJ
EFah41mSvLXPLywEAMzEFH21LoZJno0dOsDE/MFGe6BD8yWTmuPfO27vyD+41hMo
aWxgie+0CPnMrJg/yQWlYGZoSar+2qOKbootdxIyQ1IEpwDrl2oHJIX0fAs4XGv/
6Vy2RI4e6P2wQ1RIJ0yXDYU+FZCnyU64P0OM4Y1Y797aAtgjNrGXJdyuCvFJ
=SgBA
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
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
4mf0q4nXhDcYcMqLU5Vk
=1no7
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mQGiBESlkEERBACtZ1xzBOHuB/f8LysKYYIkTB0wQJN3qDYj8NO3lczM3Uy2cbCz
SJrXZjYcpCUgpNZ4mqAVYBkiKUfOXbXSlDogzNsi2A8k0aMVpkUDs6xj0/6hXZ6p
Z8HwsaermYZQe7C5HoJaZTPaZWyVFJm97lereyV/ePk4ccapJn85TkrAFwCglkZb
Zmhr76wSuiu6TK7a9TmetS8EAITEh+Yr4+rzu1myce3Fst+tC8VtRCN0qOMNd4Ho
/TVPSdnZ9NS/F48D7VKhinUw25PaAwjE2DnnOUBXeEN3IzQvK3M2A/pD7vBr/xlX
0NIhL7rjbW18Rs7q61tQKyAXUsKmMmU/hAEqq2ckodqsSamfnXe5UlUSmWq1iyUd
3GigBACOg+o7PsdSQNE+ZmNDdf6s1/8u6EdUGtjBUTIqGG3adEPB6JpYc+9GN66l
TU/shWI3Dwn8cD4xOaWsN9KSGQIorC5O8DcLI0AG/675rEHt0eNrj7zFsRJvaJ28
D7Obm0EW+SrhnVKedZ09ypPaMSTMc+Jiv2zoqrKmCbpAnLrRwIhfBCARAgAfBQJH
bPdFGB0BYSBuZXcga2V5IGlzIGF2YWlsYWJsZQAKCRAKhDbcrMsEgB7WAKCGMyAF
GOmnmZdwnY63TV7+oNc/lwCdEC0NaMgKaOp9R+/NIdjQoaqVZDy0WEF1dGlzdGlj
aSAvIEludmVudGF0aSBTdGFmZiAod3d3LmF1dGlzdGljaS5vcmcgLyB3d3cuaW52
ZW50YXRpLm9yZykgPGluZm9AYXV0aXN0aWNpLm9yZz6IZwQTEQIAJwUCRKWQQQIb
AwUJAeEzgAcLCQgHAwIBBBUCCAMEFgIDAQIeAQIXgAAKCRAKhDbcrMsEgJYPAJ9s
P+CPf6AWG46MXolbf6jQ7E06twCePo0omWm9itKrqvhTSv34oib0uD6IZgQTEQIA
JgIbAwUJAeEzgAIeAQIXgAUCRRDyMwYLCQgHAwIEFQIIAwQWAgMBAAoJEAqENtys
ywSACeoAniw6Yk7mpfezw2cJo5q65Lin0FzYAJ9DhPJq6HfcP7lCjKkqDmR5UnO4
q4hoBBMRAgAoAhsDAh4BAheABQkGIiGIBQJMBps5BgsJCAcDAgYVCAIJCgsEFgID
AQAKCRAKhDbcrMsEgEHBAJ4qBDwKd7gRGVcwpRj3pHNx9w03xgCaA1d/CE79bnmt
ukzoLJrba3gSD3+IZwQTEQIAJwIbAwcLCQgHAwIBBBUCCAMEFgIDAQIeAQIXgAUC
RwVK5QUJBiIhiAAKCRAKhDbcrMsEgBl4AJ9Hlj1mmtW9R2Tqr8NFHtgi4SW+6QCf
dB8gxeNHOic0q4f5OW3aR9eTzQi0WEF1dGlzdGljaSAvIEludmVudGF0aSBTdGFm
ZiAod3d3LmF1dGlzdGljaS5vcmcgLyB3d3cuaW52ZW50YXRpLm9yZykgPGluZm9A
aW52ZW50YXRpLm9yZz6IZwQTEQIAJwUCRKWRrgIbAwUJAeEzgAcLCQgHAwIBBBUC
CAMEFgIDAQIeAQIXgAAKCRAKhDbcrMsEgDfGAJ0emJssUmSjBI8xdmnC9LmM/ig7
ngCfZT5DpMZ2vvjN/pnjqs3BfwN3ePmIZgQTEQIAJgIbAwUJAeEzgAIeAQIXgAUC
RRDyLAYLCQgHAwIEFQIIAwQWAgMBAAoJEAqENtysywSA/nIAn2K/0P7ZAW5/Hmm8
hOMApT1jjV6fAJ0Y67yhwYgYKDQ4SuyJilXBrHmYKohoBBMRAgAoAhsDAh4BAheA
BQkGIiGIBQJMBps+BgsJCAcDAgYVCAIJCgsEFgIDAQAKCRAKhDbcrMsEgE3RAJ4u
GH41MiPkM89A4zBg/wWCv6RWhgCfWpKTsuZ9zP1x9f2X/96G24Ac8QOIZwQTEQIA
JwIbAwcLCQgHAwIBBBUCCAMEFgIDAQIeAQIXgAUCRwVK4AUJBiIhiAAKCRAKhDbc
rMsEgLhgAJ9X13rML9RsS4QbPivtBmoiu9sMmgCfSynKBq7oeGoQ2pLtPgYIXZ0V
bNe5BA0ERKWQ8xAQAO/umENMxIQ/aY/FUN5BtFo1SQGWHz+aRaWOSbVS5iBamDK/
szgegJLJ2m2NAf7cor8qVlRUy6y2nyeNsTOeRaUMHnYDQ8hF1jefDuLIiUFABHEJ
xNHCM7/5Yf0ClYAUBIFEqY3bBkgeSqGfPPcp6LlEXe4yWGLJcfSJgBWElc5m3QPI
EMU+uOIqKIVQaJSD7FFNliaKZwRTF9q28kNVh5By00DcQ1d9h9pMhQw/9VsFeYup
wmEwIfNihLd8QiFvhMKP14Hoktk4pTkV6RWt2qWTO3FKbqzE+xNYXijZiW57bQQr
pkKd/bo0tnvLWfGPaX9yfZbetT0/76f4WMlvwkqP4GAGDLpsqZWoeTO3aRFA2aKb
gXoebYZAT8hc889/iLSJyhyGFRSvtEpWJoIqEt+snuPbtrB9PUOIWYnFOfHTmT3E
SWfxHblbJ3/tzli1KIsBoee6+26/0GXYR7uyS36tLXRgEWU+uFDE7cqY6MctCqev
4THjkxRhfICgfZxkDMx9tSNKqqpmvufPBZHTyZcsCuI/6jyVKr2q31nCn4GfSFwu
nm8+EguiHzQkq9fGYnet2A16yLm2h1eMDKOf7tBIX00vpoRKrPfBv4DHa0Yg/1Qr
xFCbNTNpvBpS20jZu5OU5SlYwKAnl2c6QyBzDeVRSTC8G5c3jU8AYmnZZrGzAAMG
D/9IrBaFD3zGkuhjeus8nbt6BGT50iQWw5xsGV1e+IurcyoJJLoIXQwMojPxGDHs
VCmsF0THZ7RdTEV2QqQO39fFH0Bc9U7Cizl3WpU7rykslkdzjzOYjkXQ6GZyNcwB
KBwvPbZxH2BrYiuac1zLSAv3iedyPZBYrMTIDCK7vwbOG+ZAbgpiwLoWOA0mRa6V
F40OOVcbCB0tGQRtg+Uw7XB7pZquw/C68BaVuIvp1ulNLPtktR/qmqq1iAOR+LXi
2bcQsEcDkcFXKFc+S0GX5Svh+wvkGkbn5j+IxG8B0KqRlFM5bSovYZ2EsjVH2ijq
E93Roc22seY6TL6pxRUt+EKK0wJi+qKP+yeRympEg7c0SSlQKy5oKv8FWm8N3LHE
COBhN9x6rRq9p0TYW+ZSu05S3sXCThjBhS3NenGWROovFZpMy9jhLpzvIujiM+mW
zZEXUrDS4EOcRdbYoYxCSBzS8/l65u1y62L+Wc3a1rg/3mUiLsk1ZnRMUkJEkbRH
36lE0WU2hn3LiX8wkw2DQX1r37HXrf0Xx3ETfsdtRzb8E8xg3PyKBvAnWdZIjeoM
ieZ0DxM5gG32aDC17yq6opOlCZgKFenI2oSFX3vjmrzY8q0M0qAUi1JfjsDjNsN6
Pkcdm5g1S8SJjMFMiw/ibrrWK9bavfPEO2qVWvbO5GfbkIhOBBgRAgAPBQJEpZDz
AhsMBQkB4TOAAAoJEAqENtysywSA6wQAmJjFLB7mASFdbffl+/KOZEkt2EUAnirL
hzEfvC/SPUiOQ7YJeYmxPgqr
=Xjlr
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v2
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
=E3LA
-----END PGP PRIVATE KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
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
3WyyTG85He9G
=qT+Y
-----END PGP PUBLIC KEY BLOCK-----
......@@ -5,6 +5,8 @@ import unittest
import smtplib
import gnupg
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import pgp_mime_lib
......@@ -18,7 +20,7 @@ class TestBase(unittest.TestCase):
def setUp(self):
self.dir = tempfile.mkdtemp()
# Create a temporary secret key.
# Load our test secret key.
self.public_keyring = os.path.join(
fixtures_dir, 'secret/pubring.gpg')
self.secret_keyring = os.path.join(
......@@ -32,12 +34,15 @@ class TestBase(unittest.TestCase):
return pgp_mime_lib.GPG(self.secret_key, self.public_keyring, self.secret_keyring)
class TestGPG(TestBase):
class TestSign(TestBase):
def test_sign_ok(self):
result = self._gpg().sign_message(MIMEText('test message'))
self.assertTrue(result)
class TestEncrypt(TestBase):
def test_encrypt_and_sign_ok(self):
with open(os.path.join(fixtures_dir, 'pubkey1.asc')) as fd:
pubkey = fd.read()
......@@ -45,20 +50,50 @@ class TestGPG(TestBase):
result = self._gpg().sign_and_encrypt_message(msg, pubkey)
self.assertTrue(result)
def test_encrypt_fails_with_bad_public_key(self):
def test_encrypt_and_sign_ok_v2key(self):
with open(os.path.join(fixtures_dir, 'pubkey2.asc')) as fd:
pubkey = fd.read()
msg = MIMEText('test message')
result = self._gpg().sign_and_encrypt_message(msg, pubkey)
self.assertTrue(result)
def test_encrypt_fails_with_revoked_public_key(self):
with open(os.path.join(fixtures_dir, 'revoked.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error,
self._gpg().encrypt_message, MIMEText('test_message'), 'this is not a pgp key')
self._gpg().encrypt_message, MIMEText('test_message'), pubkey)
def test_parse_public_key_ok(self):
with open(os.path.join(fixtures_dir, 'pubkey1.asc')) as fd:
def test_encrypt_fails_with_more_than_one_public_key(self):
with open(os.path.join(fixtures_dir, 'twokeys.asc')) as fd:
pubkey = fd.read()
result = pgp_mime_lib.parse_public_key(pubkey)
self.assertTrue(result)
self.assertRaises(
pgp_mime_lib.Error,
self._gpg().encrypt_message, MIMEText('test_message'), pubkey)
def test_parse_public_key_fail(self):
def test_encrypt_fails_with_secret_key(self):
# People will do this!
with open(os.path.join(fixtures_dir, 'secretkey.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error,
self._gpg().encrypt_message, MIMEText('test_message'), pubkey)
def test_encrypt_fails_with_bad_public_key(self):
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key, 'this is not a pgp key')
pgp_mime_lib.Error,
self._gpg().encrypt_message, MIMEText('test_message'),
'this is not a pgp key')
def test_encrypt_fails_with_our_own_public_key(self):
# Being fed our own public key is pretty much the only way to
# get a 0 imported keys result from gpg.
with open(os.path.join(fixtures_dir, '92BCB5CF.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error,
self._gpg().encrypt_message, MIMEText('test_message'),
pubkey)
def test_encrypt_and_sign_send_via_smtp(self):
# Send an email to yourself if you want to manually check the
......@@ -83,3 +118,80 @@ class TestGPG(TestBase):
s.login(smtp_user, smtp_password)
s.sendmail(smtp_recip, [smtp_recip], result.as_string(unixfrom=False))
s.quit()
class TestParsePublicKey(TestBase):
def test_parse_public_key_ok(self):
with open(os.path.join(fixtures_dir, 'pubkey1.asc')) as fd:
pubkey = fd.read()
result = pgp_mime_lib.parse_public_key(pubkey)
self.assertTrue(result)
def test_parse_public_key_fails_with_bad_public_key(self):
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
'this is not a pgp key')
def test_parse_public_key_fails_with_empty_data(self):
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
'')
def test_parse_public_key_fails_with_empty_pgp_key_block(self):
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
'''
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
-----END PGP PUBLIC KEY BLOCK-----
''')
def test_parse_public_key_fails_with_revoked_public_key(self):
with open(os.path.join(fixtures_dir, 'revoked.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
pubkey)
def test_parse_public_key_fails_with_more_than_one_key(self):
with open(os.path.join(fixtures_dir, 'twokeys.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
pubkey)
def test_parse_public_key_fails_with_secret_key(self):
with open(os.path.join(fixtures_dir, 'secretkey.asc')) as fd:
pubkey = fd.read()
self.assertRaises(
pgp_mime_lib.Error, pgp_mime_lib.parse_public_key,
pubkey)
class TestMIME(TestBase):
def _encrypt(self, msg):
with open(os.path.join(fixtures_dir, 'pubkey1.asc')) as fd:
pubkey = fd.read()
result = self._gpg().sign_and_encrypt_message(msg, pubkey)
self.assertTrue(result)
def test_simple_text_message(self):
self._encrypt(MIMEText('test message'))
def test_utf8_text_message(self):
self._encrypt(MIMEText(u'test message', 'plain', 'utf-8'))
def test_multipart_message_with_image(self):
msg = MIMEMultipart()
msg.preamble = 'This is a message with an image attachment'
msg.attach(MIMEImage('GIF89ZZ', 'gif'))
self._encrypt(msg)
def test_multipart_alternative(self):
msg = MIMEMultipart('alternative')
msg.attach(MIMEText('text version', 'plain'))
msg.attach(MIMEText('html version', 'html'))
self._encrypt(msg)
......@@ -4,6 +4,7 @@ deps=
coverage
commands=
/usr/bin/env LANG=en_US.UTF-8 \
nosetests \
nosetests -v \
--with-coverage --cover-package=pgp_mime_lib \
--cover-erase --cover-html --cover-html-dir=htmlcov \
[]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment