Using IdentityModel: Simplifying Calculation of Information Card Unique IDs in WCF

The key to information card backed systems is calculating a stable unique identifier for your users based on the card claims. Typically this is done by hashing the issuer public key (plus some other information like a PPID for managed cards).

This involves the following steps:

  • Find the issuer claim set containing the issuer RSA key
  • Optionally find some other claims (e.g. a PPID)
  • Create a hash from that pieces of information

In LeastPrivilege.IdentityModel I added some helper extension methods to simplify this process. The first one extends the RSACryptoServiceProvider class and allows calculating the hash the from the key (plus optional extra information):

public static class RSAExtensions
{
    public static byte[] GetKeyHash(this RSACryptoServiceProvider rsa)
    {
        return rsa.GetKeyHash(string.Empty);
    }

    public static byte[] GetKeyHash(this RSACryptoServiceProvider rsa, string entropy)
    {
        int entropyLength = Encoding.UTF8.GetByteCount(entropy);
        RSAParameters rsaParams = rsa.ExportParameters(false);
        byte[] shaInput;
        byte[] shaOutput;

        int i = 0;
        shaInput = new byte[rsaParams.Modulus.Length +
          rsaParams.Exponent.Length + entropyLength];
        rsaParams.Modulus.CopyTo(shaInput, i);
        i += rsaParams.Modulus.Length;
        rsaParams.Exponent.CopyTo(shaInput, i);
        i += rsaParams.Exponent.Length;
        i += Encoding.UTF8.GetBytes(entropy, 0, entropy.Length, shaInput, i);

        using (SHA256 sha = SHA256.Create())
        {
            shaOutput = sha.ComputeHash(shaInput);
        }

        return shaOutput;
    }
}

 

I use the same algorithm here as in Microsoft’s Token class for ASP.NET. This makes it easy to share the IDs between ASP.NET and other application types.

Another helper extends IEnumerable<ClaimSet> and simplifies retrieving the RSA claim:

public static RSACryptoServiceProvider FindIssuerRsaClaim(
  this IEnumerable<ClaimSet> claimSets)
{
    return claimSets.FindClaim(
        ClaimTypes.Rsa,
        ClaimSearchMode.Issuer).Get<RSACryptoServiceProvider>();
}

 

With these helpers you can retrieve the unique ID by using this code:

AuthorizationContext context =
    ServiceSecurityContext.Current.AuthorizationContext;
byte[] uniqueId = context.ClaimSets.FindIssuerRsaClaim().GetKeyHash();

This entry was posted in IdentityModel, WCF. Bookmark the permalink.

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 )

Facebook photo

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

Connecting to %s