6060from saml2.samlp import SessionIndex
6161from saml2.samlp import artifact_resolve_from_string
6262from saml2.samlp import response_from_string
63- from saml2.sigver import SignatureError
63+ from saml2.sigver import SignatureError, XMLSEC_SESSION_KEY_URI_TO_ALG
6464from saml2.sigver import SigverError
6565from saml2.sigver import get_pem_wrapped_unwrapped
6666from saml2.sigver import make_temp
7878from saml2.xmldsig import SIG_ALLOWED_ALG
7979from saml2.xmldsig import DefaultSignature
8080
81-
8281logger = logging.getLogger(__name__)
8382
8483__author__ = "rolandh"
@@ -181,6 +180,9 @@ def __init__(self, entity_type, config=None, config_file="", virtual_organizatio
181180
182181 self.sec = security_context(self.config)
183182
183+ self.encrypt_assertion_session_key_algs = self.config.encrypt_assertion_session_key_algs
184+ self.encrypt_assertion_cert_key_algs = self.config.encrypt_assertion_cert_key_algs
185+
184186 if virtual_organization:
185187 if isinstance(virtual_organization, str):
186188 self.vorg = self.config.vorg[virtual_organization]
@@ -644,34 +646,97 @@ def has_encrypt_cert_in_metadata(self, sp_entity_id):
644646 return True
645647 return False
646648
647- def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=None):
649+ def _encrypt_assertion(
650+ self,
651+ encrypt_cert,
652+ sp_entity_id,
653+ response,
654+ node_xpath=None,
655+ encrypt_cert_session_key_alg=None,
656+ encrypt_cert_cert_key_alg=None,
657+ ):
648658 """Encryption of assertions.
649659
650660 :param encrypt_cert: Certificate to be used for encryption.
651661 :param sp_entity_id: Entity ID for the calling service provider.
652662 :param response: A samlp.Response
663+ :param encrypt_cert_cert_key_alg: algorithm used for encrypting session key
664+ :param encrypt_cert_session_key_alg: algorithm used for encrypting assertion
665+ :param encrypt_cert_cert_key_alg:
653666 :param node_xpath: Unquie path to the element to be encrypted.
654667 :return: A new samlp.Resonse with the designated assertion encrypted.
655668 """
656669 _certs = []
657670
658671 if encrypt_cert:
659- _certs.append((None, encrypt_cert))
672+ _certs.append((None, encrypt_cert, None, None ))
660673 elif sp_entity_id is not None:
661- _certs = self.metadata.certs(sp_entity_id, "any", "encryption")
674+ _certs = self.metadata.certs(sp_entity_id, "any", "encryption", get_with_usage_and_encryption_methods=True )
662675 exception = None
663- for _cert_name, _cert in _certs:
676+
677+ # take certs with encryption and encryption_methods first (priority 1)
678+ sorted_certs = []
679+ for _unpacked_cert in _certs:
680+ _cert_name, _cert, _cert_use, _cert_encryption_methods = _unpacked_cert
681+ if _cert_use == "encryption" and _cert_encryption_methods:
682+ sorted_certs.append(_unpacked_cert)
683+
684+ # take certs with encryption or encryption_methods (priority 2)
685+ for _unpacked_cert in _certs:
686+ _cert_name, _cert, _cert_use, _cert_encryption_methods = _unpacked_cert
687+ if _cert_use == "encryption" and _unpacked_cert not in sorted_certs:
688+ sorted_certs.append(_unpacked_cert)
689+
690+ for _unpacked_cert in _certs:
691+ if _unpacked_cert not in sorted_certs:
692+ sorted_certs.append(_unpacked_cert)
693+
694+ for _cert_name, _cert, _cert_use, _cert_encryption_methods in sorted_certs:
664695 wrapped_cert, unwrapped_cert = get_pem_wrapped_unwrapped(_cert)
665696 try:
666697 tmp = make_temp(
667698 wrapped_cert.encode("ascii"),
668699 decode=False,
669700 delete_tmpfiles=self.config.delete_tmpfiles,
670701 )
702+
703+ msg_enc = (
704+ encrypt_cert_session_key_alg
705+ if encrypt_cert_session_key_alg
706+ else self.encrypt_assertion_session_key_algs[0]
707+ )
708+ key_enc = (
709+ encrypt_cert_cert_key_alg if encrypt_cert_cert_key_alg else self.encrypt_assertion_cert_key_algs[0]
710+ )
711+
712+ if encrypt_cert != _cert and _cert_encryption_methods:
713+ viable_session_key_algs = []
714+ for alg in self.encrypt_assertion_session_key_algs:
715+ for cert_method in _cert_encryption_methods:
716+ if cert_method.get("algorithm") == alg:
717+ viable_session_key_algs.append(alg)
718+
719+ viable_cert_algs = []
720+ for alg in self.encrypt_assertion_cert_key_algs:
721+ for cert_method in _cert_encryption_methods:
722+ if cert_method.get("algorithm") == alg:
723+ viable_cert_algs.append(alg)
724+
725+ if viable_session_key_algs:
726+ msg_enc = viable_session_key_algs[0]
727+
728+ if viable_cert_algs:
729+ key_enc = viable_cert_algs[0]
730+
731+ key_type = XMLSEC_SESSION_KEY_URI_TO_ALG.get(msg_enc)
732+
671733 response = self.sec.encrypt_assertion(
672734 response,
673735 tmp.name,
674- pre_encryption_part(key_name=_cert_name, encrypt_cert=unwrapped_cert),
736+ pre_encryption_part(
737+ key_name=_cert_name, encrypt_cert=unwrapped_cert, msg_enc=msg_enc, key_enc=key_enc
738+ ),
739+ key_type=key_type,
675740 node_xpath=node_xpath,
676741 )
677742 return response
@@ -697,7 +762,11 @@ def _response(
697762 encrypt_assertion_self_contained=False,
698763 encrypted_advice_attributes=False,
699764 encrypt_cert_advice=None,
765+ encrypt_cert_advice_cert_key_alg=None,
766+ encrypt_cert_advice_session_key_alg=None,
700767 encrypt_cert_assertion=None,
768+ encrypt_cert_assertion_cert_key_alg=None,
769+ encrypt_cert_assertion_session_key_alg=None,
701770 sign_assertion=None,
702771 pefim=False,
703772 sign_alg=None,
@@ -731,8 +800,16 @@ def _response(
731800 element should be encrypted.
732801 :param encrypt_cert_advice: Certificate to be used for encryption of
733802 assertions in the advice element.
803+ :param encrypt_cert_advice_cert_key_alg: algorithm used for encrypting session key
804+ by encrypt_cert_advice
805+ :param encrypt_cert_advice_session_key_alg: algorithm used for encrypting assertion
806+ when using encrypt_cert_advice
734807 :param encrypt_cert_assertion: Certificate to be used for encryption
735808 of assertions.
809+ :param encrypt_cert_assertion_cert_key_alg: algorithm used for encrypting session key
810+ by encrypt_cert_assertion
811+ :param encrypt_cert_assertion_session_key_alg: algorithm used for encrypting assertion when
812+ using encrypt_cert_assertion
736813 :param sign_assertion: True if assertions should be signed.
737814 :param pefim: True if a response according to the PEFIM profile
738815 should be created.
@@ -856,6 +933,8 @@ def _response(
856933 sp_entity_id,
857934 response,
858935 node_xpath=node_xpath,
936+ encrypt_cert_session_key_alg=encrypt_cert_advice_session_key_alg,
937+ encrypt_cert_cert_key_alg=encrypt_cert_advice_cert_key_alg,
859938 )
860939 response = response_from_string(response)
861940
@@ -900,7 +979,13 @@ def _response(
900979 response = signed_instance_factory(response, self.sec, to_sign_assertion)
901980
902981 # XXX encrypt assertion
903- response = self._encrypt_assertion(encrypt_cert_assertion, sp_entity_id, response)
982+ response = self._encrypt_assertion(
983+ encrypt_cert_assertion,
984+ sp_entity_id,
985+ response,
986+ encrypt_cert_session_key_alg=encrypt_cert_assertion_session_key_alg,
987+ encrypt_cert_cert_key_alg=encrypt_cert_assertion_cert_key_alg,
988+ )
904989 else:
905990 # XXX sign other parts! (defiend by to_sign)
906991 if to_sign:
@@ -1357,7 +1442,6 @@ def create_manage_name_id_response(
13571442 digest_alg=None,
13581443 **kwargs,
13591444 ):
1360-
13611445 rinfo = self.response_args(request, bindings)
13621446
13631447 response = self._status_response(
0 commit comments