SignedXml checksignature 返回 false

2023-11-23

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

上周我一直在尝试验证 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.");
    }

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

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

我在这里缺少什么?

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


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

.NET 实现对其接受的内容非常有选择性。您的其他实现很可能与 .NET 实现的工作方式不完全相同。这确实是非常可悲的事情。例如,如果您可以在签名之前消除源 XML 中的空格和命名空间,那么这可能会有所帮助。另外,如果您可以确保两种实现都使用相同的 C14N 设置。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SignedXml checksignature 返回 false 的相关文章

随机推荐