Second Life of a Hungarian SharePoint Geek

February 11, 2014

Certificate-related Errors with Claims-based Authentication

Filed under: Certificates, Claims, SP 2010 — Tags: , , — Peter Holpar @ 22:49

Today I wanted to fix a sporadic error we experienced with an IIS-based Security Token Service (STS) we use in one of our test SharePoint 2010 farms.

The original error was:

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

with a stack trace:

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at System.IdentityModel.Tokens.X509AsymmetricSecurityKey.get_PrivateKey()
at System.IdentityModel.Tokens.X509AsymmetricSecurityKey.GetAsymmetricAlgorithm(String algorithm, Boolean privateKey)
at Microsoft.IdentityModel.CryptoUtil.GetSignatureFormatterForSha256(AsymmetricSecurityKey key)
at Microsoft.IdentityModel.Protocols.XmlSignature.SignedXml.ComputeSignature(SecurityKey signingKey)
at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureWriter.ComputeSignature()
at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureWriter.OnEndRootElement()
at Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler.WriteAssertion(XmlWriter writer, SamlAssertion assertion)
at Microsoft.IdentityModel.Tokens.SecurityTokenSerializerAdapter.WriteTokenCore(XmlWriter writer, SecurityToken token)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteRSTRXml(XmlWriter writer, String elementName, Object elementValue, WSTrustSerializationContext context, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteResponse(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteXml(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSFederation.WSFederationSerializer.GetResponseAsString(RequestSecurityTokenResponse response, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSFederation.SignInResponseMessage..ctor(Uri baseUrl, RequestSecurityTokenResponse response, WSFederationSerializer federationSerializer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Web.FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(SignInRequestMessage requestMessage, IPrincipal principal, SecurityTokenService sts, WSFederationSerializer federationSerializer)

We typically did not experience this error at the office, most often it happened when we visited the site for example from home.

I found a few useful resources related to this issue, like this, this or this. However, in our case the RSACryptoServiceProvider constructor was called by internal IdentityModel classes and not by our custom code, so the proposed solution was not applicable, I had to investigate further.

During my study I found, that the application pool of the STS is running with the identity of one of the developer accounts. I created a dedicated service account and gave all the required permissions (at least, I thought I did…).

After the change the previous error disappeared, but a new one arose, and in this case, not only sporadic, but constantly:

System.Security.Cryptography.CryptographicException: Keyset does not exist

with a stack trace:

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at System.IdentityModel.Tokens.X509AsymmetricSecurityKey.get_PrivateKey()
at System.IdentityModel.Tokens.X509AsymmetricSecurityKey.GetAsymmetricAlgorithm(String algorithm, Boolean privateKey)
at Microsoft.IdentityModel.CryptoUtil.GetSignatureFormatterForSha256(AsymmetricSecurityKey key)
at Microsoft.IdentityModel.Protocols.XmlSignature.SignedXml.ComputeSignature(SecurityKey signingKey)
at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureWriter.ComputeSignature()
at Microsoft.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureWriter.OnEndRootElement()
at Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler.WriteAssertion(XmlWriter writer, SamlAssertion assertion)
at Microsoft.IdentityModel.Tokens.SecurityTokenSerializerAdapter.WriteTokenCore(XmlWriter writer, SecurityToken token)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteRSTRXml(XmlWriter writer, String elementName, Object elementValue, WSTrustSerializationContext context, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteKnownResponseElement(RequestSecurityTokenResponse rstr, XmlWriter writer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.WriteResponse(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.WriteXml(RequestSecurityTokenResponse response, XmlWriter writer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSFederation.WSFederationSerializer.GetResponseAsString(RequestSecurityTokenResponse response, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSFederation.SignInResponseMessage..ctor(Uri baseUrl, RequestSecurityTokenResponse response, WSFederationSerializer federationSerializer, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Web.FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest(SignInRequestMessage requestMessage, IPrincipal principal, SecurityTokenService sts, WSFederationSerializer federationSerializer)
at ITSV.MOAAuth.Login.LogInLogOutUser(IPrincipal user) in E:\data\pholpar\projects\MOAAuth\MOAAuth\Login.aspx.cs:line 394

When I logged in using the service account and tried to set permissions on the certificate using the Manage Private Keys… menu option, instead of the usual dialog box I received an “Object was not found” error (or something very similar).

clip_image002

The answer of Željko Tanović (answered Dec 7 ’09 at 10:52) helped me to solve the issue. The problem was that the certificate was originally imported into the user store of the developer, then it was moved into the local machine store. That means the private key was stored in the original folder, where the new (service) account could not access it.

Solution: import the certificate directly into the local machine store.

After fixing the former issue, the original error appeared again, but it was no more sporadic, but rather constant.

Based on the links above I assumed, that it was related to the user profile, that was somehow not loaded. Using this trick it was easy to confirm, that the profile of the service account was indeed not loaded.

image

Though the Load User Profile setting of the STS application pool I was able to fix the problem, I had to set the value as True, instead of the former False value.

image

The reason of why we experienced this error originally only sporadic, and not when working in the office: the developer was typically logged on into the system interactively, so his profile was loaded. But after work-hours, he was logged out, and his profile was unloaded, so the error appeared when the STS was accessed.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: