Package: signxml-openadr
SignXMLis an implementation of the W3CXML Signaturestandard in
Python. This standard (also known as XMLDSig andRFC 3275) is used to provide
payload security inSAML 2.0andWS-Security, among other uses. Two versions of the standard exist
(Version 1.1andVersion 2.0).SignXMLimplements all of the required components of the standard, and most recommended ones. Its features are:Use of a libxml2-based XML parser configured to defend againstcommon XML attackswhen verifying signaturesExtensions to allow signing with and verifying X.509 certificate chains, including hostname/CN validationSupport for exclusive XML canonicalization with inclusive prefixes (InclusiveNamespaces PrefixList, required to verify signatures generated by
some SAML implementations)Modern Python compatibility (2.7-3.8+ and PyPy)Well-supported, portable, reliable dependencies:lxml,cryptography,eight,pyOpenSSLComprehensive testing (including the XMLDSig interoperability suite) andcontinuous integrationSimple interface with useful defaultsCompactness, readability, and extensibilityInstallationpip3 install signxmlNote: SignXML depends onlxmlandcryptography, which in turn depend onOpenSSL,LibXML, and Python tools to interface with them. You can install those as follows:OSCommandUbuntuapt-getinstall--no-install-recommendspython3-pippython3-wheelpython3-setuptoolspython3-opensslpython3-lxmlRed Hat,
Amazon Linux,
CentOSyum installpython3-pippython3-pyOpenSSLpython3-lxmlMac OSInstallHomebrew, then runbrew install python.SynopsisSignXML uses thelxml ElementTree APIto work with XML data.fromlxmlimportetreefromsignxmlimportXMLSigner,XMLVerifierdata_to_sign="<Test/>"cert=open("example.pem").read()key=open("example.key").read()root=etree.fromstring(data_to_sign)signed_root=XMLSigner().sign(root,key=key,cert=cert)verified_data=XMLVerifier().verify(signed_root).signed_xmlTo make this example self-sufficient for test purposes:Generate a test certificate and key usingopenssl req-x509-sha256-nodes-subj"/CN=test"-days1-newkeyrsa:2048-keyoutexample.key-outexample.pem(runyum install opensslon Red Hat).Pass thex509_cert=certkeyword argument toXMLVerifier.verify(). (In production, ensure this is replaced with
the correct configuration for the trusted CA or certificate - this determines which signatures your application trusts.)Verifying SAML assertionsAssumingmetadata.xmlcontains SAML metadata for the assertion source:fromlxmlimportetreefrombase64importb64decodefromsignxmlimportXMLVerifierwithopen("metadata.xml","rb")asfh:cert=etree.parse(fh).find("//ds:X509Certificate").textassertion_data=XMLVerifier().verify(b64decode(assertion_body),x509_cert=cert).signed_xmlSigning SAML assertionsThe SAML assertion schema specifies a location for the enveloped XML signature (between<Issuer>and<Subject>). To sign a SAML assertion in a schema-compliant way, insert a signature placeholder tag at that location
before calling XMLSigner:<ds:SignatureId="placeholder"></ds:Signature>.See what is signedIt is important to understand and follow the best practice rule of “See what is signed” when verifying XML
signatures. The gist of this rule is: if your application neglects to verify that the information it trusts is
what was actually signed, the attacker can supply a valid signature but point you to malicious data that wasn’t signed
by that signature. Failure to follow this rule can lead to vulnerability against attacks likeSAML signature wrapping.In SignXML, you can ensure that the information signed is what you expect to be signed by only trusting the
data returned by theverify()method. Thesigned_xmlattribute of the return value is the XML node or string that
was signed.Recommended reading:W3C XML Signature Best Practices for Applications,OWASP: On Breaking SAML: Be Whoever You Want to Be,Duo Finds SAML Vulnerabilities Affecting Multiple ImplementationsEstablish trustIf you do not supply any keyword arguments toverify(), the default behavior is to trustanyvalid XML
signature generated using a valid X.509 certificate trusted by your system’s CA store. This means anyone can
get an SSL certificate and generate a signature that you will trust. To establish trust in the signer, use thex509_certargument to specify a certificate that was pre-shared out-of-band (e.g. via SAML metadata, as
shown inVerifying SAML assertions), orcert_subject_nameto specify a
subject name that must be in the signing X.509 certificate given by the signature (verified as if it were a
domain name), orca_pem_file/ca_pathto give a custom CA.XML signature methods: enveloped, detached, envelopingThe XML Signature specification defines three ways to compose a signature with the data being signed: enveloped,
detached, and enveloping signature. Enveloped is the default method. To specify the type of signature that you want to
generate, pass themethodargument tosign():signed_root=XMLSigner(method=signxml.methods.detached).sign(root,key=key,cert=cert)verified_data=XMLVerifier().verify(signed_root).signed_xmlFor detached signatures, the code above will use theIdorIDattribute ofrootto generate a relative URI
(<ReferenceURI="#value"). You can also override the value ofURIby passing areference_uriargument tosign(). To verify a detached signature that refers to an external entity, pass a callable resolver inXMLVerifier().verify(data,uri_resolver=...).See theAPI documentationfor more.XML parsing security and compatibility withxml.etree.ElementTreeSignXML uses thelxmlElementTree library, not theElementTree from Python’s standard library,
to work with XML. lxml is used due to its superior resistance to XML attacks, as well as XML canonicalization and
namespace organization features. It is recommended that you pass XML string input directly to signxml before further
parsing, and use lxml to work with untrusted XML input in general. If you do passxml.etree.ElementTreeobjects to
SignXML, you should be aware of differences in XML namespace handling between the two libraries. See the following
references for more information:How do I use lxml safely as a web-service endpoint?ElementTree compatibility of lxml.etreeXML Signatures with Python ElementTreeAuthorsAndrey KislyukLinksProject home page (GitHub)Documentation (Read the Docs)Package distribution (PyPI)Change logList of W3C XML Signature standards and draftsW3C Recommendation: XML Signature Syntax and Processing Version 1.1W3C Working Group Note: XML Signature Syntax and Processing Version 2.0W3C Working Group Note: XML Security 2.0 Requirements and Design ConsiderationsW3C Working Group Note: XML Signature Best PracticesXML-Signature InteroperabilityW3C Working Group Note: Test Cases for C14N 1.1 and XMLDSig InteroperabilityXMLSec: Related linksOWASP SAML Security Cheat SheetOkta Developer Docs: SAMLBugsPlease report bugs, issues, feature requests, etc. onGitHub.LicenseLicensed under the terms of theApache License, Version 2.0.