Brad
Brad

Reputation: 143

Invalid algorithm specified - Custom STS

I have implemented a custom STS in order to authenticate users from our web application into a SharePoint instance hosted elsewhere, and is displayed in a frame in the application.

This worked fine during development, and also during testing, however the following exception is being thrown intermittently during UAT:

[System.Security.Cryptography.CryptographicException] Invalid algorithm specified.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature)
   at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash)
   at System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash)
   at System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash)
   at System.IdentityModel.SignedXml.ComputeSignature(HashAlgorithm hash, AsymmetricSignatureFormatter formatter, String signatureMethod)
   at System.IdentityModel.SignedXml.ComputeSignature(SecurityKey signingKey)
   at System.IdentityModel.EnvelopedSignatureWriter.ComputeSignature()
   at System.IdentityModel.EnvelopedSignatureWriter.OnEndRootElement()
   at System.IdentityModel.Tokens.SamlSecurityTokenHandler.WriteAssertion(XmlWriter writer, SamlAssertion assertion)
   at System.IdentityModel.Tokens.SecurityTokenHandlerCollection.WriteToken(XmlWriter writer, SecurityToken token)
   at System.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteRSTRXml(XmlWriter writer, String elementName, Object elementValue, WSTrustSerializationContext context, WSTrustConstantsAdapter trustConstants)
   at System.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
   at System.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context)
   at System.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteResponse(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
   at System.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteXml(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context)
   at System.IdentityModel.Services.WSFederationSerializer.GetResponseAsString(RequestSecurityTokenResponse response, WSTrustSerializationContext context)
   at System.IdentityModel.Services.SignInResponseMessage..ctor(Uri baseUrl, RequestSecurityTokenResponse response, WSFederationSerializer federationSerializer, WSTrustSerializationContext context)
   at System.IdentityModel.Services.FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(SignInRequestMessage requestMessage, ClaimsPrincipal principal, SecurityTokenService sts, WSFederationSerializer federationSerializer)
   at Web.Secure.SharePoint.ProcessRequest()

The implementation of the STS is as follows:

using System.IdentityModel;
using System.IdentityModel.Configuration;
using System.IdentityModel.Protocols.WSTrust;
using System.IdentityModel.Tokens;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;

namespace Core.Services
{
    public class SharepointSecurityTokenService : SecurityTokenService
    {
        public SharepointSecurityTokenService(SecurityTokenServiceConfiguration securityTokenServiceConfiguration)
            : base(securityTokenServiceConfiguration)
        {
        }

        protected override Scope GetScope(ClaimsPrincipal principal, RequestSecurityToken request)
        {
            var scope = new Scope(request.AppliesTo.Uri.OriginalString, SecurityTokenServiceConfiguration.SigningCredentials);
            scope.TokenEncryptionRequired = false;
            scope.ReplyToAddress = request.ReplyTo;

            return scope;
        }

        protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
        {
            var identity = new ClaimsIdentity(principal.Claims);

            return identity;
        }
    }
}

and the code that calls this and generates the response form is as follows:

var identity = (ClaimsIdentity)HttpContext.Current.User.Identity;
identity.AddClaim(new Claim(ClaimTypes.Role, role));
var claimsPrinciple = new ClaimsPrincipal(identity);

var requestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromNameValueCollection(sharePointLibraryUri, parameters);
var sharepointCertificate = Global.AppCache.GetSharepointCertificate();

if (sharepointCertificate == null)
{
    throw new SharePointRequestException("No SharePoint signing certificate.", requestId);
}

var signingCredentials = new X509SigningCredentials(sharepointCertificate);
var config = new SecurityTokenServiceConfiguration(Settings.Default.SharePointTokenIssuerName, signingCredentials);
var sts = new SharepointSecurityTokenService(config);
var responseMessage = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(requestMessage, claimsPrinciple, sts);
var responseForm = responseMessage.WriteFormPost();

Response.Write(responseForm);

To confirm we have used the same certificate on all environments, and it consistently works in development, but fails on the server. To confuse matters further it has worked for a few hours at a time on this server, but for no apparent reason will stop working again. I do not know what triggers it to either start or stop working.

Upvotes: 3

Views: 892

Answers (1)

peter.swallow
peter.swallow

Reputation: 945

You could be missing a reference to the the algorithm. You may need to include this line when you're application starts up.

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

Upvotes: 0

Related Questions