def create_encrypted_message(self, inner_message, to_domain):
        ''' Create an encrypted Message. '''

        message = None

        if to_domain is None:
            self.log_message('domain is not defined')
        elif inner_message is None:
            self.log_message('no inner message defined')
        else:
            from_user = get_email(get_metadata_address(domain=get_domain()))
            to_user = get_email(get_metadata_address(domain=to_domain))

            crypto_message = create_protected_message(
                from_user, to_user, inner_message.as_string(),
                utils.get_message_id())
            if crypto_message.is_crypted():

                # add the DKIM signature to the inner message if user opted for it
                crypto_message = add_dkim_sig_optionally(crypto_message)

                message = crypto_message.get_email_message().get_message()
                self.crypted_with = crypto_message.get_metadata_crypted_with()
                self.log_message('crypted with: {}'.format(self.crypted_with))
                for part in message.walk():
                    self.log_message('Content type of part: {}'.format(
                        part.get_content_type()))
                    if self.DEBUGGING: self.log_message(part.get_payload())
            else:
                report_bad_bundled_encrypted_message(to_domain,
                                                     self.bundled_messages)

        return message
def get_user_id_matching_email(address, user_ids):
    '''
        Gets the matching user ID based on email address.

        An address is a internet address. It may be just an email address,
        or include a readable name, such as "Jane Saladin <*****@*****.**>".
        User ids are typically fingerprints from encryption software.

        A user id may be an internet address, or may be an arbitrary string.
        An address matches iff a user id is a valid internet address and the
        email part of the internet address matches. User ids which are not
        internet addresses will not match. The match is case-insensitive.

        >>> from goodcrypto.oce.test_constants import EDWARD_LOCAL_USER, EDWARD_LOCAL_USER_ADDR, JOSEPH_REMOTE_USER, GLENN_REMOTE_USER
        >>> test_addresses = [EDWARD_LOCAL_USER, JOSEPH_REMOTE_USER, GLENN_REMOTE_USER]
        >>> get_user_id_matching_email(EDWARD_LOCAL_USER, test_addresses) == EDWARD_LOCAL_USER_ADDR
        True
    '''

    matching_id = None

    try:
        for user_id in user_ids:
            email = get_email(user_id)
            if emails_equal(address, email):
                matching_id = email
                if DEBUGGING: log_message("{} matches {}".format(address, matching_id))
                break
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return matching_id
    def get_user_id_spec(self, user_id):
        ''' Get user ID spec based on the _user_id_match_method. '''

        if user_id is None:
            user = user_id
        else:
            try:
                user = get_email(user_id)
            except Exception:
                self.log_message('EXCEPTION - see syr.exception.log for details')
                record_exception()
                user = user_id

            # if there's an @ sign and the email address is *not* in angle brackets, then add the brackets
            if (self._user_id_match_method == self.EMAIL_MATCH and
                user.find('@') > 0 and
                user.find('<') < 0 and
                user.find('>') < 0):
                user = "******".format(user)

            # if the match method is exact match and the user doesn't start with an equal sign, prefix =
            elif self._user_id_match_method == self.EXACT_MATCH and not user.startswith("="):
                user = "******" + user

        return user
