@@ -661,8 +661,8 @@ def _apply_transforms(self, payload, transforms_node, signature, c14n_algorithm)
661
661
return payload
662
662
663
663
def verify (self , data , require_x509 = True , x509_cert = None , cert_subject_name = None , ca_pem_file = None , ca_path = None ,
664
- hmac_key = None , validate_schema = True , parser = None , uri_resolver = None , id_attribute = None ,
665
- expect_references = 1 , ignore_ambiguous_key_info = False ):
664
+ hmac_key = None , validate_schema = True , parser = None , uri_resolver = None , cert_resolver = None ,
665
+ id_attribute = None , expect_references = 1 , ignore_ambiguous_key_info = False ):
666
666
"""
667
667
Verify the XML signature supplied in the data and return the XML node signed by the signature, or raise an
668
668
exception if the signature is not valid. By default, this requires the signature to be generated using a valid
@@ -724,8 +724,16 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
724
724
Custom XML parser instance to use when parsing **data**. The default parser arguments used by SignXML are:
725
725
``resolve_entities=False``. See https://lxml.de/FAQ.html#how-do-i-use-lxml-safely-as-a-web-service-endpoint.
726
726
:type parser: :py:class:`lxml.etree.XMLParser` compatible parser
727
- :param uri_resolver: Function to use to resolve reference URIs that don't start with "#".
727
+ :param uri_resolver:
728
+ Function to use to resolve reference URIs that don't start with "#". The function is called with a single
729
+ string argument containing the URI to be resolved, and is expected to return a lxml.etree node or string.
728
730
:type uri_resolver: callable
731
+ :param cert_resolver:
732
+ Function to use to resolve X.509 certificates when X509IssuerSerial and X509Digest references are found in
733
+ the signature. The function is called with the keyword arguments ``x509_issuer_name``,
734
+ ``x509_serial_number`` and ``x509_digest``, and is expected to return an iterable of one or more
735
+ strings containing PEM-formatted certificates.
736
+ :type cert_resolver: callable
729
737
:param id_attribute:
730
738
Name of the attribute whose value ``URI`` refers to. By default, SignXML will search for "Id", then "ID".
731
739
:type id_attribute: string
@@ -791,10 +799,18 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
791
799
if x509_data is None :
792
800
raise InvalidInput ("Expected a X.509 certificate based signature" )
793
801
certs = [cert .text for cert in self ._findall (x509_data , "X509Certificate" )]
794
- if not certs :
795
- msg = "Expected to find an X509Certificate element in the signature"
796
- msg += " (X509SubjectName, X509SKI are not supported)"
797
- raise InvalidInput (msg )
802
+ if len (certs ) == 0 :
803
+ x509_iss = x509_data .find ("ds:X509IssuerSerial/ds:X509IssuerName" , namespaces = namespaces )
804
+ x509_sn = x509_data .find ("ds:X509IssuerSerial/ds:X509SerialNumber" , namespaces = namespaces )
805
+ x509_digest = x509_data .find ("dsig11:X509Digest" , namespaces = namespaces )
806
+ if cert_resolver is not None and (x509_iss or x509_sn or x509_digest ):
807
+ certs = cert_resolver (x509_issuer_name = x509_iss .text if x509_iss is not None else None ,
808
+ x509_serial_number = x509_sn .text if x509_sn is not None else None ,
809
+ x509_digest = x509_digest .text if x509_digest is not None else None )
810
+ else :
811
+ msg = "Expected to find an X509Certificate element in the signature"
812
+ msg += " (X509SubjectName, X509SKI are not supported)"
813
+ raise InvalidInput (msg )
798
814
cert_chain = [load_certificate (FILETYPE_PEM , add_pem_header (cert )) for cert in certs ]
799
815
signing_cert = verify_x509_cert_chain (cert_chain , ca_pem_file = ca_pem_file , ca_path = ca_path )
800
816
elif isinstance (self .x509_cert , X509 ):
0 commit comments