STS and Relying Party Encryption Setup

Jul 25, 2011 at 1:16 PM

I am stumped and hope someone here can add some clarity. 

I have written a custom STS.  I have written a separate, simple Relying Party that outputs the claims of the STS.  It works on my local machine.  I can make it work if I deploy the STS and RP to the same server.  However, trying to run an RP from my dev box, hitting the dev server, I get ID4036 errors (ID4036: The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier '<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /></e:EncryptionMethod><KeyInfo><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><X509Data><X509IssuerSerial><X509IssuerName>CN=Cin1Web07-Dev.paycor-test.com</X509IssuerName><X509SerialNumber>116108771XXXXXX3182074711</X509SerialNumber></X509IssuerSerial></X509Data></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>bOkGGQaGymVHZXc9v8AsLyx/Qiy0fhmKKu88BVinXvx4ySzBMqmb1IiY7DSFAXR1PeFevfTxmzmZwu1ztPyJWpNV0LzKnVbxrqChH7iREfYhp5EHUzF0tCdJ49Q/XL3laN/Nh971hxPzj0rBQIIJ8bK/vW70x6gCkIj4Wy50Qow=</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo>'. Ensure that the SecurityTokenResolver is populated with the required key)

I've tried finding answers in the Claims Guide and Programming WIF books, but no luck.  Also, I found this site: http://consultingblogs.emc.com/simonevans/archive/2010/11/19/common-windows-identity-foundation-ws-federation-exceptions-explained.aspx  but it doesn't get me further either.

If anyone has any troubleshooting tips, or ideas, I would appreciate.  Here are my details of what I'm doing:

The STS signs the certificate with a simple cn=LocalHost, this is set here:

    public static MetadataBase GetFederationMetadata()
    {
        string endpointId = WebConfigurationManager.AppSettings["ActiveSTSUrl"];
        EntityDescriptor metadata = new EntityDescriptor();
        metadata.EntityId = new EntityId(endpointId);

        // Define the signing key
        X509Certificate2 cert = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, GetCertificateNameForSigningMetadata());
        metadata.SigningCredentials = new X509SigningCredentials(cert);

        // Create role descriptor for security token service
        SecurityTokenServiceDescriptor stsRole = new SecurityTokenServiceDescriptor();
        stsRole.ProtocolsSupported.Add(new Uri(WSFederationMetadataConstants.Namespace));
        metadata.RoleDescriptors.Add(stsRole);

        // Add a contact name
        ContactPerson person = new ContactPerson(ContactType.Administrative);
        person.GivenName = "contactName";
        stsRole.Contacts.Add(person);

        // Include key identifier for signing key in metadata
        SecurityKeyIdentifierClause clause = new X509RawDataKeyIdentifierClause(cert);
        SecurityKeyIdentifier ski = new SecurityKeyIdentifier(clause);
        KeyDescriptor signingKey = new KeyDescriptor(ski);
        signingKey.Use = KeyType.Signing;
        stsRole.Keys.Add(signingKey);

        // Add endpoints
        string activeSTSUrl = WebConfigurationManager.AppSettings["ActiveSTSUrl"];
        EndpointAddress endpointAddress = new EndpointAddress(new Uri(activeSTSUrl),
                                                    null,
                                                    null, GetMetadataReader(activeSTSUrl), null);
        stsRole.SecurityTokenServiceEndpoints.Add(endpointAddress);

        ExposeClaimTypesOffered(stsRole);

        return metadata;
    }

and set here:

    public MembershipSTSConfiguration() : base()
    {
        X509Certificate2 signingCert = CertificateUtil.GetCertificate(
            StoreName.My,
            StoreLocation.LocalMachine,
            Common.GetCertificateNameForSigningMetadata());

        this.SigningCredentials = new X509SigningCredentials(signingCert);
        this.SecurityTokenService = typeof(MembershipSTS);
        this.TokenIssuerName = "MembershipSTS";
    }

I called the method GetCertificateNameForSigningMetadata, but my understanding is that this also signs the token.

In my RP, I have this section - and the thumbprint matches the thumbprint of the cn=localhost from the STS server:

 

      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="A6F68xxxxxxxx575EBDC" name="http://cin1web07-dev.paycor-test.com:8080/PaycorAuthServices/PassiveSTS.aspx" />
        </trustedIssuers>
      </issuerNameRegistry>

 

I believe that is all configured correctly.  However, the encryption part is where I think there is a problem.  This is in the RP's web.config.  The Thumbprint below references a certificate called RelyingParty.MyOrg. 

 

      <serviceCertificate>
        <certificateReference x509FindType="FindByThumbprint" findValue="AA310FF423XXXXXXXX910F9C69" storeLocation="LocalMachine" storeName="My" />
      </serviceCertificate>

The certificate is installed on my development machine (the RP) along with the private key.  The Certificate Authority also exists on my machine.  I exported the certificate to the dev server and the CA cert.  They seem to be setup correctly.  In the GetScope of the STS, I have this:

    protected override Scope GetScope(IClaimsPrincipal principal, RequestSecurityToken request)
    {
        Scope scope = new Scope(request.AppliesTo.Uri.AbsoluteUri, SecurityTokenServiceConfiguration.SigningCredentials);
        scope.EncryptingCredentials = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine,
                    System.Configuration.ConfigurationManager.AppSettings["CertificateNameForEncryptingToken"]));

        scope.ReplyToAddress = scope.AppliesToAddress + "/Default.aspx";
        return scope;
    }

The AppSetting maps to cn=RelyingParty.MyOrg, and is finding the certificate I believe (because if I change 1 letter, I get a different 'can't find cert' error).

Despite all this, I get the ID4036 on my dev box when I use the STS.

Here is the part that REALLY stumps me - after changing to the RelyingParty.MyOrg cert, the RP on the dev server still works - even though it is set to the old cn=localhost and does not have the private key for the cn=RelyingParty.MyOrg.

So clearly, I do not understand some of this config.  I apologize for the lengthy post, but I am really getting desperate to wrap this up.  If anyone has any suggestions, I would greatly appreciate it.

ID4036: The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier '<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /></e:EncryptionMethod><KeyInfo><o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><X509Data><X509IssuerSerial><X509IssuerName>CN=Cin1Web07-Dev.paycor-test.com</X509IssuerName><X509SerialNumber>116108771798210860686154714333182074711</X509SerialNumber></X509IssuerSerial></X509Data></o:SecurityTokenReference></KeyInfo><e:CipherData><e:CipherValue>bOkGGQaGymVHZXc9v8AsLyx/Qiy0fhmKKu88BVinXvx4ySzBMqmb1IiY7DSFAXR1PeFevfTxmzmZwu1ztPyJWpNV0LzKnVbxrqChH7iREfYhp5EHUzF0tCdJ49Q/XL3laN/Nh971hxPzj0rBQIIJ8bK/vW70x6gCkIj4Wy50Qow=</e:CipherValue></e:CipherData></e:EncryptedKey></KeyInfo>'. Ensure that the SecurityTokenResolver is populated with the required key.

Jul 25, 2011 at 7:40 PM

Nevermind... after a great deal of time, this was actually related to configuration of other legacy apps.  It's a long story and I am surprised this ever worked even locally.