Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Strengthen Encryption] PySAML2 Encrypted Assertions work with Shibboleth SP 3 #754

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/saml2/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
from saml2.sigver import SigverError
from saml2.sigver import SignatureError
from saml2.sigver import make_temp
from saml2.sigver import get_pem_wrapped_unwrapped
from saml2.sigver import pre_encryption_part
from saml2.sigver import pre_signature_part
from saml2.sigver import pre_encrypt_assertion
Expand Down Expand Up @@ -650,18 +651,21 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=No
_certs = self.metadata.certs(sp_entity_id, "any", "encryption")
exception = None
for _cert in _certs:
wrapped_cert, unwrapped_cert = get_pem_wrapped_unwrapped(_cert)
try:
begin_cert = "-----BEGIN CERTIFICATE-----\n"
end_cert = "\n-----END CERTIFICATE-----\n"
if begin_cert not in _cert:
_cert = "%s%s" % (begin_cert, _cert)
if end_cert not in _cert:
_cert = "%s%s" % (_cert, end_cert)
tmp = make_temp(_cert.encode('ascii'),
tmp = make_temp(wrapped_cert.encode('ascii'),
decode=False,
delete_tmpfiles=self.config.delete_tmpfiles)

# it would be possibile to handle many other args here ...
pre_enc_part_dict = dict()
if encrypt_cert:
pre_enc_part_dict['encrypt_cert'] = unwrapped_cert
pre_enc_part = pre_encryption_part(**pre_enc_part_dict)
# end pre_enc_part

response = self.sec.encrypt_assertion(response, tmp.name,
pre_encryption_part(),
pre_enc_part,
node_xpath=node_xpath)
return response
except Exception as ex:
Expand Down
39 changes: 27 additions & 12 deletions src/saml2/sigver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import itertools
import logging
import os
import re
import six
from uuid import uuid4 as gen_random_key

Expand Down Expand Up @@ -61,9 +62,8 @@

SIG = '{{{ns}#}}{attribute}'.format(ns=ds.NAMESPACE, attribute='Signature')

RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'
TRIPLE_DES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'

TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'
RSA_OAEP_MGF1P = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"

class SigverError(SAMLError):
pass
Expand Down Expand Up @@ -102,6 +102,14 @@ class CertificateError(SigverError):
pass


def get_pem_wrapped_unwrapped(cert):
begin_cert = "-----BEGIN CERTIFICATE-----\n"
end_cert = "\n-----END CERTIFICATE-----\n"
unwrapped_cert = re.sub(f'{begin_cert}|{end_cert}', '', cert)
wrapped_cert = f'{begin_cert}{unwrapped_cert}{end_cert}'
return wrapped_cert, unwrapped_cert


def read_file(*args, **kwargs):
with open(*args, **kwargs) as handler:
return handler.read()
Expand Down Expand Up @@ -752,7 +760,7 @@ def encrypt_assertion(self, statement, enc_key, template, key_type='des-192', no
:param key_type: The type of session key to use.
:return: The encrypted text
"""

if isinstance(statement, SamlBase):
statement = pre_encrypt_assertion(statement)

Expand Down Expand Up @@ -1086,10 +1094,8 @@ def encrypt_cert_from_item(item):
pass

if _encrypt_cert is not None:
if _encrypt_cert.find('-----BEGIN CERTIFICATE-----\n') == -1:
_encrypt_cert = '-----BEGIN CERTIFICATE-----\n' + _encrypt_cert
if _encrypt_cert.find('\n-----END CERTIFICATE-----') == -1:
_encrypt_cert = _encrypt_cert + '\n-----END CERTIFICATE-----'
wrapped_cert, unwrapped_cert = get_pem_wrapped_unwrapped(_encrypt_cert)
_encrypt_cert = wrapped_cert
return _encrypt_cert


Expand Down Expand Up @@ -1291,7 +1297,7 @@ def __init__(

self.metadata = metadata
self.only_use_keys_in_metadata = only_use_keys_in_metadata

if not template:
this_dir, this_filename = os.path.split(__file__)
self.template = os.path.join(this_dir, 'xml_template', 'template.xml')
Expand Down Expand Up @@ -1849,8 +1855,10 @@ def pre_signature_part(
# </EncryptedData>


def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_1_5, key_name='my-rsa-key',
encrypted_key_id=None, encrypted_data_id=None):
def pre_encryption_part(msg_enc=TRIPLEDES_CBC, key_enc=RSA_OAEP_MGF1P,
key_name='my-rsa-key',
encrypted_key_id=None, encrypted_data_id=None,
encrypt_cert=None):
"""

:param msg_enc:
Expand All @@ -1862,10 +1870,17 @@ def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_1_5, key_name='my-rs
ed_id = encrypted_data_id or "ED_{id}".format(id=gen_random_key())
msg_encryption_method = EncryptionMethod(algorithm=msg_enc)
key_encryption_method = EncryptionMethod(algorithm=key_enc)

enc_key_dict= dict(key_name=ds.KeyName(text=key_name))

enc_key_dict['x509_data'] = ds.X509Data(
x509_certificate=ds.X509Certificate(text=encrypt_cert))
key_info = ds.KeyInfo(**enc_key_dict)

encrypted_key = EncryptedKey(
id=ek_id,
encryption_method=key_encryption_method,
key_info=ds.KeyInfo(key_name=ds.KeyName(text=key_name)),
key_info=key_info,
cipher_data=CipherData(cipher_value=CipherValue(text='')),
)
key_info = ds.KeyInfo(encrypted_key=encrypted_key)
Expand Down
6 changes: 2 additions & 4 deletions src/saml2/xml_template/template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
<EncryptedData
xmlns="http://www.w3.org/2001/04/xmlenc#"
Type="http://www.w3.org/2001/04/xmlenc#Element">
<EncryptionMethod Algorithm=
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm=
"http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName/>
</KeyInfo>
Expand Down
2 changes: 1 addition & 1 deletion tests/test_42_enc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

__author__ = 'roland'

TMPL_NO_HEADER = """<ns0:EncryptedData xmlns:ns0="http://www.w3.org/2001/04/xmlenc#" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" Id="{ed_id}" Type="http://www.w3.org/2001/04/xmlenc#Element"><ns0:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /><ns1:KeyInfo><ns0:EncryptedKey Id="{ek_id}"><ns0:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /><ns1:KeyInfo><ns1:KeyName>my-rsa-key</ns1:KeyName></ns1:KeyInfo><ns0:CipherData><ns0:CipherValue /></ns0:CipherData></ns0:EncryptedKey></ns1:KeyInfo><ns0:CipherData><ns0:CipherValue /></ns0:CipherData></ns0:EncryptedData>"""
TMPL_NO_HEADER = """<ns0:EncryptedData xmlns:ns0="http://www.w3.org/2001/04/xmlenc#" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" Id="{ed_id}" Type="http://www.w3.org/2001/04/xmlenc#Element"><ns0:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /><ns1:KeyInfo><ns0:EncryptedKey Id="{ek_id}"><ns0:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" /><ns1:KeyInfo><ns1:KeyName>my-rsa-key</ns1:KeyName><ns1:X509Data><ns1:X509Certificate /></ns1:X509Data></ns1:KeyInfo><ns0:CipherData><ns0:CipherValue /></ns0:CipherData></ns0:EncryptedKey></ns1:KeyInfo><ns0:CipherData><ns0:CipherValue /></ns0:CipherData></ns0:EncryptedData>"""
TMPL = "<?xml version='1.0' encoding='UTF-8'?>\n%s" % TMPL_NO_HEADER

IDENTITY = {"eduPersonAffiliation": ["staff", "member"],
Expand Down