SignedXml checksignature返回false

Jon*_* S. 10 .net c# xml-signature

我在这里看了关于这个问题的其他帖子,但似乎没有一个能解决我的情况.

我一直在尝试验证上周的SAML断言,我有2个客户端已经发送给我SAML但我无法验证它.

主要过程是我们得到一个base64编码的断言,我解码它.使用PreserveWhitespace = true将其加载到XmlDocment中.

验证方法是

  public static bool Verify(X509Certificate2 cert, XmlElement xmlElement, SignedXml signedXml)
  {
       bool flag;
       try
       {
           KeyInfo keyInfo = new KeyInfo();
           var clause = new KeyInfoX509Data(cert);
           keyInfo.AddClause(clause);

            XmlElement signatureElement = GetSignatureElement(xmlElement);
            if (signatureElement == null)
            {
                string message = "The XML does not contain a signature.";
                throw new SAMLSignatureException(message);
            }
            signedXml.LoadXml(signatureElement);
            if (keyInfo != null)
            {
                signedXml.KeyInfo = keyInfo;
            }
            SetSigningKeyFromKeyInfo(signedXml);
            flag = signedXml.CheckSignature(cert.PublicKey.Key);
        }
        catch (Exception exception)
        {
            throw new SAMLSignatureException("Failed to verify the XML signature.", exception);
        }
        return flag;
    }

 private static void SetSigningKeyFromKeyInfo(SignedXml signedXml)
    {
        IEnumerator enumerator = signedXml.KeyInfo.GetEnumerator();
        while (enumerator.MoveNext())
        {
            if (enumerator.Current is KeyInfoX509Data)
            {
                var current = (KeyInfoX509Data) enumerator.Current;
                if (current.Certificates.Count != 0)
                {
                    var certificate = (X509Certificate) current.Certificates[0];
                    var certificate2 = new X509Certificate2(certificate);
                    AsymmetricAlgorithm key = certificate2.PublicKey.Key;
                    signedXml.SigningKey = key;
                    return;
                }
            }
            else
            {
                if (enumerator.Current is RSAKeyValue)
                {
                    var value2 = (RSAKeyValue) enumerator.Current;
                    signedXml.SigningKey = value2.Key;
                    return;
                }
                if (enumerator.Current is DSAKeyValue)
                {
                    var value3 = (DSAKeyValue) enumerator.Current;
                    signedXml.SigningKey = value3.Key;
                    return;
                }
            }
        }
        throw new SAMLSignatureException("No signing key could be found in the key info.");
    }
Run Code Online (Sandbox Code Playgroud)

我从Web.Config读取客户端的证书(它存储为base64编码的字符串)xmlelement是signed元素,signedXml是使用新的SignedXml(xmlElement)创建的SignedXml对象

两个客户端都通过checkignature返回错误,但是当我使用我的证书创建自己的签名saml时,它将返回true.

我在这里错过了什么?

编辑:是的两个客户端都在Java上,我发布了SetSigningKeyFromKeyInfo方法

fej*_*oco 8

我过去经常处理签名的XML.我只能说这是一场噩梦.基本上,当您对XML进行签名时,它会经历一个名为canonicalization(C14N)的过程.它需要将XML文本转换为可以签名的字节流.XML C14N标准中的空白和命名空间处理等很难理解,甚至难以正确实现.甚至有多种类型的C14N.

.NET实现对它接受的内容非常挑剔.你的其他实现很可能与.NET的实现方式完全不同.这确实非常悲伤.例如,如果您可以在签名之前从源XML中消除空格和命名空间,那可能会有所帮助.此外,如果您可以确保两个实现使用相同的C14N设置.

否则很多调试都在等着你.您可以调试框架,或者通过反射手动调用其内部方法,以查看它如何计算XML片段和签名.并对其他实现做同样的事情.基本上,您需要查看在两种情况下都签名的确切字节流.这是签署前转换的最后一步.如果这些字节流匹配,那么根据我的经验,您对RSA签名部分没有任何问题.如果那些不匹配,就像你的情况一样,至少你会看到问题出在哪里.

  • 我真的希望这不是正确的答案. (5认同)

Tim*_*res 8

我刚刚遇到了类似的问题并损失了很多时间,也许这可以帮助别人。

我的环境是 100% .Net 4.5,并且我的代码仅使用 SignedXml 类。但 SAML 断言在一个地方被接受,而在另一个地方被拒绝。

结果发现,一个地方正在通过使用 初始化的 XmlDocument 实例加载断言PreserveWhitespace = true,而另一个地方则没有。

而且这个断言打印得很漂亮,所以它有回车符和很多缩进空间。删除所有回车符和缩进空格解决了我的问题。