I have a common RESTful API end point that two applications are hitting - one of them is in .NET Core 3.1 and the other is in .NET Framework 4.7.2. Both are using similar code to retrieve the certificate (a PFX file), attaching that cert to an HTTP handler and then creating an HTTP Client using that handler as shown:
var currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
X509Certificate2 cert = null;
var password = new AzureKeyVault(_configuration).GetPassword(_secretUri).Result;
try
{
cert = new X509Certificate2(currentDirectory + _certName, password);
}
catch (Exception ex)
{
throw new Exception("Error trying to retrieve certificate named " + currentDirectory + _certName + " - exception was " + ex.Message);
}
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
return responseContent;
}
throw new ApplicationException($"Status code: {response.StatusCode}, Error: {response.ReasonPhrase}");
The .NET Core code works; the .NET Framework code does not. The .NET Framework gets an exception that no SSL/TLS connection could be made. Using Wireshark, I found that I am indeed using TLS 1.2 which is required for the endpoint. However, the .NET Core call has the certificate present whereas the .NET Framework call does not.
Investigating this further on the .NET Framework side, I see that the private key is not available on the Certificate. In the .NET Core code, it is available (see below).
The cert being retrieved is from the exact same directory and both are running on the exact same machine. I should also mention that the .NET Core code is a RESTful API itself; the .NET Framework code is a simple console application (thus eliminating all the permissions issues with IIS). If I do a call in the debugger's Immediate Window of 'cert.GetRSAPrivateKey()', I do get an RSA key back...so maybe the above screen shots is just a symptom of the debugger.
I am guessing that the lack of the private key on the .NET Framework side is the problem. Or maybe this has nothing to do with it - but at the end of the day, the cert is on the packet from .NET Core but not from .NET Framework using essentially the exact same code. Any thoughts on this issue would be greatly appreciated as a number of us are stumped. Thanks in advance!
EDIT #1: Below is the debugger trace output showing - what I believe - is .NET Framework concluding that there are no certs available to pick from with the request:
System.Net Information: 0 : [14200] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 12ed470:6ee7d30, targetName = xxxx.xxx.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [14200] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=CredentialsNeeded).
System.Net Information: 0 : [14200] SecureChannel#7894961 - We have user-provided certificates. The server has specified 1 issuer(s). Looking for certificates that match any of the issuers.
System.Net Information: 0 : [14200] SecureChannel#7894961 - Left with 0 client certificates to choose from.
Also here are the Wireshark entries showing certs on .NET Core calls, but not on the .NET Framework calls:
.NET Core (correct):
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 4262
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 3924
Certificates Length: 3921
Certificates (3921 bytes)
Certificate Length: 1957
Certificate: ... <removed rest for brevity>
.NET Framework (incorrect):
Transport Layer Security
TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
Content Type: Handshake (22)
Version: TLS 1.2 (0x0303)
Length: 77
Handshake Protocol: Certificate
Handshake Type: Certificate (11)
Length: 3
Certificates Length: 0

