TLS exceptions in UCMA services-tracking down the issue

I ran into an issue today that was baffling me for a couple of hours.  I had a UCMA service that worked fine on one machine, but when a colleague set it up on another machine, I got the dreaded “Microsoft.Rtc.Internal.Sip.TLSException: CertificateInfoNative::AcquireCredentialsHandle() failed;”, which basically means that you don’t have access to the certificate.  The strange thing was, the certificate checked out, it was in the local machine store, and the service was installed and running as Local System.  It also worked if I changed the service to run as the logged in user, which meant it had to be a permission issue, but Local System has access to everything, right?

As it turns out, some digging led to a fairly simple root cause.  If you install a certificate using web enrollment, it automatically installs to the current user store.  You can just launch the MMC and copy/paste the certificate from one store to another after that-after all, this works fine for root CA certs, right?  Well, in this case, the certificate will definitely be there in the local machine store, and your app will be able to see it in the local machine store, but the private key will still be in the current user’s application data directory. 

To figure this out, try this piece of code:

private static X509Certificate2 GetLocalCertificate()
{
    //6B8F3E0E000000000040
    X509Store store = new X509Store(StoreLocation.LocalMachine);

    store.Open(OpenFlags.ReadOnly);

    X509Certificate2Collection certificates = store.Certificates;

    foreach (X509Certificate2 certificate in certificates)
    {
        //look up a specific cert from the right CA
        if (certificate.SerialNumber == "6B8F3E0E000000000040")
        {
            RSACryptoServiceProvider rsa = certificate.PrivateKey as RSACryptoServiceProvider;
            string keyFile = rsa.CspKeyContainerInfo.UniqueKeyContainerName;
            Console.WriteLine("Private Key is in file name: " + keyFile);
            return certificate;
        }
    }
    return null;
}

Of course, you’ll probably want to put in the serial number of your certificate.  This will find the matching cert, but will also spit out the filename of the private key, which is stored in one of two places (in Server 2003 at least).  For the current user it’s a subdirectory of %appdata%\Microsoft\Crypto\RSA\, and for the local machine it’s something like C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys.  If the cert is in the local machine store, but the key is still in the current user’s appdata, then no other accounts will be able to access that private key (unless you change the ACLs on the current user’s appdata that is). 

The solution is pretty simple if you have a cert like this.  Right click the cert in the MMC, export it (with the private key) to a pfx file, and import it again, this time directly into the local machine store.  Now, if you verify, the private key should be in the MachineKeys directory, and not under the current user’s appdata, and your UCMA service should work again. 

Advertisements
This entry was posted in Uncategorized. 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 )

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