示例#1
0
    def examine(self, suspect):
        if not DKIMPY_AVAILABLE:
            suspect.debug("dkimpy not available, can not check")
            suspect.set_tag('DKIMVerify.skipreason',
                            'dkimpy library not available')
            return DUNNO

        hdr_from_domain = extract_from_domain(suspect)
        if not hdr_from_domain:
            self.logger.debug(
                '%s DKIM Verification skipped, no header from address')
            suspect.set_tag("DKIMVerify.skipreason", 'no header from address')
            return DUNNO

        self.skiplist.filename = self.config.get(self.section, 'skiplist')
        skiplist = self.skiplist.get_list()
        if hdr_from_domain in skiplist:
            self.logger.debug(
                '%s DKIM Verification skipped, sender domain skiplisted')
            suspect.set_tag("DKIMVerify.skipreason",
                            'sender domain skiplisted')
            return DUNNO

        source = suspect.get_original_source()
        if "dkim-signature" not in suspect.get_message_rep():
            suspect.set_tag('DKIMVerify.skipreason', 'not dkim signed')
            suspect.write_sa_temp_header('X-DKIMVerify', 'unsigned')
            suspect.debug("No dkim signature header found")
            return DUNNO
        # use the local logger of the plugin but prepend the fuglu id
        d = DKIM(source,
                 logger=PrependLoggerMsg(self.logger,
                                         prepend=suspect.id,
                                         maxlevel=logging.INFO))

        try:
            try:
                valid = d.verify()
            except DKIMException as de:
                self.logger.warning("%s: DKIM validation failed: %s" %
                                    (suspect.id, str(de)))
                valid = False
            suspect.set_tag("DKIMVerify.sigvalid", valid)
            suspect.write_sa_temp_header('X-DKIMVerify',
                                         'valid' if valid else 'invalid')
        except NameError as ne:
            self.logger.warning(
                "%s: DKIM validation failed due to missing dependency: %s" %
                (suspect.id, str(ne)))
            suspect.set_tag('DKIMVerify.skipreason', 'plugin error')
        except Exception as e:
            self.logger.warning("%s: DKIM validation failed: %s" %
                                (suspect.id, str(e)))
            suspect.set_tag('DKIMVerify.skipreason', 'plugin error')

        return DUNNO
def check_dkim(msg, dnsfunc=None):
    d = DKIM(msg)
    try:
        if(dnsfunc):
            res = d.verify(dnsfunc=dnsfunc) and 'pass' or 'fail'
        else:
            res = d.verify() and 'pass' or 'fail'
    except DKIMException as e:
        res = 'fail'

    header_i = d.signature_fields.get(b'i', b'').decode('ascii')
    header_d = d.signature_fields.get(b'd', b'').decode('ascii')

    return DKIMAuthenticationResult(result=res, header_d=header_d, header_i=header_i)
def sign_message(msg, selector, domain, privkey, sig_headers, sig='DKIM', srv_id=None,
                 identity=None, length=None, canonicalize=(b'relaxed', b'relaxed'), timestamp=None,
                 logger=None, standardize=False):
    """Sign an RFC822 message and return the ARC or DKIM header(s)
    @param msg: an RFC822 formatted message (with either \\n or \\r\\n line endings)
    @param selector: the DKIM selector value for the signature
    @param domain: the DKIM domain value for the signature
    @param privkey: a PKCS#1 private key in base64-encoded text form
    @param sig_headers: a list of strings indicating which headers are to be signed
    @param sig: "DKIM" or "ARC"
    @param srv_id: an authserv_id to identify AR headers to sign
    @param identity: (DKIM) the DKIM identity value for the signature (default "@"+domain)
    @param length: (DKIM) true if the l= tag should be included to indicate body length (default False)
    @param canonicalize: (DKIM) the canonicalization algorithms to use (default (Relaxed, Relaxed))
    @param timestamp: (for testing) a manual timestamp to use for signature generation
    @param logger: An optional logger
    @param standardize: A testing flag for arc to output a standardized header format
    @return: The DKIM-Message-Signature, or ARC set headers
    @raises: DKIMException if mis-configured
    """

    if sig=="DKIM":
        return DKIM(msg, logger=logger).sign(selector, domain, privkey, include_headers=sig_headers,
                              identity=identity, length=length, canonicalize=canonicalize, timestamp=timestamp)
    else:
        return ARC(msg, logger=logger).sign(selector, domain, privkey, srv_id, include_headers=sig_headers, timestamp=timestamp, standardize=standardize)
