def _importGPGKey(self, key_path): """Import the given secret GPG key to sign packages. Return the key ID import as '0xAABBCCDD' """ gpghandler = getUtility(IGPGHandler) if key_path is None: self.gpg_key_id = None return gpghandler.resetLocalState() import_secret_test_key(key_path) key = list(gpghandler.localKeys())[0] return '0x%s' % key.keyid
def test_signContent_uses_sha512_digests(self): secret_keys = [ ("*****@*****.**", ""), # 1024R ("*****@*****.**", ""), # 4096R ] for key_name, password in secret_keys: self.gpg_handler.resetLocalState() secret_key = import_secret_test_key(key_name) content = "abc\n" signed_content = self.gpg_handler.signContent( content, secret_key, password) signature = self.gpg_handler.getVerifiedSignature(signed_content) self.assertEqual(content, signature.plain_data) self.assertEqual(secret_key.fingerprint, signature.fingerprint) # pygpgme doesn't tell us the hash algorithm used for a verified # signature, so we have to do this by hand. Sending --status-fd # output to stdout is a bit dodgy, but at least with --quiet # it's OK for test purposes and it simplifies subprocess # plumbing. with open(os.devnull, "w") as devnull: gpg_proc = subprocess.Popen([ get_gpg_path(), "--quiet", "--status-fd", "1", "--verify" ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=devnull, universal_newlines=True) status = gpg_proc.communicate(signed_content)[0].splitlines() validsig_prefix = "[GNUPG:] VALIDSIG " [validsig_line ] = [line for line in status if line.startswith(validsig_prefix)] validsig_tokens = validsig_line[len(validsig_prefix):].split() self.assertEqual(gpgme.MD_SHA512, int(validsig_tokens[7]))
def _importGPGKey(self, key_path): """Import the given secret GPG key to sign packages. Return the fingerprint of the imported key, prefixed with '0x'. """ gpghandler = getUtility(IGPGHandler) if key_path is None: self.gpg_key_fingerprint = None return gpghandler.resetLocalState() import_secret_test_key(key_path) key = list(gpghandler.localKeys())[0] return '0x%s' % key.fingerprint
def _get_detached_message_for_person(self, sender): # Return a signed message that contains a detached signature. body = dedent("""\ This is a multi-line body. Sincerely, Your friendly tester.""") to = self.factory.getUniqueEmailAddress() msg = MIMEMultipart() msg['Message-Id'] = make_msgid('launchpad') msg['Date'] = formatdate() msg['To'] = to msg['From'] = sender.preferredemail.email msg['Subject'] = 'Sample' body_text = MIMEText(body) msg.attach(body_text) # A detached signature is calculated on the entire string content of # the body message part. key = import_secret_test_key() gpghandler = getUtility(IGPGHandler) signature = gpghandler.signContent( canonicalise_line_endings(body_text.as_string()), key.fingerprint, 'test', gpgme.SIG_MODE_DETACH) attachment = Message() attachment.set_payload(signature) attachment['Content-Type'] = 'application/pgp-signature' msg.attach(attachment) self.assertTrue(msg.is_multipart()) return signed_message_from_string(msg.as_string())
def testFilteredGetKeys(self): """Check the filtered key lookup mechanism. Test filtering by fingerprint, key ID, UID restricted to public or secret keyrings. """ self.populateKeyring() target_fpr = '340CA3BB270E2716C9EE0B768E7EB7086C64A8C5' # Finding a key by its fingerprint. filtered_keys = self.gpg_handler.localKeys(target_fpr) [key] = filtered_keys self.assertEqual(key.fingerprint, target_fpr) # Finding a key by its key ID. filtered_keys = self.gpg_handler.localKeys(target_fpr[-8:]) [key] = filtered_keys self.assertEqual(key.fingerprint, target_fpr) # Multiple results when filtering by email. filtered_keys = self.gpg_handler.localKeys('*****@*****.**') filtered_fingerprints = [key.fingerprint for key in filtered_keys] self.assertTrue(target_fpr in filtered_fingerprints) self.assertTrue( 'FD311613D941C6DE55737D310E3498675D147547' in filtered_fingerprints) # Secret keys only filter. self.assertEqual( list(self.gpg_handler.localKeys(secret=True)), []) # Import a secret key and look it up. import_secret_test_key() secret_target_fpr = 'A419AE861E88BC9E04B9C26FBA2B9389DFD20543' filtered_keys = self.gpg_handler.localKeys(secret=True) [key] = filtered_keys self.assertEqual(key.fingerprint, secret_target_fpr) # Combining 'filter' and 'secret'. filtered_keys = self.gpg_handler.localKeys( filter=secret_target_fpr[-8:], secret=True) [key] = filtered_keys self.assertEqual(key.fingerprint, secret_target_fpr)
def testFilteredGetKeys(self): """Check the filtered key lookup mechanism. Test filtering by fingerprint, key ID, UID restricted to public or secret keyrings. """ self.populateKeyring() target_fpr = '340CA3BB270E2716C9EE0B768E7EB7086C64A8C5' # Finding a key by its fingerprint. filtered_keys = self.gpg_handler.localKeys(target_fpr) [key] = filtered_keys self.assertEqual(key.fingerprint, target_fpr) # Finding a key by its key ID. filtered_keys = self.gpg_handler.localKeys(target_fpr[-8:]) [key] = filtered_keys self.assertEqual(key.fingerprint, target_fpr) # Multiple results when filtering by email. filtered_keys = self.gpg_handler.localKeys('*****@*****.**') filtered_fingerprints = [key.fingerprint for key in filtered_keys] self.assertTrue(target_fpr in filtered_fingerprints) self.assertTrue('FD311613D941C6DE55737D310E3498675D147547' in filtered_fingerprints) # Secret keys only filter. self.assertEqual(list(self.gpg_handler.localKeys(secret=True)), []) # Import a secret key and look it up. import_secret_test_key() secret_target_fpr = 'A419AE861E88BC9E04B9C26FBA2B9389DFD20543' filtered_keys = self.gpg_handler.localKeys(secret=True) [key] = filtered_keys self.assertEqual(key.fingerprint, secret_target_fpr) # Combining 'filter' and 'secret'. filtered_keys = self.gpg_handler.localKeys( filter=secret_target_fpr[-8:], secret=True) [key] = filtered_keys self.assertEqual(key.fingerprint, secret_target_fpr)
def test_good_signature_timestamp(self): # An email message's GPG signature's timestamp checked to be sure it # isn't too far in the future or past. This test shows that a # signature with a timestamp of appxoimately now will be accepted. signing_context = GPGSigningContext(import_secret_test_key(), password='******') msg = self.factory.makeSignedMessage(body=' security no', signing_context=signing_context) handler = MaloneHandler() with person_logged_in(self.factory.makePerson()): handler.process(msg, msg['To']) # Since there were no commands in the poorly-timestamped message, no # error emails were generated. self.assertEmailQueueLength(0)
def test_bad_signature_timestamp(self): """If the signature is nontrivial future-dated, it's not trusted.""" signing_context = GPGSigningContext(import_secret_test_key().fingerprint, password="******") msg = self.factory.makeSignedMessage(signing_context=signing_context) # It's not trivial to make a gpg signature with a bogus timestamp, so # let's just treat everything as invalid, and trust that the regular # implementation of extraction and checking of timestamps is correct, # or at least tested. def fail_all_timestamps(timestamp, context): raise helpers.IncomingEmailError("fail!") self.assertRaises(helpers.IncomingEmailError, authenticateEmail, msg, fail_all_timestamps)
def test_good_signature_timestamp(self): # An email message's GPG signature's timestamp checked to be sure it # isn't too far in the future or past. This test shows that a # signature with a timestamp of appxoimately now will be accepted. signing_context = GPGSigningContext( import_secret_test_key().fingerprint, password='******') msg = self.factory.makeSignedMessage( body=' security no', signing_context=signing_context) handler = MaloneHandler() with person_logged_in(self.factory.makePerson()): handler.process(msg, msg['To']) transaction.commit() # Since there were no commands in the poorly-timestamped message, no # error emails were generated. self.assertEqual(stub.test_emails, [])
def test_bad_signature_timestamp(self): """If the signature is nontrivial future-dated, it's not trusted.""" signing_context = GPGSigningContext( import_secret_test_key(), password='******') msg = self.factory.makeSignedMessage(signing_context=signing_context) # It's not trivial to make a gpg signature with a bogus timestamp, so # let's just treat everything as invalid, and trust that the regular # implementation of extraction and checking of timestamps is correct, # or at least tested. def fail_all_timestamps(timestamp, context): raise helpers.IncomingEmailError("fail!") self.assertRaises( helpers.IncomingEmailError, authenticateEmail, msg, fail_all_timestamps)
def _get_clearsigned_for_person(self, sender, body=None): # Create a signed message for the sender specified with the test # secret key. key = import_secret_test_key() signing_context = GPGSigningContext(key.fingerprint, password='******') if body is None: body = dedent("""\ This is a multi-line body. Sincerely, Your friendly tester. """) msg = self.factory.makeSignedMessage( email_address=sender.preferredemail.email, body=body, signing_context=signing_context) self.assertFalse(msg.is_multipart()) return signed_message_from_string(msg.as_string())