From a23ed34e395b5f7f71e8226c7ad2075736a892c4 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Sun, 13 Dec 2020 18:42:15 +0100 Subject: [PATCH 1/5] Fixed: "ERROR Shibboleth.SSO.SAML2 [6] [default]: failed to decrypt assertion: Unable to resolve any key decryption keys." --- src/saml2/entity.py | 6 +++++- src/saml2/sigver.py | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/saml2/entity.py b/src/saml2/entity.py index 71e9ecfbf..3311e6a21 100644 --- a/src/saml2/entity.py +++ b/src/saml2/entity.py @@ -660,8 +660,12 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=No tmp = make_temp(_cert.encode('ascii'), decode=False, delete_tmpfiles=self.config.delete_tmpfiles) + + # it would be possibile to handle many other args here ... + pre_enc_part = pre_encryption_part(encrypt_cert=encrypt_cert) + response = self.sec.encrypt_assertion(response, tmp.name, - pre_encryption_part(), + pre_enc_part, node_xpath=node_xpath) return response except Exception as ex: diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index 52324eb40..0ea7b66da 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -1850,7 +1850,8 @@ def pre_signature_part( 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): + encrypted_key_id=None, encrypted_data_id=None, + encrypt_cert=None): """ :param msg_enc: @@ -1865,7 +1866,10 @@ def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_1_5, key_name='my-rs encrypted_key = EncryptedKey( id=ek_id, encryption_method=key_encryption_method, - key_info=ds.KeyInfo(key_name=ds.KeyName(text=key_name)), + key_info=ds.KeyInfo(key_name=ds.KeyName(text=key_name), + x509_data=ds.X509Data( + x509_certificate=ds.X509Certificate(text=encrypt_cert) + )), cipher_data=CipherData(cipher_value=CipherValue(text='')), ) key_info = ds.KeyInfo(encrypted_key=encrypted_key) From 0a1413490998ffe8f9e119fda582013d819ad531 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Sun, 13 Dec 2020 18:50:45 +0100 Subject: [PATCH 2/5] Fixed: "WARN XMLTooling.Decrypter [7] [default]: XMLSecurity exception while decrypting key: XSECAlgorithmMapper::mapURIToHandler - URI http://www.w3.org/2001/04/xmlenc#rsa-1_5 disallowed by whitelist/blacklist policy" --- src/saml2/sigver.py | 7 +++++-- src/saml2/xml_template/template.xml | 6 ++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index 0ea7b66da..e65cb2c80 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -61,9 +61,11 @@ SIG = '{{{ns}#}}{attribute}'.format(ns=ds.NAMESPACE, attribute='Signature') +# deprecated 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' +TRIPLE_DES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' +RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" class SigverError(SAMLError): pass @@ -1849,7 +1851,8 @@ def pre_signature_part( # -def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_1_5, key_name='my-rsa-key', +def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_OAEP, + key_name='my-rsa-key', encrypted_key_id=None, encrypted_data_id=None, encrypt_cert=None): """ diff --git a/src/saml2/xml_template/template.xml b/src/saml2/xml_template/template.xml index 0b962e55b..d581485ec 100644 --- a/src/saml2/xml_template/template.xml +++ b/src/saml2/xml_template/template.xml @@ -2,12 +2,10 @@ - + - + From 35752d02a76d961f7b83979e991e858f79908859 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Sun, 13 Dec 2020 18:59:06 +0100 Subject: [PATCH 3/5] Fixed test 42 --- tests/test_42_enc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_42_enc.py b/tests/test_42_enc.py index 97bdf8ea6..c6ede49dd 100644 --- a/tests/test_42_enc.py +++ b/tests/test_42_enc.py @@ -12,7 +12,7 @@ __author__ = 'roland' -TMPL_NO_HEADER = """my-rsa-key""" +TMPL_NO_HEADER = """my-rsa-key""" TMPL = "\n%s" % TMPL_NO_HEADER IDENTITY = {"eduPersonAffiliation": ["staff", "member"], From 867c8dbfe4093e0f812b3f88449eb1ed3893e66b Mon Sep 17 00:00:00 2001 From: peppelinux Date: Mon, 14 Dec 2020 13:29:17 +0100 Subject: [PATCH 4/5] Tests Fixed a regexp generalization for wrapped and unwrapped PEM certs (BEGIN/END) --- src/saml2/entity.py | 18 ++++++++++-------- src/saml2/sigver.py | 18 +++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/saml2/entity.py b/src/saml2/entity.py index 3311e6a21..3b1b58297 100644 --- a/src/saml2/entity.py +++ b/src/saml2/entity.py @@ -1,6 +1,7 @@ import base64 import copy import logging +import re import requests import six @@ -650,19 +651,20 @@ 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: + 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}' 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 = pre_encryption_part(encrypt_cert=encrypt_cert) + 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) response = self.sec.encrypt_assertion(response, tmp.name, pre_enc_part, diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index e65cb2c80..5563627ba 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -62,7 +62,7 @@ SIG = '{{{ns}#}}{attribute}'.format(ns=ds.NAMESPACE, attribute='Signature') # deprecated -RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5' +# 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' RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" @@ -754,7 +754,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) @@ -1293,7 +1293,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') @@ -1866,13 +1866,17 @@ def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_OAEP, 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), - x509_data=ds.X509Data( - x509_certificate=ds.X509Certificate(text=encrypt_cert) - )), + key_info=key_info, cipher_data=CipherData(cipher_value=CipherValue(text='')), ) key_info = ds.KeyInfo(encrypted_key=encrypted_key) From daf2142b6fdb2a0bed7da585d7717fdfdd47293e Mon Sep 17 00:00:00 2001 From: peppelinux Date: Mon, 14 Dec 2020 14:56:51 +0100 Subject: [PATCH 5/5] Better generalization for PEM certs --- src/saml2/entity.py | 8 +++----- src/saml2/sigver.py | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/saml2/entity.py b/src/saml2/entity.py index 3b1b58297..12d882f20 100644 --- a/src/saml2/entity.py +++ b/src/saml2/entity.py @@ -1,7 +1,6 @@ import base64 import copy import logging -import re import requests import six @@ -66,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 @@ -651,10 +651,7 @@ 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: - 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}' + wrapped_cert, unwrapped_cert = get_pem_wrapped_unwrapped(_cert) try: tmp = make_temp(wrapped_cert.encode('ascii'), decode=False, @@ -665,6 +662,7 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=No 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_enc_part, diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index 5563627ba..9744bd2cc 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -8,6 +8,7 @@ import itertools import logging import os +import re import six from uuid import uuid4 as gen_random_key @@ -61,11 +62,8 @@ SIG = '{{{ns}#}}{attribute}'.format(ns=ds.NAMESPACE, attribute='Signature') -# deprecated -# 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' -RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" +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 @@ -104,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() @@ -1088,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 @@ -1851,7 +1855,7 @@ def pre_signature_part( # -def pre_encryption_part(msg_enc=TRIPLE_DES_CBC, key_enc=RSA_OAEP, +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):