Add E2E case: a user with a key and PGP/MIME configured
- Add a new test input message for a new test identity, test scenario configuration and a test key. - While retrieving message payload, determine charset based on the Content-Type header. When missing, default to UTF-8. - Use more comprehensible variables names. - Adjust logging levels.
This commit is contained in:
parent
707fc96234
commit
3bcc1151e5
|
@ -35,20 +35,6 @@ def build_command(key_home, *args, **kwargs):
|
||||||
cmd = ["gpg", '--homedir', key_home] + list(args)
|
cmd = ["gpg", '--homedir', key_home] + list(args)
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
def private_keys( keyhome ):
|
|
||||||
cmd = build_command(keyhome, '--list-secret-keys', '--with-colons')
|
|
||||||
p = subprocess.Popen( cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
|
|
||||||
p.wait()
|
|
||||||
keys = dict()
|
|
||||||
for line in p.stdout.readlines():
|
|
||||||
if line[0:3] == 'uid' or line[0:3] == 'sec':
|
|
||||||
if ('<' not in line or '>' not in line):
|
|
||||||
continue
|
|
||||||
email = line.split('<')[1].split('>')[0]
|
|
||||||
fingerprint = line.split(':')[4]
|
|
||||||
keys[fingerprint] = email
|
|
||||||
return keys
|
|
||||||
|
|
||||||
def public_keys( keyhome ):
|
def public_keys( keyhome ):
|
||||||
cmd = build_command(keyhome, '--list-keys', '--with-colons')
|
cmd = build_command(keyhome, '--list-keys', '--with-colons')
|
||||||
p = subprocess.Popen( cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
|
p = subprocess.Popen( cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
|
||||||
|
@ -58,7 +44,7 @@ def public_keys( keyhome ):
|
||||||
fingerprint = None
|
fingerprint = None
|
||||||
email = None
|
email = None
|
||||||
for line in p.stdout.readlines():
|
for line in p.stdout.readlines():
|
||||||
line = line.decode('utf-8')
|
line = line.decode(sys.getdefaultencoding())
|
||||||
if line[0:3] == LINE_FINGERPRINT:
|
if line[0:3] == LINE_FINGERPRINT:
|
||||||
fingerprint = line.split(':')[POS_FINGERPRINT]
|
fingerprint = line.split(':')[POS_FINGERPRINT]
|
||||||
if line[0:3] == LINE_USER_ID:
|
if line[0:3] == LINE_USER_ID:
|
||||||
|
|
|
@ -113,7 +113,7 @@ def gpg_encrypt( raw_message, recipients ):
|
||||||
else:
|
else:
|
||||||
# Log message only if an unknown style is defined
|
# Log message only if an unknown style is defined
|
||||||
if conf.config_item_set('pgp_style', rcpt[0]):
|
if conf.config_item_set('pgp_style', rcpt[0]):
|
||||||
LOG.info("Style %s for recipient %s is not known. Use default as fallback." % (conf.get_item("pgp_style", rcpt[0]), rcpt[0]))
|
LOG.debug("Style %s for recipient %s is not known. Use default as fallback." % (conf.get_item("pgp_style", rcpt[0]), rcpt[0]))
|
||||||
|
|
||||||
# If no style is in settings defined for recipient, use default from settings
|
# If no style is in settings defined for recipient, use default from settings
|
||||||
if conf.config_item_equals('default', 'mime_conversion', 'yes'):
|
if conf.config_item_equals('default', 'mime_conversion', 'yes'):
|
||||||
|
@ -177,17 +177,17 @@ def encrypt_all_payloads_inline( message, gpg_to_cmdline ):
|
||||||
def encrypt_all_payloads_mime( message, gpg_to_cmdline ):
|
def encrypt_all_payloads_mime( message, gpg_to_cmdline ):
|
||||||
|
|
||||||
# Convert a plain text email into PGP/MIME attachment style. Modeled after enigmail.
|
# Convert a plain text email into PGP/MIME attachment style. Modeled after enigmail.
|
||||||
submsg1 = email.message.Message()
|
pgp_ver_part = email.message.Message()
|
||||||
submsg1.set_payload("Version: 1\n")
|
pgp_ver_part.set_payload("Version: 1\n")
|
||||||
submsg1.set_type("application/pgp-encrypted")
|
pgp_ver_part.set_type("application/pgp-encrypted")
|
||||||
submsg1.set_param('PGP/MIME version identification', "", 'Content-Description' )
|
pgp_ver_part.set_param('PGP/MIME version identification', "", 'Content-Description' )
|
||||||
|
|
||||||
submsg2 = email.message.Message()
|
encrypted_part = email.message.Message()
|
||||||
submsg2.set_type("application/octet-stream")
|
encrypted_part.set_type("application/octet-stream")
|
||||||
submsg2.set_param('name', "encrypted.asc")
|
encrypted_part.set_param('name', "encrypted.asc")
|
||||||
submsg2.set_param('OpenPGP encrypted message', "", 'Content-Description' )
|
encrypted_part.set_param('OpenPGP encrypted message', "", 'Content-Description' )
|
||||||
submsg2.set_param('inline', "", 'Content-Disposition' )
|
encrypted_part.set_param('inline', "", 'Content-Disposition' )
|
||||||
submsg2.set_param('filename', "encrypted.asc", 'Content-Disposition' )
|
encrypted_part.set_param('filename', "encrypted.asc", 'Content-Disposition' )
|
||||||
|
|
||||||
if isinstance(message.get_payload(), str):
|
if isinstance(message.get_payload(), str):
|
||||||
# WTF! It seems to swallow the first line. Not sure why. Perhaps
|
# WTF! It seems to swallow the first line. Not sure why. Perhaps
|
||||||
|
@ -195,13 +195,16 @@ def encrypt_all_payloads_mime( message, gpg_to_cmdline ):
|
||||||
# Workaround it here by prepending a blank line.
|
# Workaround it here by prepending a blank line.
|
||||||
# This happens only on text only messages.
|
# This happens only on text only messages.
|
||||||
additionalSubHeader=""
|
additionalSubHeader=""
|
||||||
|
encoding = sys.getdefaultencoding()
|
||||||
if 'Content-Type' in message and not message['Content-Type'].startswith('multipart'):
|
if 'Content-Type' in message and not message['Content-Type'].startswith('multipart'):
|
||||||
additionalSubHeader="Content-Type: "+message['Content-Type']+"\n"
|
additionalSubHeader="Content-Type: "+message['Content-Type']+"\n"
|
||||||
submsg2.set_payload(additionalSubHeader+"\n" +message.get_payload(decode=True))
|
(base, encoding) = parse_content_type(message['Content-Type'])
|
||||||
|
LOG.debug(f"Identified encoding as {encoding}")
|
||||||
|
encrypted_part.set_payload(additionalSubHeader+"\n" +message.get_payload(decode=True).decode(encoding))
|
||||||
check_nested = True
|
check_nested = True
|
||||||
else:
|
else:
|
||||||
processed_payloads = generate_message_from_payloads(message)
|
processed_payloads = generate_message_from_payloads(message)
|
||||||
submsg2.set_payload(processed_payloads.as_string())
|
encrypted_part.set_payload(processed_payloads.as_string())
|
||||||
check_nested = False
|
check_nested = False
|
||||||
|
|
||||||
message.preamble = "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)"
|
message.preamble = "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)"
|
||||||
|
@ -217,7 +220,15 @@ def encrypt_all_payloads_mime( message, gpg_to_cmdline ):
|
||||||
else:
|
else:
|
||||||
message['Content-Type'] = "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary
|
message['Content-Type'] = "multipart/encrypted; protocol=\"application/pgp-encrypted\";\nboundary=\"%s\"\n" % boundary
|
||||||
|
|
||||||
return [ submsg1, encrypt_payload(submsg2, gpg_to_cmdline, check_nested) ]
|
return [ pgp_ver_part, encrypt_payload(encrypted_part, gpg_to_cmdline, check_nested) ]
|
||||||
|
|
||||||
|
def parse_content_type(content_type):
|
||||||
|
split_at = content_type.index(';')
|
||||||
|
second_part = content_type[split_at+1 : ].strip()
|
||||||
|
if second_part.startswith('charset'):
|
||||||
|
return (content_type[0 : split_at], second_part[second_part.index('=') + 1 : ].strip())
|
||||||
|
else:
|
||||||
|
return (content_type[0 : split_at], sys.getdefaultencoding())
|
||||||
|
|
||||||
def encrypt_payload( payload, gpg_to_cmdline, check_nested = True ):
|
def encrypt_payload( payload, gpg_to_cmdline, check_nested = True ):
|
||||||
global LOG
|
global LOG
|
||||||
|
@ -297,11 +308,11 @@ def smime_encrypt( raw_message, recipients ):
|
||||||
|
|
||||||
s.write(out, p7)
|
s.write(out, p7)
|
||||||
|
|
||||||
LOG.debug("Sending message from " + from_addr + " to " + str(smime_to))
|
LOG.debug(f"Sending message from {from_addr} to {smime_to}")
|
||||||
|
|
||||||
send_msg(out.read(), smime_to)
|
send_msg(out.read(), smime_to)
|
||||||
if unsmime_to:
|
if unsmime_to:
|
||||||
LOG.debug("Unable to find valid S/MIME certificates for " + str(unsmime_to))
|
LOG.debug(f"Unable to find valid S/MIME certificates for {unsmime_to}")
|
||||||
|
|
||||||
return unsmime_to
|
return unsmime_to
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ certs: test/certs
|
||||||
|
|
||||||
[tests]
|
[tests]
|
||||||
# Number of "test-*" sections in this file, describing test cases.
|
# Number of "test-*" sections in this file, describing test cases.
|
||||||
cases: 6
|
cases: 7
|
||||||
e2e_log: test/logs/e2e.log
|
e2e_log: test/logs/e2e.log
|
||||||
e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s
|
e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s
|
||||||
e2e_log_datefmt: %Y-%m-%d %H:%M:%S
|
e2e_log_datefmt: %Y-%m-%d %H:%M:%S
|
||||||
|
@ -72,3 +72,9 @@ descr: Multipart encrypted message to a user with an Ed25519 key.
|
||||||
to: bob@disposlab
|
to: bob@disposlab
|
||||||
in: test/msgin/multipart2rsa.msg
|
in: test/msgin/multipart2rsa.msg
|
||||||
out: -----BEGIN PGP MESSAGE-----
|
out: -----BEGIN PGP MESSAGE-----
|
||||||
|
|
||||||
|
[case-7]
|
||||||
|
descr: Clear text message to a user with an RSA key and PGP/MIME enabled in configuration
|
||||||
|
to: evan@disposlab
|
||||||
|
in: test/msgin/clear2rsa2.msg
|
||||||
|
out: -----BEGIN PGP MESSAGE-----
|
||||||
|
|
|
@ -51,6 +51,12 @@ def build_config(config):
|
||||||
cp.add_section("enc_keymap")
|
cp.add_section("enc_keymap")
|
||||||
cp.set("enc_keymap", "alice@disposlab", "1CD245308F0963D038E88357973CF4D9387C44D7")
|
cp.set("enc_keymap", "alice@disposlab", "1CD245308F0963D038E88357973CF4D9387C44D7")
|
||||||
cp.set("enc_keymap", "bob@disposlab", "19CF4B47ECC9C47AFA84D4BD96F39FDA0E31BB67")
|
cp.set("enc_keymap", "bob@disposlab", "19CF4B47ECC9C47AFA84D4BD96F39FDA0E31BB67")
|
||||||
|
cp.set("enc_keymap", "evan@disposlab", "530B1BB2D0CC7971648198BBA4774E507D3AF5BC")
|
||||||
|
|
||||||
|
cp.add_section("pgp_style")
|
||||||
|
# Default style is PGP/Inline, so to cover more branches, one test identity
|
||||||
|
# uses PGP/MIME.
|
||||||
|
cp.set("pgp_style", "evan@disposlab", "mime")
|
||||||
|
|
||||||
logging.debug(f"Created config with keyhome={config['gpg_keyhome']}, cert_path={config['smime_certpath']} and relay at port {config['port']}")
|
logging.debug(f"Created config with keyhome={config['gpg_keyhome']}, cert_path={config['smime_certpath']} and relay at port {config['port']}")
|
||||||
return cp
|
return cp
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
||||||
|
From: Dave <dave@disposlab
|
||||||
|
To: Evan <evan@disposlab>
|
||||||
|
Subject: Test
|
||||||
|
Content-Type: text/plain; charset="utf-8"
|
||||||
|
|
||||||
|
Body of the message.
|
Loading…
Reference in New Issue