/// <summary> /// Sign an xml element with the supplied cert. /// </summary> /// <param name="xmlElement">xmlElement to be signed. The signature is /// added as a node in the document, right after the Issuer node.</param> /// <param name="cert">Certificate to use when signing.</param> /// <param name="includeKeyInfo">Include public key in signed output.</param> /// <param name="signingAlgorithm">The signing algorithm to use.</param> public static void Sign( this XmlElement xmlElement, X509Certificate2 cert, bool includeKeyInfo, string signingAlgorithm) { if (xmlElement == null) { throw new ArgumentNullException(nameof(xmlElement)); } if (cert == null) { throw new ArgumentNullException(nameof(cert)); } var signedXml = new SignedXmlWithIdFix(xmlElement.OwnerDocument); // The transform XmlDsigExcC14NTransform and canonicalization method XmlDsigExcC14NTransformUrl is important for partially signed XML files // see: http://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.signedxml.xmldsigexcc14ntransformurl(v=vs.110).aspx // The reference URI has to be set correctly to avoid assertion injections // For both, the ID/Reference and the Transform/Canonicalization see as well: // https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf section 5.4.2 and 5.4.3 signedXml.SigningKey = EnvironmentHelpers.IsNetCore ? cert.PrivateKey : ((RSACryptoServiceProvider)cert.PrivateKey) .GetSha256EnabledRSACryptoServiceProvider(); signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; signedXml.SignedInfo.SignatureMethod = signingAlgorithm; // We need a document unique ID on the element to sign it -- make one up if it's missing string id = xmlElement.GetAttribute("ID"); if (String.IsNullOrEmpty(id)) { id = "_" + Guid.NewGuid().ToString("N"); xmlElement.SetAttribute("ID", id); } var reference = new Reference { Uri = "#" + id, DigestMethod = GetCorrespondingDigestAlgorithm(signingAlgorithm) }; reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); reference.AddTransform(new XmlDsigExcC14NTransform()); signedXml.AddReference(reference); signedXml.ComputeSignature(); if (includeKeyInfo) { var keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(cert)); signedXml.KeyInfo = keyInfo; } xmlElement.InsertAfter( xmlElement.OwnerDocument.ImportNode(signedXml.GetXml(), true), xmlElement["Issuer", Saml2Namespaces.Saml2Name]); }