def add_dkim_sig_optionally(crypto_message):
    ''' Add DKIM signature if option selected. '''

    if (options.add_dkim_sig() and options.dkim_public_key() is not None
            and len(options.dkim_public_key()) > 0):

        log_message('trying to add DKIM signature')

        try:
            global log

            SELECTOR = b'mail'
            DKIM_SIG = b'DKIM-Signature'
            PRIVATE_KEY_FILE = '/etc/opendkim/{}/dkim.private.key'.format(
                get_domain())

            # in case there's a mixture of CR-LF and LF lines, convert CR-LF to LF and then all LFs to CR-LFs
            message = crypto_message.get_email_message().to_string().replace(
                constants.CRLF, constants.LF).replace(constants.LF,
                                                      constants.CRLF)

            charset, __ = get_charset(crypto_message.get_email_message())
            msg = bytes(message, charset)
            with open(PRIVATE_KEY_FILE, 'rb') as f:
                private_key = f.read()

            dkim = DKIM(message=msg, minkey=constants.MIN_DKIM_KEY, logger=log)
            # stop header injections of standard headers
            dkim.frozen_sign = set(DKIM.RFC5322_SINGLETON)
            sig = dkim.sign(SELECTOR, get_domain().encode(), private_key)
            if sig.startswith(DKIM_SIG):
                signed_message = '{}{}'.format(sig.decode(), message)
                crypto_message.get_email_message().set_message(signed_message)
                crypto_message.set_dkim_signed(True)
                crypto_message.set_dkim_sig_verified(True)
                log_message('added DKIM signature successfully')
            else:
                log_message('error trying to add DKIM signature')
        except ParameterError as pe:
            log_message(str(pe))
        except:
            log_message('EXCEPTION - see syr.exception.log for details')
            record_exception()

    return crypto_message
示例#5
0
    def examine(self, suspect):
        if not DKIMPY_AVAILABLE:
            suspect.debug("dkimpy not available, can not check")
            suspect.set_tag(
                'DKIMVerify.skipreason', 'dkimpy library not available')
            return DUNNO

        source = suspect.get_original_source()
        if "dkim-signature: " not in suspect.get_headers().lower():
            suspect.set_tag('DKIMVerify.skipreason', 'not dkim signed')
            suspect.debug("No dkim signature header found")
            return DUNNO
        d = DKIM(source, logger=suspect.get_tag('debugfile'))
        try:
            valid = d.verify(source)
        except DKIMException, de:
            self.logger.warning("%s: DKIM validation failed: %s" % (str(de)))
            valid = False
def add_dkim_sig_optionally(crypto_message):
    ''' Add DKIM signature if option selected. '''

    if (options.add_dkim_sig() and
        options.dkim_public_key() is not None and
        len(options.dkim_public_key()) > 0):

        log_message('trying to add DKIM signature')

        try:
            global log

            SELECTOR = b'mail'
            DKIM_SIG = b'DKIM-Signature'
            PRIVATE_KEY_FILE = '/etc/opendkim/{}/dkim.private.key'.format(get_domain())

            # in case there's a mixture of CR-LF and LF lines, convert CR-LF to LF and then all LFs to CR-LFs
            message = crypto_message.get_email_message().to_string().replace(
                constants.CRLF, constants.LF).replace(constants.LF, constants.CRLF)

            charset, __ = get_charset(crypto_message.get_email_message())
            msg = bytes(message, charset)
            with open(PRIVATE_KEY_FILE, 'rb') as f:
                private_key = f.read()

            dkim = DKIM(message=msg, minkey=constants.MIN_DKIM_KEY, logger=log)
            # stop header injections of standard headers
            dkim.frozen_sign = set(DKIM.RFC5322_SINGLETON)
            sig = dkim.sign(SELECTOR, get_domain().encode(), private_key)
            if sig.startswith(DKIM_SIG):
                signed_message = '{}{}'.format(sig.decode(), message)
                crypto_message.get_email_message().set_message(signed_message)
                crypto_message.set_dkim_signed(True)
                crypto_message.set_dkim_sig_verified(True)
                log_message('added DKIM signature successfully')
            else:
                log_message('error trying to add DKIM signature')
        except ParameterError as pe:
            log_message(str(pe))
        except:
            log_message('EXCEPTION - see syr.exception.log for details')
            record_exception()

    return crypto_message