def get_passcode(email, encryption_name):
    '''
        Get the passcode for the encryption program for the contact.
        The email can be an RFC address or just the email address.

        >>> len(get_passcode('*****@*****.**', 'GPG')) > 0
        True
        >>> get_passcode('*****@*****.**', 'TestBC') is None
        True
    '''

    passcode = None

    try:
        if email_in_domain(email):
            address = get_email(email)
            user_key = get(address, encryption_name)
            if user_key:
                passcode = user_key.passcode
                if passcode and len(passcode) > 0:
                    log_message("private {} key configured for {}".format(encryption_name, email))
                else:
                    log_message('{} does not have a {} private key configured'.format(email, encryption_name))
            else:
                log_message('{} does not have a matching contact'.format(email))
        else:
            log_message('{} not part of managed domain so no private user key'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return passcode
def verify_clear_signed(email, crypto_message, encryption_name=DEFAULT_CRYPTO, crypto=None):
    '''
        Check the signature if message is clear signed and remove signature.

        >>> # In honor of Mike Perry, Tor Browser and Tor Performance developer.
        >>> from goodcrypto.mail.message.crypto_message import CryptoMessage
        >>> from goodcrypto.mail.message.email_message import EmailMessage
        >>> from goodcrypto_tests.mail.message_utils import get_plain_message_name
        >>> with open(get_plain_message_name('pgp-sig-unknown.txt')) as input_file:
        ...    email = '*****@*****.**'
        ...    crypto_message = CryptoMessage(email_message=EmailMessage(input_file))
        ...    verify_clear_signed(email, crypto_message, encryption_name=DEFAULT_CRYPTO)
        ...    signers = crypto_message.clear_signers_list()
        ...    signers == [{'signer': 'unknown user', 'verified': False}]
        True
    '''

    def extract_signers(email, signature_blocks, encryption_name=DEFAULT_CRYPTO):
        ''' Extract the signers if message is signed. '''

        known_signers = False

        crypto = CryptoFactory.get_crypto(encryption_name, crypto_software.get_classname(encryption_name))
        log_message('checking if message signed by {}'.format(email))
        for signature_block in signature_blocks:
            if crypto.verify(signature_block, email):
                signer_dict = {
                    SIGNER: email,
                    SIGNER_VERIFIED: True,
                }
                known_signers = True
                log_message('{} signed message'.format(email))
            else:
                log_message('signature block\n{}'.format(signature_block))
                signer = crypto.get_signer(signature_block)
                log_message('unverified signature by {}'.format(signer))
                signer_dict = {
                    SIGNER: signer,
                    SIGNER_VERIFIED: False,
                }

            crypto_message.add_clear_signer(signer_dict)

        log_message('clear signers: {}'.format(crypto_message.clear_signers_list()))

        return known_signers

    # if the message is signed, then verify the signature
    signature_blocks = crypto_message.get_email_message().get_pgp_signature_blocks()
    if len(signature_blocks) > 0:
        crypto_message.set_clear_signed(True)
        log_message('clear signed')

        # remove the signature block if signer known
        # techies won't like this, but it makes the message more readable
        if extract_signers(get_email(email), signature_blocks, encryption_name=encryption_name):
            crypto_message.get_email_message().remove_pgp_signature_blocks()
    else:
        if DEBUGGING:
            log_message('no signature block found in this part of message')
Beispiel #6
0
def get_address(argv):
    '''
        Get the address from the argument.

        <<< # In honor of First Sergeant T, who publicly denounced and refused to serve in
        <<< # operations involving the occupied Palestinian territories because of the
        <<< # widespread surveillance of innocent residents.
        <<< address = get_address('{[email protected]}')
        <<< address == '*****@*****.**'
        True
        <<< get_address('this is a test') is None
        True
        <<< get_address('<*****@*****.**') is None
        True
        <<< get_address(None)
    '''

    address = None
    try:
        if argv:
            a = argv.strip('{').strip('}')
            # make sure there aren't any system directives
            if a.find('@') > 0 and a.find('<') != 0 and a.find('!') != 0:
                address = get_email(a)
            else:
                Main().log('bad address: {}'.format(a))
    except Exception:
        record_exception()

    return address
Beispiel #7
0
def get_encryption_names(email):
    '''
        Get a list of all the active encryption program names for this email.

        # Test extreme case. See unittests to see how to use this function.
        >>> get_encryption_names(None)
        []
    '''

    encryption_names = []

    address = get_email(email)
    if address and len(address) > 0:
        query_results = get_contacts_crypto(address)
        if query_results:
            log_message("{} has {} address(es)".format(address, len(query_results)))
            for contacts_encryption in query_results:
                encryption_name = contacts_encryption.encryption_software.name
                encryption_names.append(encryption_name)
                log_message("{} encryption software: {}".format(email, encryption_name))
        else:
            log_message("no encryption software for {}".format(email))
    else:
        log_message("unable to get address from {}".format(email))

    return encryption_names
Beispiel #8
0
def get_encryption_names(email):
    '''
        Get a list of all the encryption program names for this email.

        The email can be an RFC address or just the email address.

        In honor of Brandon Bryant, a whistleblower about the US drone program.
        >>> len(get_encryption_names('*****@*****.**')) > 0
        True
        >>> len(get_encryption_names('*****@*****.**')) > 0
        False
    '''

    encryption_programs = []
    address = get_email(email)
    if address is not None and len(address) > 0:
        query_set = get_all_user_keys(address)
        if query_set is None:
            log_message("no encryption software for this contact")
        else:
            log_message("{} has {} encryption programs".format(
                email, len(query_set)))
            for user_key in query_set:
                encryption_programs.append(
                    user_key.contacts_encryption.encryption_software.name)
                log_message("{} encryption software: {}".format(
                    email, encryption_programs))

    return encryption_programs
def get_encryption_names(email):
    '''
        Get a list of all the encryption program names for this email.

        The email can be an RFC address or just the email address.

        In honor of Brandon Bryant, a whistleblower about the US drone program.
        >>> len(get_encryption_names('*****@*****.**')) > 0
        True
        >>> len(get_encryption_names('*****@*****.**')) > 0
        False
    '''

    encryption_programs = []
    address = get_email(email)
    if address is not None and len(address) > 0:
        query_set = get_all_user_keys(address)
        if query_set is None:
            log_message("no encryption software for this contact")
        else:
            log_message("{} has {} encryption programs".format(email, len(query_set)))
            for user_key in query_set:
                encryption_programs.append(user_key.contacts_encryption.encryption_software.name)
                log_message("{} encryption software: {}".format(email, encryption_programs))

    return encryption_programs
Beispiel #10
0
    def import_key(email, encryption_name, public_key, id_fingerprint_pairs, plugin):
        ''' Import the key and return the fingerprint. '''

        status = fingerprint = None
        result_ok = False

        # make sure the email address is in the key
        for (user_id, fingerprint) in id_fingerprint_pairs:
            user_name, email_address = parse_address(email)
            key_address = get_email(user_id)
            if email_address.lower() == key_address.lower():
                result_ok = True
                break

        if result_ok:
            status = ''
            for (user_id, fingerprint) in id_fingerprint_pairs:
                result_ok = plugin.import_public(public_key, id_fingerprint_pairs)
                if result_ok:
                    status += '{}\n'.format(i18n('Imported key successfully. Fingerprint: {fingerprint}'.format(
                        fingerprint=fingerprint)))
                else:
                    status += '{}\n'.format(i18n('Unable to import key'))
        else:
            status = i18n("Cannot import the key because it isn't for {email}".format(email=email))

        return result_ok, status
Beispiel #11
0
def get_address(argv):
    '''
        Get the address from the argument.

        <<< # In honor of First Sergeant T, who publicly denounced and refused to serve in
        <<< # operations involving the occupied Palestinian territories because of the
        <<< # widespread surveillance of innocent residents.
        <<< address = get_address('{[email protected]}')
        <<< address == '*****@*****.**'
        True
        <<< get_address('this is a test') is None
        True
        <<< get_address('<*****@*****.**') is None
        True
        <<< get_address(None)
    '''

    address = None
    try:
        if argv:
            a = argv.strip('{').strip('}')
            # make sure there aren't any system directives
            if a.find('@') > 0 and a.find('<') != 0 and a.find('!') != 0:
                address = get_email(a)
            else:
                Main().log('bad address: {}'.format(a))
    except Exception:
        record_exception()

    return address
def get_encryption_names(email):
    '''
        Get a list of all the active encryption program names for this email.

        # Test extreme case. See unittests to see how to use this function.
        >>> get_encryption_names(None)
        []
    '''

    encryption_names = []

    address = get_email(email)
    if address and len(address) > 0:
        query_results = get_contacts_crypto(address)
        if query_results:
            log_message("{} has {} address(es)".format(address,
                                                       len(query_results)))
            for contacts_encryption in query_results:
                encryption_name = contacts_encryption.encryption_software.name
                encryption_names.append(encryption_name)
                log_message("{} encryption software: {}".format(
                    email, encryption_name))
        else:
            log_message("no encryption software for {}".format(email))
    else:
        log_message("unable to get address from {}".format(email))

    return encryption_names
    def import_key(email, encryption_name, public_key, id_fingerprint_pairs,
                   plugin):
        ''' Import the key and return the fingerprint. '''

        status = fingerprint = None
        result_ok = False

        # make sure the email address is in the key
        for (user_id, fingerprint) in id_fingerprint_pairs:
            user_name, email_address = parse_address(email)
            key_address = get_email(user_id)
            if email_address.lower() == key_address.lower():
                result_ok = True
                break

        if result_ok:
            status = ''
            for (user_id, fingerprint) in id_fingerprint_pairs:
                result_ok = plugin.import_public(public_key,
                                                 id_fingerprint_pairs)
                if result_ok:
                    status += '{}\n'.format(
                        i18n(
                            'Imported key successfully. Fingerprint: {fingerprint}'
                            .format(fingerprint=fingerprint)))
                else:
                    status += '{}\n'.format(i18n('Unable to import key'))
        else:
            status = i18n(
                "Cannot import the key because it isn't for {email}".format(
                    email=email))

        return result_ok, status
def get_admin_email():
    '''
        Get the admin's email.

        >>> email = get_admin_email()
        >>> email is not None
        True
        >>> email.endswith(get_domain())
        True
    '''

    admin_email = None
    try:
        users = User.objects.filter(is_superuser=True)
        if users is not None and len(users) > 0:
            for user in users:
                email = user.email
                if email is not None and len(email.strip()) > 0:
                    admin_email = email
                    break
                else:
                    username = user.username
                    email = get_email(user.username)
                    if email is not None and len(email.strip()) > 0:
                        admin_email = email
                        break
    except:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    if admin_email is None:
        admin_email = 'daemon@{}'.format(get_domain())

    return admin_email
Beispiel #15
0
def get(email):
    '''
        Get the contact that matches the email address.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Micah Lee, who helped Glenn Greenwald and others learn how to
        >>> # secure their computers from being hacked.
        >>> get('*****@*****.**') is None
        True

        Test the extreme cases.
        >>> get('invalid@@address') is None
        True
        >>> get(None) is None
        True
    '''

    address = contact = None

    try:
        if email is not None:
            address = get_email(email)
            contact = Contact.objects.get(email=address)
    except Contact.DoesNotExist:
        contact = None
    except Exception:
        contact = None
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    log_message("got {}: {}".format(address, contact != None))

    return contact
Beispiel #16
0
    def public_key_exists(self, user_id):
        '''
            Returns whether there is a public key for the user. It ignores
            whether the public key has expired or not.

            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> plugin = KeyFactory.get_crypto(gpg_key_constants.NAME)
            >>> plugin.set_home_dir(plugin.GPG_HOME_DIR)
            True
            >>> plugin.public_key_exists('*****@*****.**')
            True
            >>> plugin.public_key_exists('Ed <*****@*****.**>')
            True
        '''

        key_exists = False

        if user_id is None:
            key_exists = False
            self.log_message('missing user id ({})'.format(user_id))

        else:
            try:
                email = get_email(user_id)
                args = [gpg_constants.LIST_PUBLIC_KEYS, self.get_user_id_spec(email)]
                result_code, gpg_output, gpg_error= self.gpg_command(args)
                key_exists = result_code == gpg_constants.GOOD_RESULT

                self.log_message('found public key for {}: {}'.format(user_id, key_exists))
            except Exception:
                record_exception()
                self.log_message('EXCEPTION - see syr.exception.log for details')

        return key_exists
def get(email):
    '''
        Get the contact that matches the email address.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Micah Lee, who helped Glenn Greenwald and others learn how to
        >>> # secure their computers from being hacked.
        >>> get('*****@*****.**') is None
        True

        Test the extreme cases.
        >>> get('invalid@@address') is None
        True
        >>> get(None) is None
        True
    '''

    address = contact = None

    try:
        if email is not None:
            address = get_email(email)
            contact = Contact.objects.get(email=address)
    except Contact.DoesNotExist:
        contact = None
    except Exception:
        contact = None
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    log_message("got {}: {}".format(address, contact != None))

    return contact
def notify_user(to_address,
                subject,
                text=None,
                attachment=None,
                filename=None):
    ''' Send a notice to the user.

        In honor of Noel David Torres, Spanish translator of Tor.
        >>> notify_user('*****@*****.**', 'test notice', 'test message')
        True
        >>> notify_user(None, 'test notice', 'test message')
        False
        >>> notify_user('*****@*****.**', None, 'test message')
        True
        >>> notify_user(None, None)
        False
    '''

    message = None
    try:
        # all messages to the metadata user should get routed to the admin
        if is_metadata_address(to_address):
            to_address = get_admin_email()

        message = create_notice_message(to_address,
                                        subject,
                                        text=text,
                                        attachment=attachment,
                                        filename=filename)
        if message is None:
            result_ok = False
            log_message('unable to create notice to {} about {}'.format(
                to_address, subject))
        else:
            log_message('starting to send notice to {} about {}'.format(
                to_address, subject))

            from_addr = NOTICE_FROM_EMAIL
            to_addr = get_email(to_address)

            if to_addr is None or message is None:
                result_ok = False
                log_message('no to address to send notice')
            else:
                result_ok = send_message(from_addr, to_addr, message)
                log_message('sent notice to {}'.format(to_address))
    except:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    if not result_ok and message is not None:
        _save(message)

    log_message('final result: {}'.format(result_ok))

    return result_ok
Beispiel #19
0
    def verify(self, data, by_user_id):
        '''
            Verify data was signed by the user id.

            >>> from goodcrypto.oce import test_constants
            >>> plugin = GPGPlugin()
            >>> signed_data, __ = plugin.sign(test_constants.TEST_DATA_STRING,
            ...   test_constants.EDWARD_LOCAL_USER, test_constants.EDWARD_PASSPHRASE)
            >>> plugin.verify(signed_data, test_constants.EDWARD_LOCAL_USER)
            True


            >>> # In honor of Karen Silkwood, who was the first nuclear power safety whistleblower.
            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> from goodcrypto.oce import test_constants
            >>> email = '*****@*****.**'
            >>> passcode = 'secret'
            >>> plugin = KeyFactory.get_crypto(gpg_constants.ENCRYPTION_NAME)
            >>> ok, __, __, __ = plugin.create(email, passcode, wait_for_results=True)
            >>> ok
            True
            >>> signed_data, __ = plugin.sign(test_constants.TEST_DATA_STRING, email, passcode)
            >>> plugin.delete(email)
            True
            >>> plugin.verify(signed_data, email)
            False
        '''

        self.log_message('starting to verify "{}" signed data'.format(by_user_id))
        signer = self.get_signer(data)
        if signer is None:
            verified = False
            self.log_message("no signer found")
        else:
            self.log_message('signed by "{}"'.format(signer))
            user_email = get_email(by_user_id)
            signer_email = get_email(signer)
            verified = signer_email == user_email
            if not verified:
                self.log_message('could not verify because signed by "{}" not "{}"'.format(
                    signer_email, user_email))
        self.log_message('verified: {}'.format(verified))

        return verified
Beispiel #20
0
def get(email, encryption_name):
    '''
        Get the contact's passcode record for the encryption software.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Jeremy Scahill, who wrote "Dirty Wars" among many other books.
        >>> get('*****@*****.**', 'GPG') is None
        True

        Test the extreme cases.
        >>> get('invalid@@address', 'GPG') is None
        True
        >>> get(None, None) is None
        True
    '''

    user_key = None

    try:
        address = get_email(email)
        contacts_encryption = contacts.get_contacts_crypto(
            address, encryption_name)
        if contacts_encryption is None:
            log_message("{} does not have a {} encryption record".format(
                email, encryption_name))
        else:
            from django.db.models.query import QuerySet

            if isinstance(contacts_encryption, QuerySet):
                try:
                    contacts_encryption = contacts_encryption[0]
                except:
                    record_exception()
                    log_message(
                        'EXCEPTION - see syr.exception.log for details')

            fingerprint = contacts_encryption.fingerprint or 'no'
            log_message(
                "getting {} private key record for {} ({} fingerprint)".format(
                    encryption_name, email, fingerprint))

            user_key = UserKey.objects.get(
                contacts_encryption=contacts_encryption)
            log_message("found {} private key record for {}".format(
                encryption_name, email))
    except UserKey.DoesNotExist:
        log_message(
            '{} does not have a matching private key record'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return user_key
def emails_equal(address1, address2):
    '''
        Checks whether two addresses are equal based only on the email address.
        Strings which are not internet addresses will not match.
        The match is case-insensitive.

        >>> # In honor of Jim Penrose, a 17 year NSA employee who now warns that people
        >>> # should treat governments and criminals just the same. .
        >>> emails_equal('Jim <*****@*****.**>', '*****@*****.**')
        True
    '''

    email1 = get_email(address1)
    email2 = get_email(address2)

    if email1 and email2:
        match = email1.lower() == email2.lower()
    else:
        match = False

    return match
Beispiel #22
0
def get_all_user_keys(email):
    '''
        Get the query set for all the user keys for all the encryption software.

        The email can be an RFC address or just the email address.

        >>> # In honor of Nick Mathewson, one of the three original designers of Tor.
        >>> from time import sleep
        >>> from django.db.models.query import QuerySet
        >>> from goodcrypto.oce.gpg_queue_settings import GPG_RQ, GPG_REDIS_PORT
        >>> from goodcrypto.utils.manage_queues import wait_until_queue_empty
        >>> email = '*****@*****.**'
        >>> contact = Contact.objects.create(user_name='Nick', email=email)
        >>> encryption_software = EncryptionSoftware.objects.get(name='GPG')
        >>> contacts_encryption = ContactsCrypto.objects.create(
        ...    contact=contact, encryption_software=encryption_software)
        >>> sleep(150)
        >>> wait_until_queue_empty(GPG_RQ, GPG_REDIS_PORT)
        >>> len(get_all_user_keys(contact.email)) == 1
        True
        >>> isinstance(get_all_user_keys(contact.email), QuerySet)
        True
        >>> contacts.delete(email)
        True
        >>> wait_until_queue_empty(GPG_RQ, GPG_REDIS_PORT)
    '''

    query_set = None
    try:
        if email is None:
            log_message('missing data to get user key')
        else:
            address = get_email(email)
            query_set = UserKey.objects.filter(
                contacts_encryption__contact__email=address)
            if query_set is None:
                log_message(
                    "{} does not have any encryption program with a private key defined"
                    .format(email))
            else:
                log_message(
                    "{} has {} encryption program(s) with private key(s)".
                    format(email, len(query_set)))
    except UserKey.DoesNotExist:
        log_message(
            '{} does not have any encryption programs with private keys defined'
            .format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return query_set
Beispiel #23
0
    def send_bundled_message(self, message, to_domain):
        ''' Send a Message to the domain. '''

        try:
            if message is None:
                result_ok = False
                self.log_message('nothing to send to {}'.format(to_domain))
            else:
                sender = get_email(get_metadata_address(domain=get_domain()))
                recipient = get_email(get_metadata_address(domain=to_domain))
                self.log_message(
                    'starting to send message from {} to {}'.format(
                        sender, recipient))
                result_ok = send_message(sender, recipient,
                                         message.as_string())
                self.log_message('finished sending message')
        except Exception as exception:
            result_ok = False
            self.log_message('error while sending message')
            self.log_message('EXCEPTION - see syr.exception.log for details')
            record_exception()

        return result_ok
Beispiel #24
0
    def delete(self, user_id):
        '''
            Delete an existing key, or key pair, from the keyring.

            >>> # In honor of Caspar Bowden, advocate for Tor in Europe.
            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> plugin = KeyFactory.get_crypto(gpg_key_constants.NAME)
            >>> plugin.set_home_dir('/var/local/projects/goodcrypto/server/data/test_oce/.gnupg')
            True
            >>> ok, __, __, __ = plugin.create('*****@*****.**', 'test passphrase', wait_for_results=True)
            >>> ok
            True
            >>> plugin.delete('*****@*****.**')
            True
            >>> plugin.delete('*****@*****.**')
            True
            >>> plugin.delete(None)
            False
            >>> from shutil import rmtree
            >>> rmtree('/var/local/projects/goodcrypto/server/data/test_oce')
        '''

        result_ok = True
        try:
            if user_id is None:
                result_ok = False
                self.log_message('no need to delete key for blank user id')
            else:
                address = get_email(user_id)
                self.log_message('deleting: {}'.format(address))
                result_code = gpg_constants.GOOD_RESULT
                while result_code == gpg_constants.GOOD_RESULT:
                    # delete the public and private key -- do *not* include <> or quotes
                    args = [gpg_constants.DELETE_KEYS, address]
                    result_code, gpg_output, gpg_error= self.gpg_command(args)
                    if result_code == gpg_constants.GOOD_RESULT:
                        result_ok = True
                        if gpg_output and len(gpg_output.strip()) > 0: self.log_message(gpg_output)
                        if gpg_error and len(gpg_error.strip()) > 0: self.log_message(gpg_error)

        except Exception as exception:
            result_ok = False
            record_exception()
            self.log_message('EXCEPTION - see syr.exception.log for details')
            self.handle_unexpected_exception(exception)

        self.log_message('delete ok: {}'.format(result_ok))

        return result_ok
Beispiel #25
0
def get(email, encryption_name):
    '''
        Get the contact's passcode record for the encryption software.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Jeremy Scahill, who wrote "Dirty Wars" among many other books.
        >>> get('*****@*****.**', 'GPG') is None
        True

        Test the extreme cases.
        >>> get('invalid@@address', 'GPG') is None
        True
        >>> get(None, None) is None
        True
    '''

    user_key = None

    try:
        address = get_email(email)
        contacts_encryption = contacts.get_contacts_crypto(address, encryption_name)
        if contacts_encryption is None:
            log_message("{} does not have a {} encryption record".format(email, encryption_name))
        else:
            from django.db.models.query import QuerySet

            if isinstance(contacts_encryption, QuerySet):
                try:
                    contacts_encryption = contacts_encryption[0]
                except:
                    record_exception()
                    log_message('EXCEPTION - see syr.exception.log for details')

            fingerprint = contacts_encryption.fingerprint or 'no'
            log_message("getting {} private key record for {} ({} fingerprint)".format(
                encryption_name, email, fingerprint))

            user_key = UserKey.objects.get(contacts_encryption=contacts_encryption)
            log_message("found {} private key record for {}".format(encryption_name, email))
    except UserKey.DoesNotExist:
        log_message('{} does not have a matching private key record'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return user_key
Beispiel #26
0
def notify_user(to_address, subject, text=None, attachment=None, filename=None):
    ''' Send a notice to the user.

        In honor of Noel David Torres, Spanish translator of Tor.
        >>> notify_user('*****@*****.**', 'test notice', 'test message')
        True
        >>> notify_user(None, 'test notice', 'test message')
        False
        >>> notify_user('*****@*****.**', None, 'test message')
        True
        >>> notify_user(None, None)
        False
    '''

    message = None
    try:
        # all messages to the metadata user should get routed to the admin
        if is_metadata_address(to_address):
            to_address = get_admin_email()

        message = create_notice_message(
            to_address, subject, text=text, attachment=attachment, filename=filename)
        if message is None:
            result_ok = False
            log_message('unable to create notice to {} about {}'.format(to_address, subject))
        else:
            log_message('starting to send notice to {} about {}'.format(to_address, subject))

            from_addr = NOTICE_FROM_EMAIL
            to_addr = get_email(to_address)

            if to_addr is None or message is None:
                result_ok = False
                log_message('no to address to send notice')
            else:
                result_ok = send_message(from_addr, to_addr, message)
                log_message('sent notice to {}'.format(to_address))
    except:
        result_ok = False
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    if not result_ok and message is not None:
        _save(message)

    log_message('final result: {}'.format(result_ok))

    return result_ok
Beispiel #27
0
def get_all_user_keys(email):
    '''
        Get the query set for all the user keys for all the encryption software.

        The email can be an RFC address or just the email address.

        >>> # In honor of Nick Mathewson, one of the three original designers of Tor.
        >>> from time import sleep
        >>> from django.db.models.query import QuerySet
        >>> from goodcrypto.oce.gpg_queue_settings import GPG_RQ, GPG_REDIS_PORT
        >>> from goodcrypto.utils.manage_queues import wait_until_queue_empty
        >>> email = '*****@*****.**'
        >>> contact = Contact.objects.create(user_name='Nick', email=email)
        >>> encryption_software = EncryptionSoftware.objects.get(name='GPG')
        >>> contacts_encryption = ContactsCrypto.objects.create(
        ...    contact=contact, encryption_software=encryption_software)
        >>> sleep(150)
        >>> wait_until_queue_empty(GPG_RQ, GPG_REDIS_PORT)
        >>> len(get_all_user_keys(contact.email)) == 1
        True
        >>> isinstance(get_all_user_keys(contact.email), QuerySet)
        True
        >>> contacts.delete(email)
        True
        >>> wait_until_queue_empty(GPG_RQ, GPG_REDIS_PORT)
    '''

    query_set = None
    try:
        if email is None:
            log_message('missing data to get user key')
        else:
            address = get_email(email)
            query_set = UserKey.objects.filter(contacts_encryption__contact__email=address)
            if query_set is None:
                log_message("{} does not have any encryption program with a private key defined".format(email))
            else:
                log_message("{} has {} encryption program(s) with private key(s)".format(email, len(query_set)))
    except UserKey.DoesNotExist:
        log_message('{} does not have any encryption programs with private keys defined'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return query_set
Beispiel #28
0
def exists(email):
    '''
        Determine if the contact has at least one passcode.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Juan Gonzalez,who frequently co-hosts Democracy Now!
        >>> exists('*****@*****.**')
        False
    '''

    address = get_email(email)
    query_set = get_all_user_keys(address)
    found = query_set is not None and len(query_set) > 0
    log_message("{} private key exists: {}".format(address, found))

    return found
    def set_smtp_recipient(self, email_address):
        '''
            Sets the SMTP recipient email address. If a message had its metadata
            protected, then we'll set the "smtp recipient" as the inner, protected
            messages are set. This address is never derived from the "header"
            section of a message.

            >>> # In honor of the Navy nurse who refused to torture prisoners
            >>> # in Guantanamo by force feeding them.
            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_smtp_recipient('*****@*****.**')
            >>> recipient = crypto_message.smtp_recipient()
            >>> recipient == '*****@*****.**'
            True
        '''

        self.recipient = get_email(email_address)
        if self.DEBUGGING: self.log_message('set recipient: {}'.format(self.recipient))
Beispiel #30
0
def exists(email):
    '''
        Determine if the contact has at least one passcode.

        Test an unknown email address so we're sure of the result.
        See the unittest to understand how to really use this function.

        >>> # In honor of Juan Gonzalez,who frequently co-hosts Democracy Now!
        >>> exists('*****@*****.**')
        False
    '''

    address = get_email(email)
    query_set = get_all_user_keys(address)
    found = query_set is not None and len(query_set) > 0
    log_message("{} private key exists: {}".format(address, found))

    return found
    def set_smtp_recipient(self, email_address):
        '''
            Sets the SMTP recipient email address. If a message had its metadata
            protected, then we'll set the "smtp recipient" as the inner, protected
            messages are set. This address is never derived from the "header"
            section of a message.

            >>> # In honor of the Navy nurse who refused to torture prisoners
            >>> # in Guantanamo by force feeding them.
            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_smtp_recipient('*****@*****.**')
            >>> recipient = crypto_message.smtp_recipient()
            >>> recipient == '*****@*****.**'
            True
        '''

        self.recipient = get_email(email_address)
        if self.DEBUGGING:
            self.log_message('set recipient: {}'.format(self.recipient))
def get_contacts_crypto(email, encryption_name=None):
    '''
        Get the ContactsCrypto record that matches the encryption_name for this email.
        If the encryption_name is None, then get the query results of all the ContactsCrypto for this email.

        # Test extreme case. See unittests to see how to use this function.
        >>> get_contacts_crypto(None) == None
        True
    '''

    query_results = None
    try:
        address = get_email(email)
        if email is not None and len(address) > 0:
            if encryption_name is None:
                query_results = ContactsCrypto.objects.filter(
                    contact__email=address, encryption_software__active=True)
            else:
                query_results = ContactsCrypto.objects.get(
                    contact__email=address,
                    encryption_software__name=encryption_name)

            if query_results is None:
                log_message(
                    "{} does not have any active encryption software defined".
                    format(address))
            else:
                from django.db.models.query import QuerySet

                if isinstance(query_results, QuerySet):
                    log_message("{} has {} encryption software defined".format(
                        email, len(query_results)))
        else:
            log_message("{} is not parseable".format(email))
    except ContactsCrypto.DoesNotExist:
        log_message('{} does not use {}'.format(email, encryption_name))
    except Contact.DoesNotExist:
        log_message('{} does not exist in the contacts table'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return query_results
Beispiel #33
0
def add_clear_signed_tags(crypto_message):
    ''' Add tags about the clear signer. '''

    log_message("clear signed: {}".format(crypto_message.is_clear_signed()))

    signers = crypto_message.clear_signers_list()
    if len(signers) > 0:
        sender = get_email(crypto_message.smtp_sender())
        for signer_dict in signers:
            signer = signer_dict[constants.SIGNER]
            log_message("clear signed by: {}".format(signer))
            if signer == sender:
                crypto_message.add_tag_once(CONTENT_SIGNED_BY.format(email=signer))
            elif signer == 'unknown user':
                crypto_message.add_error_tag_once(UNKNOWN_SIGNER_WARNING)
            else:
                crypto_message.add_error_tag_once(
                   CONTENT_NOT_SIGNED_BY_WARNING.format(email=signer, sender=sender))
    else:
        crypto_message.add_error_tag_once(UNKNOWN_SIGNER_WARNING)
def get_encryption_software(email):
    '''
        Gets the list of active encryption software for a contact.

        If the contact has no encryption software, returns a list
        consisting of just the default encryption software.

        >>> from goodcrypto.oce.test_constants import JOSEPH_REMOTE_USER
        >>> encryption_software = get_encryption_software(JOSEPH_REMOTE_USER)
        >>> encryption_software == ['GPG']
        True
        >>> get_encryption_software(None)
        []
    '''

    encryption_software_list = []

    try:
        #  start with the encryption software for this email
        address = get_email(email)

        from goodcrypto.mail.contacts import get_encryption_names
        encryption_names = get_encryption_names(address)
        if encryption_names is None:
            log_message("no encryption software names for {}".format(address))
            #  make sure we have at least the default encryption
            default_encryption_software = CryptoFactory.get_default_encryption_name()
            log_message("  defaulting to {}".format(default_encryption_software))
            encryption_names.append(default_encryption_software)

        #  only include active encryption software
        active_encryption_software = get_active_encryption_software()
        if active_encryption_software:
            for encryption_software in encryption_names:
                if encryption_software in active_encryption_software:
                    encryption_software_list.append(encryption_software)
    except:
        encryption_software_list = []
        record_exception()

    return encryption_software_list
Beispiel #35
0
    def get_fingerprint(self, user_id):
        '''
            Returns a key's fingerprint and expiration.

            Test extreme case
            >>> from goodcrypto.oce.key.key_factory import KeyFactory
            >>> plugin = KeyFactory.get_crypto(gpg_key_constants.NAME)
            >>> plugin.set_home_dir(plugin.GPG_HOME_DIR)
            True
            >>> plugin.get_fingerprint(None)
            (None, None)
        '''

        fingerprint = expiration_date = None
        try:
            email = get_email(user_id)
            self.log_message('getting fingerprint for {}'.format(email))

            # add angle brackets around the email address so we don't
            # confuse the email with any similar addresses and non-ascii characters are ok
            args = [gpg_constants.GET_FINGERPRINT, self.get_user_id_spec(email)]
            result_code, gpg_output, gpg_error= self.gpg_command(args)
            if result_code == gpg_constants.GOOD_RESULT:
                if GPGPlugin.DEBUGGING: self.log_message('fingerprint gpg output: {}'.format(gpg_output))
                fingerprint, expiration_date = gpg_utils.parse_fingerprint_and_expiration(gpg_output)
                self.log_message('{} fingerprint: {}'.format(email, fingerprint))
                self.log_message('{} expiration_date: {}'.format(email, expiration_date))
            # unable to get key
            elif result_code == gpg_constants.CONDITIONAL_RESULT:
                self.log_message(gpg_error.strip())
            else:
                errors = gpg_error
                if errors is not None:
                    errors = gpg_error
                self.log_message('gpg command had errors')
                self.log_message('  result code: {} / gpg error'.format(result_code))
                self.log_message(errors)
        except Exception as exception:
            self.handle_unexpected_exception(exception)

        return fingerprint, expiration_date
def parse_domain(email):
    '''
        Get the domain from the email address.

        >>> domain = parse_domain(None)
        >>> domain is None
        True
    '''

    domain = None

    if email is None:
        log_message('email not defined so no domain')
    else:
        try:
            address = get_email(email)
            __, __, domain = address.partition('@')
        except:
            record_exception()

    return domain
    def add_signer(self, signer_dict, signer_list):
        '''
            Add who signed this email_message.

            >>> crypto_message = CryptoMessage()
            >>> clear_signers = crypto_message.clear_signers_list()
            >>> crypto_message.add_signer({'signer': '*****@*****.**', 'verified': True}, clear_signers)
        '''

        if signer_dict is not None:
            signer = signer_dict[constants.SIGNER]
            if signer is not None:
                signer = get_email(signer)
            # now make the signer readable if unknown
            if signer == None:
                signer = 'unknown user'

            signer_dict[constants.SIGNER] = signer
            if signer_dict not in signer_list:
                if self.DEBUGGING: self.log_message("add signer: {}".format(signer_dict))
                signer_list.append(signer_dict)
    def set_smtp_sender(self, email_address):
        '''
            Sets the SMTP sender email address. If a message had its metadata
            protected, then we'll set the "smtp sender" as the inner, protected
            messages are set. This address is never derived from the "header"
            section of a message.

            # In honor of Sister Megan Rice, an anti-nuclear activist who was
            # initially sentenced for breaking into a US nuclear facility as a protest.
            # Fortunately, she was finally released when federal appeals court acknowledged a
            # little old lady had embarrassed the gov't, not threatened them.
            >>> from goodcrypto_tests.mail.message_utils import get_basic_email_message
            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_smtp_sender('*****@*****.**')
            >>> sender = crypto_message.smtp_sender()
            >>> sender == '*****@*****.**'
            True
        '''

        self.sender = get_email(email_address)
        if self.DEBUGGING: self.log_message('set sender: {}'.format(self.sender))
Beispiel #39
0
def get_contacts_crypto(email, encryption_name=None):
    '''
        Get the ContactsCrypto record that matches the encryption_name for this email.
        If the encryption_name is None, then get the query results of all the ContactsCrypto for this email.

        # Test extreme case. See unittests to see how to use this function.
        >>> get_contacts_crypto(None) == None
        True
    '''

    query_results = None
    try:
        address = get_email(email)
        if email is not None and len(address) > 0:
            if encryption_name is None:
                query_results = ContactsCrypto.objects.filter(
                  contact__email=address, encryption_software__active=True)
            else:
                query_results = ContactsCrypto.objects.get(contact__email=address,
                  encryption_software__name=encryption_name)

            if query_results is None:
                log_message("{} does not have any active encryption software defined".format(address))
            else:
                from django.db.models.query import QuerySet

                if isinstance(query_results, QuerySet):
                    log_message("{} has {} encryption software defined".format(email, len(query_results)))
        else:
            log_message("{} is not parseable".format(email))
    except ContactsCrypto.DoesNotExist:
        log_message('{} does not use {}'.format(email, encryption_name))
    except Contact.DoesNotExist:
        log_message('{} does not exist in the contacts table'.format(email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return query_results
    def set_smtp_sender(self, email_address):
        '''
            Sets the SMTP sender email address. If a message had its metadata
            protected, then we'll set the "smtp sender" as the inner, protected
            messages are set. This address is never derived from the "header"
            section of a message.

            # In honor of Sister Megan Rice, an anti-nuclear activist who was
            # initially sentenced for breaking into a US nuclear facility as a protest.
            # Fortunately, she was finally released when federal appeals court acknowledged a
            # little old lady had embarrassed the gov't, not threatened them.
            >>> from goodcrypto_tests.mail.message_utils import get_basic_email_message
            >>> crypto_message = CryptoMessage()
            >>> crypto_message.set_smtp_sender('*****@*****.**')
            >>> sender = crypto_message.smtp_sender()
            >>> sender == '*****@*****.**'
            True
        '''

        self.sender = get_email(email_address)
        if self.DEBUGGING:
            self.log_message('set sender: {}'.format(self.sender))
    def add_signer(self, signer_dict, signer_list):
        '''
            Add who signed this email_message.

            >>> crypto_message = CryptoMessage()
            >>> clear_signers = crypto_message.clear_signers_list()
            >>> crypto_message.add_signer({'signer': '*****@*****.**', 'verified': True}, clear_signers)
        '''

        if signer_dict is not None:
            signer = signer_dict[constants.SIGNER]
            if signer is not None:
                signer = get_email(signer)
            # now make the signer readable if unknown
            if signer == None:
                signer = 'unknown user'

            signer_dict[constants.SIGNER] = signer
            if signer_dict not in signer_list:
                if self.DEBUGGING:
                    self.log_message("add signer: {}".format(signer_dict))
                signer_list.append(signer_dict)
Beispiel #42
0
def get_inbound_messages(email):
    ''' Get the decrypted messages when the email address was the recipient. '''

    records = []

    if email is not None:
        address = get_email(email)
        try:
            recipient_records = MessageHistory.objects.filter(recipient=address)
            records = recipient_records.filter(Q(direction=MessageHistory.INBOUND_MESSAGE))
        except MessageHistory.DoesNotExist:
            records = []
        except Exception:
            records = []
            record_exception()
            log_message('EXCEPTION 5 - see syr.exception.log for details')
    else:
        address = email

    log_message("{} has {} decrypted messages".format(address, len(records)))

    return records
Beispiel #43
0
def get_passcode(email, encryption_name):
    '''
        Get the passcode for the encryption program for the contact.
        The email can be an RFC address or just the email address.

        >>> len(get_passcode('*****@*****.**', 'GPG')) > 0
        True
        >>> get_passcode('*****@*****.**', 'TestBC') is None
        True
    '''

    passcode = None

    try:
        if email_in_domain(email):
            address = get_email(email)
            user_key = get(address, encryption_name)
            if user_key:
                passcode = user_key.passcode
                if passcode and len(passcode) > 0:
                    log_message("private {} key configured for {}".format(
                        encryption_name, email))
                else:
                    log_message(
                        '{} does not have a {} private key configured'.format(
                            email, encryption_name))
            else:
                log_message(
                    '{} does not have a matching contact'.format(email))
        else:
            log_message(
                '{} not part of managed domain so no private user key'.format(
                    email))
    except Exception:
        record_exception()
        log_message('EXCEPTION - see syr.exception.log for details')

    return passcode
Beispiel #44
0
def get_outbound_messages(email):
    ''' Get the encrypted messages when the email address was the sender. '''

    records = []

    if email is not None:
        address = get_email(email)
        try:
            sender_records = MessageHistory.objects.filter(sender=address)
            records = sender_records.filter(
              Q(direction=MessageHistory.OUTBOUND_MESSAGE) )
        except MessageHistory.DoesNotExist:
            records = []
        except Exception:
            records = []
            record_exception()
            log_message('EXCEPTION 4 - see syr.exception.log for details')
    else:
        address = email

    log_message("{} has {} encrypted messages".format(address, len(records)))

    return records
def email_in_domain(email):
    ''' Determine if the email address has the supported domain.

        >>> # In honor of Sergeant First Class Amitai, who co-signed letter and refused to serve
        >>> # in operations involving the occupied Palestinian territories because
        >>> # of the widespread surveillance of innocent residents.
        >>> email_in_domain('*****@*****.**')
        True
        >>> email_in_domain('*****@*****.**')
        False
    '''
    if email is None:
        result_ok = False
    else:
        domain = get_domain()
        address = get_email(email)

        if address is None  or len(address) <= 0 or domain is None or len(domain) <= 0:
            result_ok = False
        else:
            result_ok = address.lower().endswith('@{}'.format(domain.lower()))

    return result_ok
Beispiel #46
0
def is_metadata_address(email):
    '''
        Determine if the email address is a metadata address.

        >>> is_metadata_address(None)
        False
    '''
    result = False

    if email is None:
        log_message('email not defined so not a metadata address')
    else:
        try:
            address = get_email(email)
            local, __, __ = address.partition('@')
            if local == get_domain_user():
                result = True
        except:
            log_message('unable to partition: {} ({})'.format(email, address))
            record_exception()
            log_message('EXCEPTION - see syr.exception.log for details')

    return result
    def encrypt_message(crypto_message, data):

        encryption_ready = False
        encrypted_with = []

        # use the metadata address' encryption
        to_metadata_address = metadata.get_metadata_address(email=to_user)
        encryption_names = contacts.get_encryption_names(to_metadata_address)
        log_message('{} encryption software for: {}'.format(
            encryption_names, to_metadata_address))

        if len(encryption_names) < 1:
            error_message = i18n(
                'Unable to protect metadata because there are no encryption programs for {}.'
                .format(to_metadata_address))
            log_message(error_message)
            raise MessageException(value=error_message)
        else:
            # encrypt with each common encryption program
            for encryption_name in encryption_names:
                ready, to_metadata_address, __ = metadata.get_metadata_user_details(
                    to_user, encryption_name)
                log_message('to metadata ready {} '.format(ready))

                if ready:
                    ready, from_metadata_address, passcode = metadata.get_from_metadata_user_details(
                        from_user, encryption_name)
                    log_message('metadata keys ready {}'.format(ready))

                if ready:
                    log_message(
                        'protecting metadata with {}'.format(encryption_names))

                    # if we're ready with any key, then the encryption is ready
                    encryption_ready = True

                    from_user_id = get_email(from_metadata_address)
                    to_user_id = get_email(to_metadata_address)
                    crypto_message.set_smtp_sender(from_user_id)
                    crypto_message.set_smtp_recipient(to_user_id)

                    # use the default charset to prevent metadata leakage
                    charset, __ = get_charset(constants.DEFAULT_CHAR_SET)
                    users_dict = {
                        TO_KEYWORD: to_user_id,
                        FROM_KEYWORD: from_user_id,
                        PASSCODE_KEYWORD: passcode,
                        CHARSET_KEYWORD: charset
                    }

                    crypto = CryptoFactory.get_crypto(
                        encryption_name, get_classname(encryption_name))
                    ciphertext, error_message = encrypt_byte_array(
                        data, crypto, users_dict)
                    if ciphertext is not None and len(ciphertext) > 0:
                        crypto_message.get_email_message().get_message(
                        ).set_payload(ciphertext)

                        crypto_message.add_public_key_to_header(
                            users_dict[FROM_KEYWORD])
                        set_sigs(crypto_message, from_user_id, passcode)
                        crypto_message.set_filtered(True)
                        crypto_message.set_crypted(True)

                        # use the encrypted data for the next level of encryption
                        data = ciphertext

                        encrypted_with.append(encryption_name)
                    else:
                        log_message(
                            'unable to encrypt the metadata with {}'.format(
                                encryption_name))
                        raise MessageException(value=error_message)
                else:
                    log_message('unable to protect metadata with {}'.format(
                        encryption_name))

            return encryption_ready, encrypted_with
def verify_clear_signed(email,
                        crypto_message,
                        encryption_name=DEFAULT_CRYPTO,
                        crypto=None):
    '''
        Check the signature if message is clear signed and remove signature.

        >>> # In honor of Mike Perry, Tor Browser and Tor Performance developer.
        >>> from goodcrypto.mail.message.crypto_message import CryptoMessage
        >>> from goodcrypto.mail.message.email_message import EmailMessage
        >>> from goodcrypto_tests.mail.message_utils import get_plain_message_name
        >>> with open(get_plain_message_name('pgp-sig-unknown.txt')) as input_file:
        ...    email = '*****@*****.**'
        ...    crypto_message = CryptoMessage(email_message=EmailMessage(input_file))
        ...    verify_clear_signed(email, crypto_message, encryption_name=DEFAULT_CRYPTO)
        ...    signers = crypto_message.clear_signers_list()
        ...    signers == [{'signer': 'unknown user', 'verified': False}]
        True
    '''
    def extract_signers(email,
                        signature_blocks,
                        encryption_name=DEFAULT_CRYPTO):
        ''' Extract the signers if message is signed. '''

        known_signers = False

        crypto = CryptoFactory.get_crypto(
            encryption_name, crypto_software.get_classname(encryption_name))
        log_message('checking if message signed by {}'.format(email))
        for signature_block in signature_blocks:
            if crypto.verify(signature_block, email):
                signer_dict = {
                    SIGNER: email,
                    SIGNER_VERIFIED: True,
                }
                known_signers = True
                log_message('{} signed message'.format(email))
            else:
                log_message('signature block\n{}'.format(signature_block))
                signer = crypto.get_signer(signature_block)
                log_message('unverified signature by {}'.format(signer))
                signer_dict = {
                    SIGNER: signer,
                    SIGNER_VERIFIED: False,
                }

            crypto_message.add_clear_signer(signer_dict)

        log_message('clear signers: {}'.format(
            crypto_message.clear_signers_list()))

        return known_signers

    # if the message is signed, then verify the signature
    signature_blocks = crypto_message.get_email_message(
    ).get_pgp_signature_blocks()
    if len(signature_blocks) > 0:
        crypto_message.set_clear_signed(True)
        log_message('clear signed')

        # remove the signature block if signer known
        # techies won't like this, but it makes the message more readable
        if extract_signers(get_email(email),
                           signature_blocks,
                           encryption_name=encryption_name):
            crypto_message.get_email_message().remove_pgp_signature_blocks()
    else:
        if DEBUGGING:
            log_message('no signature block found in this part of message')
Beispiel #49
0
def get_decrypt_signature_tag(crypto_message, from_user, signed_by, crypto_name):
    ''' Get the tag when the encrypted message was signed. '''

    tag = None
    if len(crypto_message.get_metadata_crypted_with()) > 0:
        log_message('metadata crypted with: {}'.format(crypto_message.get_metadata_crypted_with()))
        received_privately = RECEIVED_FULL_MESSAGE_PRIVATELY
    else:
        received_privately = RECEIVED_CONTENT_PRIVATELY

    if signed_by is None:
        tag = '{}, {}'.format(received_privately, SENDER_UNSIGNED_SUFFIX)
    else:
        from_user_addr = get_email(from_user)
        signed_by_addr = get_email(signed_by)
        log_message("message encrypted and signed by {}".format(signed_by_addr))

        # if the signer's not a match with the sender, see if the key is used for multiple
        # email addresses and one of those addresses is the sender's address
        if from_user_addr != signed_by_addr:
            log_message("checking if key is for multiple email addresses")
            from_fingerprint, __, __ = get_fingerprint(from_user_addr, crypto_name)
            if from_fingerprint is not None:
                signer_fingerprint, __, __ = get_fingerprint(signed_by_addr, crypto_name)
                if from_fingerprint == signer_fingerprint:
                    signed_by_addr = from_user_addr
                    log_message("signer key is for multiple addresses, including sender")

        # remember that the message was signed
        crypto_message.set_private_signed(True)

        if from_user_addr == signed_by_addr:
            # assume the key is ok unless it's required to be verified before we use it
            key_ok = not options.require_key_verified()
            if not key_ok:
                __, key_ok, __ = get_fingerprint(signed_by_addr, crypto_name)

            if key_ok:
                tag = '{}.'.format(received_privately)
                crypto_message.add_private_signer({
                   constants.SIGNER: signed_by_addr, constants.SIGNER_VERIFIED: True})
                log_message('signed by: {}'.format(crypto_message.private_signers_list()))
            else:
                tag = '{}, {}'.format(
                  received_privately, KEY_UNVERIFIED_SUFFIX.format(email=signed_by_addr))

                crypto_message.add_private_signer({
                  constants.SIGNER: signed_by_addr, constants.SIGNER_VERIFIED: False})
                log_message('signed by: {}'.format(crypto_message.private_signers_list()))
        else:
            tag = '{}, {}'.format(
              received_privately,
              SIGNED_BY_NOT_BY_SUFFIX.format(signer=signed_by_addr, sender=from_user_addr))

            crypto_message.add_private_signer({
              constants.SIGNER: signed_by_addr, constants.SIGNER_VERIFIED: False})
            log_message('signed by: {}'.format(crypto_message.private_signers_list()))

    log_message('verified sig tag: {}'.format(tag))

    return tag