通过GET方法对SAML身份验证请求的签名验证失败

时间:2019-08-17 10:28:33

标签: c# asp.net saml saml-2.0 sign

我正在使用c#和asp.net将 SIGNED authnRequest发送到idp。我的代码对authnRequest进行了签名,但签名验证在idp处失败。

详细信息

我尝试了很多解决方案,但徒劳无功。 这是我按照https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf设置的指导方针所做的事情:

  • STEPS

    1. 定义身份验证请求,然后对base64进行编码,最后对它进行Url编码。让我们称之为AR
    2. URL对RelayState进行编码。让我们称之为RS
    3. 网址对签名算法字符串进行编码。让我们称之为SA
    4. 因此现在要签名的字符串变为 SAMLRequest = AR&RelayState = RS&SigAlg = SA
    5. 现在,我使用私钥(服务提供商私钥)对在步骤4中获得的字符串进行签名。 6.我得到的结果签名是基于64进行编码的,然后是URL进行编码的。因此,我得到了base64和url编码的签名。让我们称之为SG
    6. 现在,我将在步骤6中获得的签名附加到步骤4中的查询字符串。所以最终的查询字符串变成 SAMLRequest = AR&RelayState = RS&SigAlg = SA&Signature = SG

一切正常,但签名验证失败!

这是我的代码,类似于这里的https://github.com/Sustainsys/Saml2/blob/v0.21.2/Kentor.AuthServices/WebSSO/Saml2RedirectBinding.cs#L53-L68

protected void btnSendAuthRequest_Click(object sender, EventArgs e)
    {
        string authRequest = txtInput.Text;
        //authRequest = authRequest.TrimEnd('\r', '\n');
        authRequest = DeflateBase64UrlEncode(authRequest);

        string spPrivateKey= txtKey.Text;
        string relayState = HttpUtility.UrlEncode("https://example.com/pages/home.aspx");

        string qs = "SAMLRequest=" + authRequest + "&RelayState=" + relayState;
        qs = AddSignature(qs, spPrivateKey);

        txtOutput.Text = qs;
    }

public string AddSignature(string queryString, string PrivateKeyNoHeaders)
    {
        RSACryptoServiceProvider tmpRsa = RSAKeyTests.RSAKeyUtils.DecodePrivateKeyInfo(Convert.FromBase64String(PrivateKeyNoHeaders));

        string signingAlgorithmUrl = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";

        queryString += "&SigAlg=" + HttpUtility.UrlEncode(signingAlgorithmUrl);

        var signatureDescription = (SignatureDescription)CryptoConfig.CreateFromName(signingAlgorithmUrl);
        HashAlgorithm hashAlg = signatureDescription.CreateDigest();
        hashAlg.ComputeHash(Encoding.UTF8.GetBytes(queryString));

AsymmetricSignatureFormatter asymmetricSignatureFormatter =
            signatureDescription.CreateFormatter(
                ((RSACryptoServiceProvider)tmpRsa));
        //.GetSha256EnabledRSACryptoServiceProvider()); 
        // Is the signature failing because of above ? 

        byte[] signatureValue = asymmetricSignatureFormatter.CreateSignature(hashAlg);
        queryString += "&Signature=" + HttpUtility.UrlEncode(Convert.ToBase64String(signatureValue));

        return queryString;
    }

private string DeflateBase64UrlEncode(string input)
    {
        var inputs = string.Format(input, Guid.NewGuid());
        var bytes = Encoding.UTF8.GetBytes(inputs);
        using (var output = new MemoryStream())
        {
            using (var zip = new DeflateStream(output, CompressionMode.Compress))
            {
                zip.Write(bytes, 0, bytes.Length);
            }
            var base64 = Convert.ToBase64String(output.ToArray());
            return HttpUtility.UrlEncode(base64);
        }
    }

1 个答案:

答案 0 :(得分:0)

CryptoConfig.createFromName(...) doesn't knowhttp://www.w3.org/2000/09/xmldsig#rsa-sha1作为摘要+签名算法。如果CryptoConfig.createFromName()不返回null,则为http://www.w3.org/2000/09/xmldsig#rsa-sha1注册的任何算法都可能不是RSA-SHA1。这是SignatureDescription与RSA和SHA1的显式实现:

public class RSASHA1SignatureDescription : SignatureDescription {

        public RSASHA1SignatureDescription() {
            KeyAlgorithm = "System.Security.Cryptography.RSA";
            DigestAlgorithm = "System.Security.Cryptography.SHA1Cng";
            FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
            DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
            _hashAlgorithm = "SHA1";
        }

        public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) {
            AsymmetricSignatureDeformatter item = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm);
            item.setKey(key);
            item.SetHashAlgorithm(_hashAlgorithm);
            return item;
        }

        public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) {
            AsymmetricSignatureFormatter item = (AsymmetricSignatureFormatter) CryptoConfig.CreateFromName(FormatterAlgorithm);
            item.setKey(key);
            item.SetHashAlgorithm(_hashAlgorithm);
            return item;
        }

        private string _hashAlgorithm;
    }

另一种可能性是,但是您要验证签名时,不需要rsa-sha1(许多身份提供者通过配置禁止rsa-sha1)或验证不正确。尝试向真实的IdP(例如Okta或Salesforce)进行注册,并在那里进行验证。