private static void ValidateSignedInfo(SignedXml signedXml, XmlElement xmlElement) { if (signedXml.SignedInfo.References.Count == 0) { throw new InvalidSignatureException("No reference found in Xml signature, it doesn't validate the Xml data."); } if (signedXml.SignedInfo.References.Count != 1) { throw new InvalidSignatureException("Multiple references for Xml signatures are not allowed."); } var reference = (Reference)signedXml.SignedInfo.References[0]; var id = reference.Uri.Substring(1); var idElement = signedXml.GetIdElement(xmlElement.OwnerDocument, id); if (idElement != xmlElement) { throw new InvalidSignatureException("Incorrect reference on Xml signature. The reference must be to the root element of the element containing the signature."); } foreach (Transform transform in reference.TransformChain) { if (!allowedTransforms.Contains(transform.Algorithm)) { throw new InvalidSignatureException( "Transform \"" + transform.Algorithm + "\" found in Xml signature SHOULD NOT be used with SAML2."); } } }
//an XML signature can "cover" not the whole document, but only a part of it //.NET's built in "CheckSignature" does not cover this case, it will validate to true. //We should check the signature reference, so it "references" the id of the root document element! If not - it's a hack private bool ValidateSignatureReference(SignedXml signedXml) { if (signedXml.SignedInfo.References.Count != 1) //no ref at all { return(false); } var reference = (Reference)signedXml.SignedInfo.References[0]; var id = reference.Uri.Substring(1); var idElement = signedXml.GetIdElement(_xmlDoc, id); if (idElement == _xmlDoc.DocumentElement) { return(true); } else //sometimes its not the "root" doc-element that is being signed, but the "assertion" element { var assertionNode = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion", _xmlNameSpaceManager) as XmlElement; if (assertionNode != idElement) { return(false); } } return(true); }
// Enveloped or detached 'internally' supported ony. internal void Sign(XmlElement rootElement) { XmlDocument doc = rootElement.OwnerDocument; SignedXml signedXml = new SignedXml(rootElement); signedXml.SigningKey = _cert.PrivateKey; KeyInfo keyInfo = GetKeyInfo(); signedXml.SignedInfo.CanonicalizationMethod = _canonicalizationMethod; if (keyInfo != null) { signedXml.KeyInfo = keyInfo; } if (_references.Count > 0) { foreach (var reference in _references) { signedXml.AddReference(NewReference(reference)); } } else { signedXml.AddReference(NewReference(string.Empty)); //Sign entire xml document. } try { signedXml.ComputeSignature(); } catch (CryptographicException e) { throw new DigitalSignException(e); } XmlElement xmlDSig = signedXml.GetXml(); if (_detached) { doc.LoadXml(xmlDSig.OuterXml); } else { //Enveloped if (_references.Count == 1 && _references[0].StartsWith("#")) { XmlElement idElement = signedXml.GetIdElement(doc, _references[0].Substring(1)); idElement.AppendChild(doc.ImportNode(xmlDSig, true)); } else { rootElement.AppendChild(doc.ImportNode(xmlDSig, true)); } } }
/// <summary> /// Verifies the signature. /// </summary> /// <param name="xml">The XML.</param> /// <returns>The issuer certificate</returns> protected virtual X509Certificate2 VerifySignature(XElement xml) { Contract.Requires(xml != null); Contract.Ensures(Contract.Result <X509Certificate2>() != null); if ((Configuration == null) || (Configuration.IssuerTokenResolver == null)) { throw new SecurityTokenException("No issuer token resolver configured"); } var xmlElement = xml.ToXmlElement(); var signedXml = new SignedXml(xmlElement); // find signature XmlNodeList nodeList = xmlElement.GetElementsByTagName("Signature"); // throw an exception if no signature was found. if (nodeList.Count <= 0) { throw new CryptographicException("Verification failed: No Signature was found in the document."); } // throw an exception if more than one signature was found. if (nodeList.Count > 1) { throw new CryptographicException("Verification failed: More that one signature was found for the document."); } // load the <signature> node. signedXml.LoadXml((XmlElement)nodeList[0]); // resolve the issuer certificate byte[] thumbprint = Convert.FromBase64String(GetIssuerThumbprint(signedXml)); var identifier = new X509ThumbprintKeyIdentifierClause(thumbprint); var issuerKey = Configuration.IssuerTokenResolver.ResolveToken(identifier) as X509SecurityToken; // check the signature var referenceUri = ((Reference)signedXml.SignedInfo.References[0]).Uri; if (!signedXml.CheckSignature(issuerKey.Certificate, true) || (referenceUri != "" && signedXml.GetIdElement(xmlElement.OwnerDocument, referenceUri) != xmlElement)) { throw new CryptographicException("Signature verification failed"); } if (issuerKey.Certificate != null) { return(issuerKey.Certificate); } else { throw new CryptographicException("No issuer certificate found"); } }
private static void ValidateReference( SignedXml signedXml, XmlElement xmlElement, string mininumDigestAlgorithm) { if (signedXml.SignedInfo.References.Count == 0) { throw new InvalidSignatureException( "No reference found in Xml signature, it doesn't validate the Xml data."); } if (signedXml.SignedInfo.References.Count != 1) { throw new InvalidSignatureException("Multiple references for Xml signatures are not allowed."); } var reference = (Reference)signedXml.SignedInfo.References[0]; if (string.IsNullOrWhiteSpace(reference.Uri)) { throw new InvalidSignatureException("Empty reference for Xml signature is not allowed."); } var id = reference.Uri.Substring(1); var idElement = signedXml.GetIdElement(xmlElement.OwnerDocument, id); if (idElement != xmlElement) { throw new InvalidSignatureException( "Incorrect reference on Xml signature. The reference must be to the root element of the element containing the signature."); } foreach (Transform transform in reference.TransformChain) { if (!allowedTransforms.Contains(transform.Algorithm)) { throw new InvalidSignatureException( "Transform \"" + transform.Algorithm + "\" found in Xml signature SHOULD NOT be used with SAML2."); } } if (!DigestAlgorithms.SkipWhile(a => a != mininumDigestAlgorithm) .Contains(reference.DigestMethod)) { throw new InvalidSignatureException("The digest method " + reference.DigestMethod + " is weaker than the minimum accepted " + mininumDigestAlgorithm + "."); } }
/// <summary> /// an XML signature can "cover" not the whole document, but only a part of it /// .NET's built in "CheckSignature" does not cover this case, it will validate to true. /// We should check the signature reference, so it "references" the id of the root document element! If not - it's a hack /// </summary> private bool HasValidSignatureReference(SignedXml signedXml) { if (signedXml.SignedInfo.References.Count != 1) //no ref at all { return(false); } var reference = (Reference)signedXml.SignedInfo.References[0]; var id = reference.Uri.Substring(1); var idElement = signedXml.GetIdElement(_xmlDoc, id); if (idElement == _xmlDoc.DocumentElement) { return(true); } var assertionNode = _xmlDoc.SelectSingleNode("/samlp:Response/saml:Assertion", _xmlNameSpaceManager) as XmlElement; return(assertionNode == idElement); }
/// <summary> /// Verifies that there is only one reference in the signature and that the reference in the signature matches the reference in the XML /// </summary> /// <param name="signedXml">The path to the signed file</param> /// <param name="xmlElement">signature and object data of the signed file</param> private static void CheckSignatureReference(SignedXml signedXml, XmlElement xmlElement) { //if no reference at all is found, there is a problem if (signedXml.SignedInfo.References.Count == 0) { throw new Exception("No reference was found in XML signature"); } //if there is more than one reference, there is a problem if (signedXml.SignedInfo.References.Count != 1) { throw new Exception("Multiple references for XML signatures are not allowed"); } var reference = (Reference)signedXml.SignedInfo.References[0]; var id = reference.Uri.Substring(1); var idElement = signedXml.GetIdElement(xmlElement.OwnerDocument, id); string signedReference = ""; //the reference in the XML will be compared to the reference in the signature, if no match, there is a problem if (idElement == null) { XmlNodeList objectNode = xmlElement.GetElementsByTagName("Object", "*"); //If we dont fine the id above, we will pull the Object element from the file if (objectNode.Count == 1) { //Create a new attribute. XmlNode testroot = objectNode[0]; signedReference = testroot.Attributes[0].Value.ToString(); } //Check the reference from the XML and see if it matches the signature, if it still doesn't there is a problem if (id != signedReference) { throw new Exception("The signed reference does not match the XML reference"); } } }