diff --git a/reaction-mailcreate/createMails.py b/reaction-mailcreate/createMails.py index c5a7b8033cbe9cc659fc388955d343f00c43ced0..588536d569a1c1e55180bb3fc9f6bdcecb88dfa2 100755 --- a/reaction-mailcreate/createMails.py +++ b/reaction-mailcreate/createMails.py @@ -66,7 +66,7 @@ parser.add_argument('-i', '--input', dest='input', default='{basedir}/ parser.add_argument('-o', '--output', dest='output', default='{basedir}/{campaign}/{site}/{timestamp}{infix}.eml', help='output file name template (default: "{basedir}/{campaign}/{site}/{timestamp}{infix}.eml")') parser.add_argument('-R', '--reply-to', dest='replyto', default=None, help='reply-to mail address (default: None)') parser.add_argument( '--salt', dest='salt', default=None, help='salt to use for hashing (default: random 8-byte hex string)') -parser.add_argument( '--sign', dest='sign', default='', choices=['', 'gpg'], help='signature method (default: ""); one of "", "gpg"') +parser.add_argument( '--sign', dest='sign', default='', type=str.lower, choices=['', 'gpg', 'gpgsm'], help='signature method (default: ""); one of "", "gpg"') parser.add_argument( '--sign-arg', dest='signarg', default={}, nargs=1, action='keyvalue', help='additional arguments to be passed to the signature call (default: None)') parser.add_argument('-s', '--subject', dest='subject', default='Security Challenge for {site} -- {campaign}{infix}', help='mail subject (default: "Security Challenge Message -- {campaign}{infix}")') parser.add_argument('-S', '--smtpserver', dest='smtpserver', default='localhost', help='SMTP server to use (default: "localhost"); port can be specified with "<host>:<port>" notation and takes precedence over implied ports and port specification') @@ -84,8 +84,6 @@ parser.add_argument('-w', '--webserver', dest='webserver', default='https://ch parser.add_argument('infix', default='', nargs='?', help='infix for ID purposes, default empty') args = parser.parse_args() -print(args) - class SafeDict(dict): def __missing__(self, key): return '{' + key + '}' @@ -99,7 +97,6 @@ if (args.sender == 'Nobody <nobody@example.com>') or \ # Import dependencies for actual SMTP interaction if necessary if not args.dryrun: import smtplib - # Import dependencies for HTTTP interaction if necessary if not args.webserver: import requests @@ -142,6 +139,9 @@ if args.smtppass and not args.smtpuser: if args.smtppass == '-': args.smtppass = getpass.getpass('SMTP authentication password: ') +if args.sign and 'keyid' not in args.signarg: + args.signarg['keyid'] = args.sender + if args.dryrun: print('DRY RUN. Not actually sending e-mails or creating targets, just creating mail files and URLs.') if args.force: @@ -173,10 +173,8 @@ if args.verbose: print(f'Using "{args.salt.format_map(SafeDict(basedir=args.basedir, campaign=args.campaign, infix=args.infix, webserver=args.webserver, salt=args.salt))}" as salt.') if args.sign: print(f'Using "{args.sign}" as signature method.') - if args.signas: - print(f'Using "{args.signas}" as signing key.') - else: - print(f'Using auto-selected signing key.') + if args.signarg: + print(f'Using "{str(args.signarg)}" as signing argument(s).') else: print(f'Using no signature method.') print(f'Using "{args.subject.format_map(SafeDict(basedir=args.basedir, campaign=args.campaign, infix=args.infix, webserver=args.webserver, salt=args.salt))}" as mail subject.') @@ -217,24 +215,38 @@ def toHex(serial): # Sign message with GPG/GPGSM -def signMailGPG(binary, message): +def signMailGPG(message): # Set up GPG context - gpg = gnupg.GPG(gpgbinary=binary) + if args.sign == 'gpg': + gpg = gnupg.GPG() + else: + gpg = gnupg.GPG(gpgbinary='gpgsm') # Sign mail try: - signature = str(gpg.sign(message.as_string().replace('\n', '\r\n'), detach=True)) + signature = str(gpg.sign(message.as_string().replace('\n', '\r\n'), detach=True, **args.signarg)) except: print('ERROR signing mail!') + if not signature: + print('ERROR signing mail!') + raise Exception('Empty signature!') + # Assemble signature message signatureMessage = EmailMessage() - signatureMessage['Content-Type'] = 'application/pgp-signature; name="signature.asc"' - signatureMessage['Content-Description'] = 'OpenPGP digital signature' + if args.sign == 'gpg': + signatureMessage['Content-Type'] = 'application/pgp-signature; name="signature.asc"' + signatureMessage['Content-Description'] = 'OpenPGP digital signature' + else: + signatureMessage['Content-Type'] = 'application/pkcs7-signature; name="smime.p7s"' + signatureMessage['Content-Description'] = 'S/MIME digital signature' signatureMessage.set_payload(signature) # Assemble new message - newMessage = MIMEMultipart(_subtype="signed", protocol="application/pgp-signature") + if args.sign == 'gpg': + newMessage = MIMEMultipart(_subtype='signed', protocol='application/pgp-signature') + else: + newMessage = MIMEMultipart(_subtype='signed', protocol='application/pkcs7-signature') newMessage.attach(message) newMessage.attach(signatureMessage) @@ -252,10 +264,8 @@ def signMail(message): return message match args.sign: - case 'gpg': - return signMailGPG('gpg', message) - case 'gpgsm': - return signMailGPG('gpgsm', message) + case 'gpg' | 'gpgsm': + return signMailGPG(message) case 'openssl': return signMailOpenSSL(message)