【问题标题】:Signed XML signature verification for SSO SAML (Using sha256)SSO SAML 的签名 XML 签名验证(使用 sha256)
【发布时间】:2017-08-01 00:08:02
【问题描述】:

在 Windows 2003 服务器上使用 VS 2008 和 .Net Framework 3.5。

为了安全起见,我们使用 SAML 实施了 SSO。我们在服务提供商端工作,我们验证从客户端系统生成的签名 XML SAML Assertuib 令牌。 到目前为止,我们遇到的任何签名文档都使用签名算法“rsa-sha1”,但现在我们有新客户发送签名算法为“rsa-sha256”的文件,问题就在这里。

public static string VerifySignature()
{
    if (m_xmlDoc == null)
        return "Could not load XMLDocument ";

    try
    {
        XmlNamespaceManager nsm = new XmlNamespaceManager(new NameTable());
        nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
        XmlElement sigElt = (XmlElement)m_xmlDoc.SelectSingleNode(
            "//dsig:Signature", nsm);

        // Load the signature for verification
        SignedXml sig = new SignedXml(m_xmlDoc);
        sig.LoadXml(sigElt);

        if (!sig.CheckSignature())
            return "Invalid Signature";
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
    return string.Empty;
}

现在,当我为这个新客户尝试相同的代码(使用签名算法 rsa-sha256h)时 - 这不起作用,我收到错误“无法为提供的签名算法创建签名描述。”

最近2-3天浏览了很多博客和文章,我才知道SignedXml不支持sha256。美好的。但是接下来呢。在某处提到使用 WIF,我也检查并尝试了this

我也在尝试使用 RSAPKCS1SignatureDeformatter 的 VerifySignature 方法。但不太确定要传递的两个参数是什么。

【问题讨论】:

  • 我的印象是支持加密算法,因为它支持 X509Certificate2 对象。 sig.CheckSignature(...) 方法有一个重载,它接受 2 个参数,即 X509Certificate2 和 bool。您是否尝试过使用它并传入证书和 true?

标签: c# .net saml sha256 signedxml


【解决方案1】:

Dotnet 4.6.2+ 内置了较新的 sha 哈希。对于 dotnet 4+,要访问 rsa-sha512、rsa-sha384 和 rsa-sha256,您应该在某处包含此代码。

/// <summary>Declare the signature type for rsa-sha512</summary>
public class RsaPkCs1Sha512SignatureDescription : SignatureDescription
{
    public RsaPkCs1Sha512SignatureDescription()
    {
        KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
        DigestAlgorithm = typeof(SHA512CryptoServiceProvider).FullName;
        FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
        DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        var sigProcessor = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA512");
        return sigProcessor;
    }

    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        var sigProcessor =
            (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA512");
        return sigProcessor;
    }
}

/// <summary>Declare the signature type for rsa-sha384</summary>
public class RsaPkCs1Sha384SignatureDescription : SignatureDescription {
    public RsaPkCs1Sha384SignatureDescription()
    {
        KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
        DigestAlgorithm = typeof(SHA384CryptoServiceProvider).FullName;
        FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
        DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        var sigProcessor = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA384");
        return sigProcessor;
    }

    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        var sigProcessor =
            (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA384");
        return sigProcessor;
    }
}

/// <summary>Declare the signature type for rsa-sha256</summary>
public class RsaPkCs1Sha256SignatureDescription : SignatureDescription
{
    public RsaPkCs1Sha256SignatureDescription()
    {
        KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
        DigestAlgorithm = typeof(SHA256CryptoServiceProvider).FullName;
        FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;
        DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        var sigProcessor =
            (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA256");
        return sigProcessor;
    }

    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        var sigProcessor =
            (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
        sigProcessor.SetKey(key);
        sigProcessor.SetHashAlgorithm("SHA256");
        return sigProcessor;
    }
}

然后,您应该通过调用这样的代码来激活这些 sig 描述。您只需调用一次,因此您可以根据需要从静态构造函数中调用它。

    CryptoConfig.AddAlgorithm(typeof(RsaPkCs1Sha512SignatureDescription),
        "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512");
    CryptoConfig.AddAlgorithm(typeof(RsaPkCs1Sha384SignatureDescription),
        "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384");
    CryptoConfig.AddAlgorithm(typeof(RsaPkCs1Sha256SignatureDescription),
        "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

在 SO 上向 Microsoft's Carlos LopezBitSchupsterAndrew 致敬。

【讨论】:

  • ....框架 4.6.2 解决了这个问题,不需要额外的代码。
  • @OllieJones - 您是否碰巧知道您的代码是否会在以后移动到目标 4.6.2 时中断?
  • @StephanG 我已经顺利迁移到 4.6.1。我知道 4.6.2 不再需要此代码,因为他们添加了新的哈希值。请参阅 blogs.msdn.microsoft.com/dotnet/2016/08/02/… 的 X509 部分。我还没有证实这个事实。
【解决方案2】:

对于 .net 4 及更早版本, 我发现从http://clrsecurity.codeplex.com/ 添加 Security.Cryptography 后,以下工作有效

(注意X509CertificateFinder是我自己的,通过指纹在证书存储中查找签名证书)

        /// <summary>
        /// Validate an XmlDocuments signature
        /// </summary>
        /// <param name="xnlDoc"> The saml response with the signature elemenet to validate </param>
        /// <returns> True if signature can be validated with certificate </returns>
        public bool ValidateX509CertificateSignature(XmlDocument xnlDoc)
        {
            XmlNodeList XMLSignatures = xnlDoc.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#");

            // Checking If the Response or the Assertion has been signed once and only once.
            if (XMLSignatures.Count != 1) return false;

            var signedXmlDoc = new SignedXml(xnlDoc);
            signedXmlDoc.LoadXml((XmlElement)XMLSignatures[0]);

            var certFinder = new X509CertificateFinder();
            var foundCert = certFinder.GetSignatureCertificate();

            CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
            return signedXmlDoc.CheckSignature(foundCert,false);
        }

【讨论】:

  • 请注意,从 .NET 4.5 开始,您不需要安装任何与 .net 4.0 及更早版本不同的第三方库。您只需添加对 System.Deployment 的引用并在您的进程中调用一次System.Security.Cryptography.CryptoConfig.AddAlgorithm(typeof (RSAPKCS1SHA256SignatureDescription), RsaSha256Namespace);,之后原始问题中的代码将使用 SHA256 哈希。另见blogs.msdn.com/b/winsdk/archive/2015/11/15/…
  • ` const string RsaSha256Namespace = "w3.org/2001/04/xmldsig-more#rsa-sha256";`
【解决方案3】:

这符合“简单”的条件,但可能不是“解决方案”:) 对于我们遇到的少数客户,我们已要求他们更改其 IdP 以使用 SHA-1 进行签名。他们能够改变它,当他们这样做时,它就会起作用。

不是技术解决方案,但它已经在“现场”工作,所以我想我会提到它。

【讨论】:

  • 我有客户拒绝做出改变,叹息。
【解决方案4】:

只需将其更新至 .NET Framework 4.6.01590 或更高版本,即可支持最高 SHA-512,无需任何代码更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-09
    • 2017-03-24
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-11-21
    • 2016-01-14
    • 2021-12-18
    相关资源
    最近更新 更多