Signature Validation for a SAML Authn Request via GET method fails

血红的双手。 提交于 2019-12-08 04:59:07

问题


I am sending a SIGNED authnRequest to the idp using c# and asp.net. My code signs the authnRequest but the signature validation fails at idp.

Details

I tried a lot of solutions but in vain. This is what i am doing following guidlines set by https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf:

  • STEPS

    1. Deflate the auth request, then base64 encode it and finally Url Encode it. Lets call it AR
    2. Url encode the RelayState. Lets call it RS
    3. Url encode the signing Algorithm string. Lets call it SA
    4. So the string to be signed now becomes SAMLRequest=AR&RelayState=RS&SigAlg=SA
    5. Now i sign the string we get in step #4 using our private key (service provider private key). 6.The resultant signature that i get, i base 64 encode it, and then URL encode it. Thus i get a base64 and url encoded signature. Lets call it SG
    6. Now i append the signature we got in step #6 to the querystring in step #4. So the final querystring becomes SAMLRequest=AR&RelayState=RS&SigAlg=SA&Signature=SG

All this works fine but the signature validation is failing !

Here's my code which is similar to the code found here 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:


CryptoConfig.createFromName(...) doesn't know about http://www.w3.org/2000/09/xmldsig#rsa-sha1 as the digest+signing algorithm. If CryptoConfig.createFromName() is not returning null, whatever algorithm is registered for http://www.w3.org/2000/09/xmldsig#rsa-sha1 might not be RSA-SHA1. Here's an explicit implementation of SignatureDescription with RSA and 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;
    }

The other possibility is that however you're validating the signature doesn't want rsa-sha1 (many identity providers prohibit rsa-sha1 via configuration) or the validation is incorrect. Try registering with a real IdP such as Okta or Salesforce and validate there.



来源:https://stackoverflow.com/questions/57535442/signature-validation-for-a-saml-authn-request-via-get-method-fails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!