我在这里查看了有关此问题的其他帖子,但它们似乎都无法解决我的情况。

我一直在尝试验证上周的SAML断言,我有2个客户向我发送了SAML,但我无法验证它。

主要过程是我们获得了一个基本64编码的断言,然后我将其解码。将其加载到具有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是一个签名XML对象,它是用新的signedxml(xmlelement)创建的signedxml对象。

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

我在这里想念什么?

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

有帮助吗?

解决方案

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

.NET实现对其接受的内容非常有选择性。您的其他实现很有可能与.NET ONE完全相同。这确实非常可悲。例如,如果您可以在签名之前从源XML中消除空格和名称空间,则可能会有所帮助。另外,如果您可以确保两个实现都使用相同的C14N设置。

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

其他提示

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

我的环境是100%.NET 4.5,我的代码仅使用签名ML类。但是在一个地方接受了SAML主张,并在另一个地方被拒绝。

事实证明,一个地方正在通过初始化的xmldocument实例加载断言 PreserveWhitespace = true, ,而另一个不是。

而且断言是相当印刷的,因此它具有马车回报和许多凹痕空间。删除所有运输申报表,并确定了我的问题。

SAML与Timores有类似的问题。 SAML需要从base64解码,但首先使用:

var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))

但这使用了ASCII解码,并且在特殊角色上遇到了麻烦。这意味着XML与签名时略有不同,这就是为什么失败的原因。将其更改为:

var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))

它适用于所有情况。

因此,请确保您正在使用正确的编码!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top