RSACryptoServiceProvider, Impersonation, and Ephemeral Keys
If you construct an RSACryptoServiceProvider class without specifying a name for the key, the CLR will create a randomephemeral key for you. However, ephemeral keys are not supported by the underlying CAPI APIs on all of the platforms that the CLR was built to support, so the RSACryptoServiceProvider will attempt to fake this behavior.
It does this by generating a random name for a key, saving the key in that named container, and then when the RSACryptoServiceProvider instance is disposed, deleting the key. Generally this works well, but when impersonation gets thrown into the mix, things can go awry.
Imagine this scenario:
- Create a new, random RSA key
- Impersonate another user
- Use the key
- Dispose the key
In this case, the key was created in the profile of one user, and when it is disposed we're running in the context of a different user. When the dispose is attempts to delete the key, we run into an issue. Namely, the new user probably doesn't have permission to delete keys in the old user's profile.
The solution here is to make sure that you create and dispose of ephemeral keys while running in the same user context. Another solution is to name the key yourself, instead of letting the CLR generate a random name. If you've given the key a name the CLR will not attempt to delete the key when the RSACryptoServiceProvider class is disposed -- you can then take care of deleting the key yourself at a later time.
That scenario is pretty straight forward, but you can get bit by this issue in another, more subtle way. Lets say that you fix the above pattern in your code and now you impersonate before creating the RSA key. However, your code does not dispose the RSACryptoServiceProvider object, and instead waits for the GC to collect it for cleanup to occur.
When the GC is ready to collect the object, it will notice that it needs to be finalized, and run the finalizer -- on a separate thread from where you created the object. This thread will not be impersonating, and you run into the same problem. This is very similar to problems that Nicole Calinoiu mentioned in her blog post about impersonation and finalization earlier this year.
In order to avoid these problems all together, the safest pattern to use when combining ephemeral keys with impersonation is:
- Impersonate
- Create the key
- Use the key
- Dispose of the key
- Undo the impersonation
Comments
- Anonymous
September 22, 2006
I was casually reading this blog entry via my normal RSS feed, while trying to debug a seemingly unsurmountable problem in my code. Then, suddenly I counted 1+1=2 and realized that this article I was reading by pure coincidence was exactly the solution to my problem! The finalizer thread turned out to be running as the non-impersonated user, thus not being able to delete the ephemeral key. Thanks guys, you saved my day.