diff --git a/reaction-mailcreate/createMails.py b/reaction-mailcreate/createMails.py index cef0959df058a9f00878afb919394c6031c6bb9a..cf28651538fb9f452157c52935f1925b8bba3a80 100755 --- a/reaction-mailcreate/createMails.py +++ b/reaction-mailcreate/createMails.py @@ -114,6 +114,7 @@ if args.sign: match args.sign: case 'gpg' | 'gpgsm': # Import dependencies for GPG-based mail signing if necessary + from base64 import b64encode from email.mime.multipart import MIMEMultipart import gnupg case 'openssl': @@ -210,6 +211,73 @@ data = dict() template = jinja2.Template(open(args.template.format_map(SafeDict(basedir=args.basedir, campaign=args.campaign, infix=args.infix, webserver=args.webserver, salt=args.salt))).read()) +# Set up GPG context if necessary +gpg = None +if args.sign == 'gpg': + gpg = gnupg.GPG(**args.signinitarg) +elif args.sign == 'gpgsm': + class GPGSM(gnupg.GPG): + def __init__(self, + gpgbinary='gpgsm', + gnupghome=None, + verbose=False, + use_agent=False, + keyring=None, + options=None, + secret_keyring=None, + env=None): + self.gpgbinary = gpgbinary + self.gnupghome = gnupghome + self.env = env + if gnupghome and not os.path.isdir(gnupghome): + raise ValueError('gnupghome should be a directory (it isn\'t): %s' % gnupghome) + if keyring: + if isinstance(keyring, string_types): + keyring = [keyring] + self.keyring = keyring + if secret_keyring: # pragma: no cover + if isinstance(secret_keyring, string_types): + secret_keyring = [secret_keyring] + self.secret_keyring = secret_keyring + self.verbose = verbose + self.use_agent = use_agent + if isinstance(options, str): # pragma: no cover + options = [options] + self.options = options + self.on_data = None # or a callable - will be called with data chunks + self.encoding = 'latin-1' + if gnupghome and not os.path.isdir(self.gnupghome): # pragma: no cover + os.makedirs(self.gnupghome, 0o700) + self.check_fingerprint_collisions = False + def make_args(self, args, passphrase): + cmd = ['gpgsm', '--status-fd', '2', '--no-tty', '--no-verbose'] + if 'DEBUG_IPC' in os.environ: # pragma: no cover + cmd.extend(['--debug', 'ipc']) + if passphrase and hasattr(self, 'version'): + if self.version >= (2, 1): + cmd[1:1] = ['--pinentry-mode', 'loopback'] + cmd.extend(['--batch', '--with-colons']) + if self.gnupghome: + cmd.extend(['--homedir', no_quote(self.gnupghome)]) + if self.keyring: + cmd.append('--no-default-keyring') + for fn in self.keyring: + cmd.extend(['--keyring', no_quote(fn)]) + if self.secret_keyring: # pragma: no cover + for fn in self.secret_keyring: + cmd.extend(['--secret-keyring', no_quote(fn)]) + if passphrase: + cmd.extend(['--passphrase-fd', '0']) + if self.use_agent: # pragma: no cover + cmd.append('--use-agent') + if self.options: + cmd.extend(self.options) + cmd.extend(args) + return cmd + gpg = GPGSM(gpgbinary='gpgsm', **args.signinitarg) + args.signarg['binary'] = True + + # Convert int to hex def toHex(serial): tmpString = hex(serial)[2:].upper() @@ -220,12 +288,6 @@ def toHex(serial): # Sign message with GPG/GPGSM def signMailGPG(message): - # Set up GPG context - if args.sign == 'gpg': - gpg = gnupg.GPG(**args.signinitarg) - else: - gpg = gnupg.GPG(gpgbinary='gpgsm', **args.signinitarg) - # Sign mail try: signature = str(gpg.sign(message.as_string().replace('\n', '\r\n'), detach=True, **args.signarg)) @@ -244,6 +306,8 @@ def signMailGPG(message): else: signatureMessage['Content-Type'] = 'application/pkcs7-signature; name="smime.p7s"' signatureMessage['Content-Description'] = 'S/MIME digital signature' + signatureMessage['Content-Transfer-Encoding'] = 'base64' + signature = b64encode(signature.encode('latin1')) signatureMessage.set_payload(signature) # Assemble new message