TomSelleck
TomSelleck

Reputation: 6968

"CryptographicException: Invalid provider type specified" only in WebAPI project

I have the following code for accessing a secret in KeyVault using a certificate installed on the local machine:

static readonly string certThumbprint = "1234...";
static readonly string clientId = "1234...";

static void Main(string[] args)
{
    X509Certificate2 certificate = FindCertificateByThumbprint(certThumbprint);
    ClientAssertionCertificate assertionCert = new ClientAssertionCertificate(clientId, certificate);

    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(
            (authority, resource, scope) => GetAccessToken(authority, resource, scope, assertionCert)));


    string url = "https://myvault.vault.azure.net/";
    var result = keyVaultClient.GetSecretAsync(url, "mySecret").Result;
}

private static X509Certificate2 FindCertificateByThumbprint(string certificateThumbprint)
{
    if (certificateThumbprint == null)
    {
        throw new System.ArgumentNullException("CertificateThumbprint");
    }

    StoreLocation[] storeLocations = (StoreLocation[])Enum.GetValues(typeof(StoreLocation));

    foreach (StoreLocation location in storeLocations)
    {
        foreach (StoreName storeName in (StoreName[])
            Enum.GetValues(typeof(StoreName)))
        {
            X509Store store = new X509Store(storeName, location);

            store.Open(OpenFlags.ReadOnly);

            X509Certificate2Collection certCollection = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);

            if (certCollection != null && certCollection.Count != 0)
            {
                foreach (X509Certificate2 cert in certCollection)
                {
                    if (cert.HasPrivateKey)
                    {
                        store.Close();
                        return cert;
                    }
                }
            }
        }
    }
    throw new Exception($"Could not find the certificate with thumbprint {certificateThumbprint} in any certificate store.");
}

private static async Task<string> GetAccessToken(string authority, string resource, string scope, ClientAssertionCertificate assertionCert)
{
    Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext context = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority, TokenCache.DefaultShared);
    AuthenticationResult result = await context.AcquireTokenAsync(resource, assertionCert).ConfigureAwait(false);

    return result.AccessToken;
}

This works fine in my .Net Framework 4.7.2 console app with the following packages installed:

  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.KeyVault">
      <Version>3.0.5</Version>
    </PackageReference>
    <PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory">
      <Version>5.2.8</Version>
    </PackageReference>
    <PackageReference Include="System.Security.Cryptography.X509Certificates">
      <Version>4.3.2</Version>
    </PackageReference>
  </ItemGroup>

However, when I run the exact same code on my WebAPI project (.Net Framework 4.7.2), I get the following error:

"ClassName": "System.Security.Cryptography.CryptographicException",
"Message": "Invalid provider type specified.\r\n"

The packages I've installed are the same version according to Nuget:

<Reference Include="Microsoft.Azure.KeyVault, Version=3.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
  <HintPath>..\packages\Microsoft.Azure.KeyVault.3.0.5\lib\net461\Microsoft.Azure.KeyVault.dll</HintPath>
</Reference>
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=5.2.8.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
  <HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.5.2.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
  <HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
  <Private>True</Private>
  <Private>True</Private>
</Reference>
  

I guess that some other package is causing a conflict and resolving some incorrect version of one of the needed libraries but I'm unsure how to diagnose & resolve.

Upvotes: 1

Views: 2882

Answers (1)

Crypt32
Crypt32

Reputation: 13924

The most likely reason for this exception is that certificate's private key is stored in modern CNG Key Storage Provider rather than legacy CAPI Cryptographic Service Provider. At the moment of this response Azure Key Vault has known compatibility issues with CNG, so you should try to generate a new certificate and select legacy CAPI CSP to store key material.

Upvotes: 2

Related Questions