From c830b1d435179dcc2aa57d6a76d816ef75b84ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Pavl=C3=AD=C4=8Dek?= <469355@mail.muni.cz> Date: Mon, 17 Jul 2023 21:33:19 +0200 Subject: [PATCH] feat: configurable encryption algorithm types --- docs/howto/config.rst | 54 +++++++++++++++++ src/saml2/config.py | 6 ++ src/saml2/entity.py | 112 +++++++++++++++++++++++++++++++---- src/saml2/md.py | 3 +- src/saml2/mdstore.py | 9 ++- src/saml2/server.py | 34 ++++++++++- src/saml2/sigver.py | 32 ++++++---- src/saml2/xmlenc/__init__.py | 42 ++++++++----- 8 files changed, 252 insertions(+), 40 deletions(-) diff --git a/docs/howto/config.rst b/docs/howto/config.rst index c224cb2a1..c5dbefa37 100644 --- a/docs/howto/config.rst +++ b/docs/howto/config.rst @@ -656,6 +656,60 @@ Example:: "verify_encrypt_cert_assertion": verify_encrypt_cert +encrypt_assertion_session_key_algs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +List of block encryption algorithms which can be used to encrypt assertion. +Values order is from highest to lowest priority. Default value is ["http://www.w3.org/2001/04/xmlenc#tripledes-cbc"] + +Valid values are: + - "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + - "http://www.w3.org/2001/04/xmlenc#aes128-cbc" + - "http://www.w3.org/2001/04/xmlenc#aes192-cbc" + - "http://www.w3.org/2001/04/xmlenc#aes256-cbc" + - "http://www.w3.org/2009/xmlenc11#aes128-gcm" + - "http://www.w3.org/2009/xmlenc11#aes192-gcm" + - "http://www.w3.org/2009/xmlenc11#aes256-gcm" + +Example:: + + "encrypt_assertion_session_key_algs" : [ + "http://www.w3.org/2009/xmlenc11#aes256-gcm", + "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" + ] + +encrypt_assertion_cert_key_algs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +List of key transport algorithms which can be used to encrypt session key used to encrypting assertion. +Values order is from highest to lowest priority. Default value is ["http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"]. + +Valid values are: + - "http://www.w3.org/2001/04/xmlenc#rsa-1_5" + - "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" + - "http://www.w3.org/2009/xmlenc11#rsa-oaep" (only supported with xmlsec1 version>=1.3.0) + +Example:: + + "encrypt_assertion_cert_key_algs": [ + "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", + "http://www.w3.org/2001/04/xmlenc#rsa-1_5" + ] + +default_rsa_oaep_mgf_alg +^^^^^^^^^^^^^^^^^^^^^^^^ +If encryption key from metadata has no encryption method specified or does not have one matching configuration and +"http://www.w3.org/2009/xmlenc11#rsa-oaep" is selected, it will be used with mask generation function specified by +this configuration option. Default value is None + +Valid values are: + - "http://www.w3.org/2009/xmlenc11#mgf1sha1" + - "http://www.w3.org/2009/xmlenc11#mgf1sha224" + - "http://www.w3.org/2009/xmlenc11#mgf1sha256" + - "http://www.w3.org/2009/xmlenc11#mgf1sha384" + - "http://www.w3.org/2009/xmlenc11#mgf1sha512" + +Example:: + + "default_rsa_oaep_mgf_alg": "http://www.w3.org/2009/xmlenc11#mgf1sha1" Specific directives ------------------- diff --git a/src/saml2/config.py b/src/saml2/config.py index dcf8fd75c..8002a8a28 100644 --- a/src/saml2/config.py +++ b/src/saml2/config.py @@ -76,6 +76,9 @@ "signing_algorithm", "digest_algorithm", "http_client_timeout", + "encrypt_assertion_session_key_algs", + "encrypt_assertion_cert_key_algs", + "default_rsa_oaep_mgf_alg", ] SP_ARGS = [ @@ -229,6 +232,9 @@ def __init__(self, homedir="."): self.signing_algorithm = None self.digest_algorithm = None self.http_client_timeout = None + self.encrypt_assertion_session_key_algs = ["http://www.w3.org/2001/04/xmlenc#tripledes-cbc"] + self.encrypt_assertion_cert_key_algs = ["http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"] + self.default_rsa_oaep_mgf_alg = None def setattr(self, context, attr, val): if context == "": diff --git a/src/saml2/entity.py b/src/saml2/entity.py index 1e36e651b..52a2f5fa8 100644 --- a/src/saml2/entity.py +++ b/src/saml2/entity.py @@ -60,7 +60,7 @@ from saml2.samlp import SessionIndex from saml2.samlp import artifact_resolve_from_string from saml2.samlp import response_from_string -from saml2.sigver import SignatureError +from saml2.sigver import SignatureError, XMLSEC_SESSION_KEY_URI_TO_ALG, RSA_OAEP from saml2.sigver import SigverError from saml2.sigver import get_pem_wrapped_unwrapped from saml2.sigver import make_temp @@ -78,7 +78,6 @@ from saml2.xmldsig import SIG_ALLOWED_ALG from saml2.xmldsig import DefaultSignature - logger = logging.getLogger(__name__) __author__ = "rolandh" @@ -181,6 +180,10 @@ def __init__(self, entity_type, config=None, config_file="", virtual_organizatio self.sec = security_context(self.config) + self.encrypt_assertion_session_key_algs = self.config.encrypt_assertion_session_key_algs + self.encrypt_assertion_cert_key_algs = self.config.encrypt_assertion_cert_key_algs + self.default_rsa_oaep_mgf_alg = self.config.default_rsa_oaep_mgf_alg + if virtual_organization: if isinstance(virtual_organization, str): self.vorg = self.config.vorg[virtual_organization] @@ -194,7 +197,6 @@ def __init__(self, entity_type, config=None, config_file="", virtual_organizatio self.sourceid = self.metadata.construct_source_id() else: self.sourceid = {} - self.msg_cb = msg_cb def reload_metadata(self, metadata_conf): @@ -644,23 +646,59 @@ def has_encrypt_cert_in_metadata(self, sp_entity_id): return True return False - def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=None): + def _get_first_matching_alg(self, priority_list, metadata_list): + for alg in priority_list: + for cert_method in metadata_list: + if cert_method.get("algorithm") == alg: + return cert_method + return None + + def _encrypt_assertion( + self, + encrypt_cert, + sp_entity_id, + response, + node_xpath=None, + encrypt_cert_session_key_alg=None, + encrypt_cert_cert_key_alg=None, + ): """Encryption of assertions. :param encrypt_cert: Certificate to be used for encryption. :param sp_entity_id: Entity ID for the calling service provider. :param response: A samlp.Response + :param encrypt_cert_cert_key_alg: algorithm used for encrypting session key + :param encrypt_cert_session_key_alg: algorithm used for encrypting assertion + :param encrypt_cert_cert_key_alg: :param node_xpath: Unquie path to the element to be encrypted. :return: A new samlp.Resonse with the designated assertion encrypted. """ _certs = [] if encrypt_cert: - _certs.append((None, encrypt_cert)) + _certs.append((None, encrypt_cert, None, None)) elif sp_entity_id is not None: - _certs = self.metadata.certs(sp_entity_id, "any", "encryption") + _certs = self.metadata.certs(sp_entity_id, "any", "encryption", get_with_usage_and_encryption_methods=True) exception = None - for _cert_name, _cert in _certs: + + # take certs with encryption and encryption_methods first (priority 1) + sorted_certs = [] + for _unpacked_cert in _certs: + _cert_name, _cert, _cert_use, _cert_encryption_methods = _unpacked_cert + if _cert_use == "encryption" and _cert_encryption_methods: + sorted_certs.append(_unpacked_cert) + + # take certs with encryption or encryption_methods (priority 2) + for _unpacked_cert in _certs: + _cert_name, _cert, _cert_use, _cert_encryption_methods = _unpacked_cert + if _cert_use == "encryption" and _unpacked_cert not in sorted_certs: + sorted_certs.append(_unpacked_cert) + + for _unpacked_cert in _certs: + if _unpacked_cert not in sorted_certs: + sorted_certs.append(_unpacked_cert) + + for _cert_name, _cert, _cert_use, _cert_encryption_methods in sorted_certs: wrapped_cert, unwrapped_cert = get_pem_wrapped_unwrapped(_cert) try: tmp = make_temp( @@ -668,10 +706,45 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=No decode=False, delete_tmpfiles=self.config.delete_tmpfiles, ) + + msg_enc = ( + encrypt_cert_session_key_alg + if encrypt_cert_session_key_alg + else self.encrypt_assertion_session_key_algs[0] + ) + key_enc = ( + encrypt_cert_cert_key_alg if encrypt_cert_cert_key_alg else self.encrypt_assertion_cert_key_algs[0] + ) + + rsa_oaep_mgf_alg = self.default_rsa_oaep_mgf_alg if key_enc == RSA_OAEP else None + if encrypt_cert != _cert and _cert_encryption_methods: + viable_session_key_alg = self._get_first_matching_alg( + self.encrypt_assertion_session_key_algs, _cert_encryption_methods + ) + if viable_session_key_alg: + msg_enc = viable_session_key_alg.get("algorithm") + + viable_cert_alg = self._get_first_matching_alg( + self.encrypt_assertion_cert_key_algs, _cert_encryption_methods + ) + if viable_cert_alg: + key_enc = viable_cert_alg.get("algorithm") + mgf = viable_cert_alg.get("mgf") + rsa_oaep_mgf_alg = mgf.get("algorithm") if mgf else None + + key_type = XMLSEC_SESSION_KEY_URI_TO_ALG.get(msg_enc) + response = self.sec.encrypt_assertion( response, tmp.name, - pre_encryption_part(key_name=_cert_name, encrypt_cert=unwrapped_cert), + pre_encryption_part( + key_name=_cert_name, + encrypt_cert=unwrapped_cert, + msg_enc=msg_enc, + key_enc=key_enc, + rsa_oaep_mgf_alg=rsa_oaep_mgf_alg, + ), + key_type=key_type, node_xpath=node_xpath, ) return response @@ -697,7 +770,11 @@ def _response( encrypt_assertion_self_contained=False, encrypted_advice_attributes=False, encrypt_cert_advice=None, + encrypt_cert_advice_cert_key_alg=None, + encrypt_cert_advice_session_key_alg=None, encrypt_cert_assertion=None, + encrypt_cert_assertion_cert_key_alg=None, + encrypt_cert_assertion_session_key_alg=None, sign_assertion=None, pefim=False, sign_alg=None, @@ -731,8 +808,16 @@ def _response( element should be encrypted. :param encrypt_cert_advice: Certificate to be used for encryption of assertions in the advice element. + :param encrypt_cert_advice_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_advice + :param encrypt_cert_advice_session_key_alg: algorithm used for encrypting assertion + when using encrypt_cert_advice :param encrypt_cert_assertion: Certificate to be used for encryption of assertions. + :param encrypt_cert_assertion_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_assertion + :param encrypt_cert_assertion_session_key_alg: algorithm used for encrypting assertion when + using encrypt_cert_assertion :param sign_assertion: True if assertions should be signed. :param pefim: True if a response according to the PEFIM profile should be created. @@ -856,6 +941,8 @@ def _response( sp_entity_id, response, node_xpath=node_xpath, + encrypt_cert_session_key_alg=encrypt_cert_advice_session_key_alg, + encrypt_cert_cert_key_alg=encrypt_cert_advice_cert_key_alg, ) response = response_from_string(response) @@ -900,7 +987,13 @@ def _response( response = signed_instance_factory(response, self.sec, to_sign_assertion) # XXX encrypt assertion - response = self._encrypt_assertion(encrypt_cert_assertion, sp_entity_id, response) + response = self._encrypt_assertion( + encrypt_cert_assertion, + sp_entity_id, + response, + encrypt_cert_session_key_alg=encrypt_cert_assertion_session_key_alg, + encrypt_cert_cert_key_alg=encrypt_cert_assertion_cert_key_alg, + ) else: # XXX sign other parts! (defiend by to_sign) if to_sign: @@ -1357,7 +1450,6 @@ def create_manage_name_id_response( digest_alg=None, **kwargs, ): - rinfo = self.response_args(request, bindings) response = self._status_response( diff --git a/src/saml2/md.py b/src/saml2/md.py index 06d5bd77d..16ca01f1b 100644 --- a/src/saml2/md.py +++ b/src/saml2/md.py @@ -10,7 +10,6 @@ from saml2 import xmldsig as ds from saml2 import xmlenc as xenc - NAMESPACE = "urn:oasis:names:tc:SAML:2.0:metadata" @@ -803,6 +802,7 @@ def __init__( text=None, extension_elements=None, extension_attributes=None, + mgf=None, ): SamlBase.__init__( self, text=text, extension_elements=extension_elements, extension_attributes=extension_attributes @@ -810,6 +810,7 @@ def __init__( self.key_info = key_info self.encryption_method = encryption_method or [] self.use = use + self.mgf = mgf def key_descriptor_type__from_string(xml_string): diff --git a/src/saml2/mdstore.py b/src/saml2/mdstore.py index 4126e49e0..e0521e8a2 100644 --- a/src/saml2/mdstore.py +++ b/src/saml2/mdstore.py @@ -476,7 +476,7 @@ def __eq__(self, other): return True - def certs(self, entity_id, descriptor, use="signing"): + def certs(self, entity_id, descriptor, use="signing", get_with_usage_and_encryption_methods=False): """ Returns certificates for the given Entity """ @@ -494,7 +494,10 @@ def extract_certs(srvs): for dat in key_info["x509_data"]: cert = repack_cert(dat["x509_certificate"]["text"]) if cert not in res: - res.append((key_name_txt, cert)) + if get_with_usage_and_encryption_methods: + res.append((key_name_txt, cert, key_use, key.get("encryption_method"))) + else: + res.append((key_name_txt, cert)) return res @@ -1327,7 +1330,7 @@ def subject_id_requirement(self, entity_id): "name_format": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", "friendly_name": "subject-id", "is_required": "true", - } + }, ] elif subject_id_req == "pairwise-id": return [ diff --git a/src/saml2/server.py b/src/saml2/server.py index 8b5572001..1a7153e93 100644 --- a/src/saml2/server.py +++ b/src/saml2/server.py @@ -457,7 +457,11 @@ def _authn_response( best_effort=False, encrypt_assertion=False, encrypt_cert_advice=None, + encrypt_cert_advice_cert_key_alg=None, + encrypt_cert_advice_session_key_alg=None, encrypt_cert_assertion=None, + encrypt_cert_assertion_cert_key_alg=None, + encrypt_cert_assertion_session_key_alg=None, authn_statement=None, encrypt_assertion_self_contained=False, encrypted_advice_attributes=False, @@ -492,8 +496,16 @@ def _authn_response( element should be encrypted. :param encrypt_cert_advice: Certificate to be used for encryption of assertions in the advice element. + :param encrypt_cert_advice_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_advice + :param encrypt_cert_advice_session_key_alg: algorithm used for encrypting assertion + when using encrypt_cert_advice :param encrypt_cert_assertion: Certificate to be used for encryption of assertions. + :param encrypt_cert_assertion_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_assertion + :param encrypt_cert_assertion_session_key_alg: algorithm used for encrypting assertion when + using encrypt_cert_assertion :param authn_statement: Authentication statement. :param pefim: True if a response according to the PEFIM profile should be created. @@ -598,7 +610,11 @@ def _authn_response( sp_entity_id=sp_entity_id, encrypt_assertion=encrypt_assertion, encrypt_cert_advice=encrypt_cert_advice, + encrypt_cert_advice_cert_key_alg=encrypt_cert_advice_cert_key_alg, + encrypt_cert_advice_session_key_alg=encrypt_cert_advice_session_key_alg, encrypt_cert_assertion=encrypt_cert_assertion, + encrypt_cert_assertion_cert_key_alg=encrypt_cert_assertion_cert_key_alg, + encrypt_cert_assertion_session_key_alg=encrypt_cert_assertion_session_key_alg, encrypt_assertion_self_contained=encrypt_assertion_self_contained, encrypted_advice_attributes=encrypted_advice_attributes, sign_assertion=sign_assertion, @@ -724,7 +740,6 @@ def gather_authn_response_args(self, sp_entity_id, name_id_policy, userid, **kwa ("encrypted_advice_attributes", "verify_encrypt_cert_advice", "encrypt_cert_advice", kwargs["pefim"]), ("encrypt_assertion", "verify_encrypt_cert_assertion", "encrypt_cert_assertion", False), ]: - if args[arg] or pefim: _enc_cert = self.config.getattr(attr, "idp") @@ -789,7 +804,11 @@ def create_authn_response( sign_response=None, sign_assertion=None, encrypt_cert_advice=None, + encrypt_cert_advice_cert_key_alg=None, + encrypt_cert_advice_session_key_alg=None, encrypt_cert_assertion=None, + encrypt_cert_assertion_cert_key_alg=None, + encrypt_cert_assertion_session_key_alg=None, encrypt_assertion=None, encrypt_assertion_self_contained=True, encrypted_advice_attributes=False, @@ -822,8 +841,16 @@ def create_authn_response( element should be encrypted. :param encrypt_cert_advice: Certificate to be used for encryption of assertions in the advice element. + :param encrypt_cert_advice_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_advice + :param encrypt_cert_advice_session_key_alg: algorithm used for encrypting assertion + when using encrypt_cert_advice :param encrypt_cert_assertion: Certificate to be used for encryption of assertions. + :param encrypt_cert_assertion_cert_key_alg: algorithm used for encrypting session key + by encrypt_cert_assertion + :param encrypt_cert_assertion_session_key_alg: algorithm used for encrypting assertion when + using encrypt_cert_assertion :param pefim: True if a response according to the PEFIM profile should be created. :return: A response instance @@ -869,6 +896,10 @@ def create_authn_response( sign_alg=sign_alg, digest_alg=digest_alg, session_not_on_or_after=session_not_on_or_after, + encrypt_cert_advice_cert_key_alg=encrypt_cert_advice_cert_key_alg, + encrypt_cert_advice_session_key_alg=encrypt_cert_advice_session_key_alg, + encrypt_cert_assertion_cert_key_alg=encrypt_cert_assertion_cert_key_alg, + encrypt_cert_assertion_session_key_alg=encrypt_cert_assertion_session_key_alg, **args, ) except MissingValue as exc: @@ -1054,7 +1085,6 @@ def create_ecp_authn_request_response( digest_alg=None, **kwargs, ): - # ---------------------------------------- # = (3, 9): @@ -61,13 +60,12 @@ from saml2.xmldsig import TRANSFORM_C14N from saml2.xmldsig import TRANSFORM_ENVELOPED import saml2.xmldsig as ds -from saml2.xmlenc import CipherData +from saml2.xmlenc import CipherData, RsaOaepMgf from saml2.xmlenc import CipherValue from saml2.xmlenc import EncryptedData from saml2.xmlenc import EncryptedKey from saml2.xmlenc import EncryptionMethod - logger = logging.getLogger(__name__) SIG = f"{{{ds.NAMESPACE}#}}Signature" @@ -76,6 +74,17 @@ 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_MGF1P = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" +RSA_OAEP = "http://www.w3.org/2009/xmlenc11#rsa-oaep" + +XMLSEC_SESSION_KEY_URI_TO_ALG = { + "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": "des-192", + "http://www.w3.org/2001/04/xmlenc#aes128-cbc": "aes-128", + "http://www.w3.org/2001/04/xmlenc#aes192-cbc": "aes-192", + "http://www.w3.org/2001/04/xmlenc#aes256-cbc": "aes-256", + "http://www.w3.org/2009/xmlenc11#aes128-gcm": "aes-128", + "http://www.w3.org/2009/xmlenc11#aes192-gcm": "aes-192", + "http://www.w3.org/2009/xmlenc11#aes256-gcm": "aes-256", +} class SigverError(SAMLError): @@ -327,7 +336,7 @@ def signed_instance_factory(instance, seccont, elements_to_sign=None): if not isinstance(instance, str): signed_xml = instance.to_string() - for (node_name, nodeid) in elements_to_sign: + for node_name, nodeid in elements_to_sign: signed_xml = seccont.sign_statement(signed_xml, node_name=node_name, node_id=nodeid) return signed_xml @@ -486,9 +495,9 @@ def parse_xmlsec_verify_output(output, version=None): raise XmlsecError(output) else: for line in output.splitlines(): - if line == 'Verification status: OK': + if line == "Verification status: OK": return True - elif line == 'Verification status: FAILED': + elif line == "Verification status: FAILED": raise XmlsecError(output) raise XmlsecError(output) @@ -854,7 +863,7 @@ def _run_xmlsec(self, com_list, extra_args): with NamedTemporaryFile(suffix=".xml") as ntf: com_list.extend(["--output", ntf.name]) if self.version_nums >= (1, 3): - com_list.extend(['--lax-key-search']) + com_list.extend(["--lax-key-search"]) com_list += extra_args logger.debug("xmlsec command: %s", " ".join(com_list)) @@ -893,6 +902,7 @@ def __init__(self): def version(self): try: import xmlsec + return xmlsec.__version__ except (ImportError, AttributeError): return "0.0.0" @@ -1206,7 +1216,6 @@ def __init__( sec_backend=None, delete_tmpfiles=True, ): - if not isinstance(crypto, CryptoBackend): raise ValueError("crypto should be of type CryptoBackend") self.crypto = crypto @@ -1733,7 +1742,7 @@ def multiple_signatures(self, statement, to_sign, key=None, key_file=None, sign_ :param key_file: A file that contains the key to be used :return: A possibly multiple signed statement """ - for (item, sid) in to_sign: + for item, sid in to_sign: if not sid: if not item.id: sid = item.id = sid() @@ -1850,11 +1859,13 @@ def pre_encryption_part( encrypted_key_id=None, encrypted_data_id=None, encrypt_cert=None, + rsa_oaep_mgf_alg=None, ): ek_id = encrypted_key_id or f"EK_{gen_random_key()}" ed_id = encrypted_data_id or f"ED_{gen_random_key()}" msg_encryption_method = EncryptionMethod(algorithm=msg_enc) - key_encryption_method = EncryptionMethod(algorithm=key_enc) + rsa_oaep_mgf_alg = RsaOaepMgf(rsa_oaep_mgf_alg) if rsa_oaep_mgf_alg else None + key_encryption_method = EncryptionMethod(algorithm=key_enc, mgf=rsa_oaep_mgf_alg) x509_data = ds.X509Data(x509_certificate=ds.X509Certificate(text=encrypt_cert)) if encrypt_cert else None key_name = ds.KeyName(text=key_name) if key_name else None @@ -1874,6 +1885,7 @@ def pre_encryption_part( key_info=key_info, cipher_data=CipherData(cipher_value=CipherValue(text="")), ) + return encrypted_data diff --git a/src/saml2/xmlenc/__init__.py b/src/saml2/xmlenc/__init__.py index 3f06bc94c..37306bf82 100644 --- a/src/saml2/xmlenc/__init__.py +++ b/src/saml2/xmlenc/__init__.py @@ -8,7 +8,6 @@ from saml2 import SamlBase from saml2 import xmldsig as ds - NAMESPACE = "http://www.w3.org/2001/04/xmlenc#" @@ -29,7 +28,6 @@ def key_size_type__from_string(xml_string): class CipherValue(SamlBase): - c_tag = "CipherValue" c_namespace = NAMESPACE c_value_type = {"base": "base64Binary"} @@ -77,7 +75,6 @@ def transforms_type__from_string(xml_string): class KA_Nonce(SamlBase): - c_tag = "KA_Nonce" c_namespace = NAMESPACE c_value_type = {"base": "base64Binary"} @@ -92,7 +89,6 @@ def k_a__nonce_from_string(xml_string): class OriginatorKeyInfo(ds.KeyInfo): - c_tag = "OriginatorKeyInfo" c_namespace = NAMESPACE c_children = ds.KeyInfo.c_children.copy() @@ -106,7 +102,6 @@ def originator_key_info_from_string(xml_string): class RecipientKeyInfo(ds.KeyInfo): - c_tag = "RecipientKeyInfo" c_namespace = NAMESPACE c_children = ds.KeyInfo.c_children.copy() @@ -229,7 +224,6 @@ def encryption_property_type__from_string(xml_string): class KeySize(KeySizeType_): - c_tag = "KeySize" c_namespace = NAMESPACE c_children = KeySizeType_.c_children.copy() @@ -243,7 +237,6 @@ def key_size_from_string(xml_string): class OAEPparams(SamlBase): - c_tag = "OAEPparams" c_namespace = NAMESPACE c_value_type = {"base": "base64Binary"} @@ -257,6 +250,27 @@ def oae_pparams_from_string(xml_string): return saml2.create_class_from_xml_string(OAEPparams, xml_string) +class RsaOaepMgf(SamlBase): + c_tag = "MGF" + c_namespace = "http://www.w3.org/2009/xmlenc11#" + c_children = SamlBase.c_children.copy() + c_attributes = SamlBase.c_attributes.copy() + c_child_order = SamlBase.c_child_order[:] + c_cardinality = SamlBase.c_cardinality.copy() + c_attributes["Algorithm"] = ("algorithm", "anyURI", True) + + def __init__( + self, + algorithm=None, + ): + SamlBase.__init__(self) + self.algorithm = algorithm + + +def mgf_name_from_string(xml_string): + return saml2.create_class_from_xml_string(RsaOaepMgf, xml_string) + + class EncryptionMethodType_(SamlBase): """The http://www.w3.org/2001/04/xmlenc#:EncryptionMethodType element""" @@ -270,8 +284,10 @@ class EncryptionMethodType_(SamlBase): c_cardinality["key_size"] = {"min": 0, "max": 1} c_children["{http://www.w3.org/2001/04/xmlenc#}OAEPparams"] = ("oae_pparams", OAEPparams) c_cardinality["oae_pparams"] = {"min": 0, "max": 1} + c_children["{http://www.w3.org/2009/xmlenc11#}MGF"] = ("mgf", RsaOaepMgf) + c_cardinality["mgf"] = {"min": 0, "max": 1} c_attributes["Algorithm"] = ("algorithm", "anyURI", True) - c_child_order.extend(["key_size", "oae_pparams"]) + c_child_order.extend(["key_size", "oae_pparams", "mgf"]) def __init__( self, @@ -281,6 +297,7 @@ def __init__( text=None, extension_elements=None, extension_attributes=None, + mgf=None, ): SamlBase.__init__( self, @@ -291,6 +308,7 @@ def __init__( self.key_size = key_size self.oae_pparams = oae_pparams self.algorithm = algorithm + self.mgf = mgf def encryption_method_type__from_string(xml_string): @@ -298,7 +316,6 @@ def encryption_method_type__from_string(xml_string): class Transforms(TransformsType_): - c_tag = "Transforms" c_namespace = NAMESPACE c_children = TransformsType_.c_children.copy() @@ -348,7 +365,6 @@ def cipher_reference_type__from_string(xml_string): class EncryptionMethod(EncryptionMethodType_): - c_tag = "EncryptionMethod" c_namespace = NAMESPACE c_children = EncryptionMethodType_.c_children.copy() @@ -377,7 +393,6 @@ def agreement_method_from_string(xml_string): class DataReference(ReferenceType_): - c_tag = "DataReference" c_namespace = NAMESPACE c_children = ReferenceType_.c_children.copy() @@ -391,7 +406,6 @@ def data_reference_from_string(xml_string): class KeyReference(ReferenceType_): - c_tag = "KeyReference" c_namespace = NAMESPACE c_children = ReferenceType_.c_children.copy() @@ -645,7 +659,6 @@ def encrypted_data_type__from_string(xml_string): class CarriedKeyName(SamlBase): - c_tag = "CarriedKeyName" c_namespace = NAMESPACE c_value_type = {"base": "string"} @@ -747,7 +760,6 @@ def encrypted_key_from_string(xml_string): ds.KeyInfo.c_children["{http://www.w3.org/2000/09/xmlenc#}EncryptedKey"] = ("encrypted_key", EncryptedKey) - ELEMENT_FROM_STRING = { EncryptionMethodType_.c_tag: encryption_method_type__from_string, KeySizeType_.c_tag: key_size_type__from_string, @@ -779,6 +791,7 @@ def encrypted_key_from_string(xml_string): DataReference.c_tag: data_reference_from_string, KeyReference.c_tag: key_reference_from_string, CarriedKeyName.c_tag: carried_key_name_from_string, + RsaOaepMgf.c_tag: mgf_name_from_string, } ELEMENT_BY_TAG = { @@ -813,6 +826,7 @@ def encrypted_key_from_string(xml_string): "KeyReference": KeyReference, "CarriedKeyName": CarriedKeyName, "EncryptedType": EncryptedType_, + "MGF": RsaOaepMgf, }