示例#7
0
def check_dkim(msg, dnsfunc=None):
    try:
        d = DKIM(msg)
        if (dnsfunc):
            res = d.verify(dnsfunc=dnsfunc) and 'pass' or 'fail'
        else:
            res = d.verify() and 'pass' or 'fail'
    # TODO: this could probably just be one line of:
    #       `except Exception as e:`
    except DKIMException as e:
        res = 'fail'
    except DNSException as e:
        res = 'fail'
    except Exception as e:
        res = 'fail'

    header_i = d.signature_fields.get(b'i', b'').decode('ascii')
    header_d = d.signature_fields.get(b'd', b'').decode('ascii')

    return DKIMAuthenticationResult(result=res,
                                    header_d=header_d,
                                    header_i=header_i)
示例#8
0
    def examine(self, suspect):
        if not DKIMPY_AVAILABLE:
            suspect.debug("dkimpy not available, can not check")
            suspect.set_tag(
                'DKIMVerify.skipreason', 'dkimpy library not available')
            return DUNNO

        source = suspect.get_original_source()
        if "dkim-signature: " not in suspect.get_headers().lower():
            suspect.set_tag('DKIMVerify.skipreason', 'not dkim signed')
            suspect.debug("No dkim signature header found")
            return DUNNO
        d = DKIM(source, logger=suspect.get_tag('debugfile'))

        try:
            valid = d.verify()
        except DKIMException as de:
            self.logger.warning("%s: DKIM validation failed: %s" %
                                (suspect.id, str(de)))
            valid = False

        suspect.set_tag("DKIMVerify.sigvalid", valid)
        return DUNNO
示例#9
0
#!/usr/bin/env python3
# Command-line tool to use hardcoded public-key instead of DNS query
# from https://gist.githubusercontent.com/stevecheckoway/51e63d4c269bd2be4a50a3b39645a77c/raw/4ed815490f4c619a5ba47dcd01d50aa32ee2cf55/verify.py
# written by Stephen Checkoway @stevecheckoway
# do 'pip install dkimpy' first to get 'dkim' dependency

from dkim import DKIM
import sys


def get_txt(*args, **kwargs):
    return b'k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Kd87/UeJjenpabgbFwh+eBCsSTrqmwIYYvywlbhbqoo2DymndFkbjOVIPIldNs/m40KF+yzMn1skyoxcTUGCQs8g3FgD2Ap3ZB5DekAo5wMmk4wimDO+U8QzI3SD0" "7y2+07wlNWwIt8svnxgdxGkVbbhzY8i+RQ9DpSVpPbF7ykQxtKXkv/ahW3KjViiAH+ghvvIhkx4xYSIc9oSwVmAl5OctMEeWUwg8Istjqz8BZeTWbf41fbNhte7Y+YqZOwq1Sd0DbvYAD9NOZK9vlfuac0598HY+vtSBczUiKERHv1yRbcaQtZFh5wtiRrN04BLUTD21MycBX5jYchHjPY/wIDAQAB'


failed = False

for path in sys.argv[1:]:
    with open(path, 'rb') as f:
        verifier = DKIM(message=f.read())

    if verifier.verify(0, dnsfunc=get_txt):
        print("{}: DKIM signature verified".format(path))
    else:
        print("{}: DKIM signature verification failed".format(path))
        failed = True
if failed:
    sys.exit(1)