Home > Software design >  Loading X509Certificate2 from pem file. Results in No credentials are available when used as a Clien
Loading X509Certificate2 from pem file. Results in No credentials are available when used as a Clien

Time:05-05

I need to make a request to a server. This request requires a certificate in order to access the server.

If I load the P12 file and and register it as a certificate on my http Client. It works fine.

var clientCertificate = new X509Certificate2(pathToTestCert, passToTestCert);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate );

However if i use CreateFromPemFile to load the certificate from a pem file.

var clientCertificate= X509Certificate2.CreateFromPemFile(purePem);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(clientCertificate);

I get when sending the request to the server.

System.IO.IOException: The read operation failed, see inner exception.
 ---> System.ComponentModel.Win32Exception (0x8009030E): No credentials are available in the security package
   at System.Net.SSPIWrapper.AcquireCredentialsHandle(ISSPIInterface secModule, String package, CredentialUse intent, SCH_CREDENTIALS* scc)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCH_CREDENTIALS* secureCredential)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandleSchCredentials(X509Certificate2 certificate, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(SslStreamCertificateContext certificateContext, SslProtocols protocols, EncryptionPolicy policy, Boolean isServer)
   at System.Net.Security.SecureChannel.AcquireClientCredentials(Byte[]& thumbPrint)
   at System.Net.Security.SecureChannel.GenerateToken(ReadOnlySpan`1 inputBuffer, Byte[]& output)
   at System.Net.Security.SecureChannel.NextMessage(ReadOnlySpan`1 incomingBuffer)
   at System.Net.Security.SslStream.ProcessBlob(Int32 frameSize)
   at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Net.Security.SslStream.ReplyOnReAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Byte[] buffer)
   at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
   --- End of inner exception stack trace ---
   at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
   at System.Net.Http.HttpConnection.InitialFillAsync(Boolean async)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken
        

Note a pem file looks like this if opened in a text editor.

-----BEGIN PRIVATE KEY-----
.
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
................
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
.................
-----END CERTIFICATE-----

CodePudding user response:

The TLS layer on Windows requires that the private key be written to disk (in a particular way). The PEM-based certificate loading doesn't do that, only PFX-loading does.

The easiest way to make the TLS layer happy is to do

cert = new X509Certificate2(cert.Export(X509ContentType.Pfx));

That is, export the cert key to a PFX, then import it again immediately (to get the side effect of the key being (temporarily) written to disk in a way that SChannel can find it). You shouldn't need to bother with changing the PFX load flags off of the defaults, though some complicatedly constrained users might need to use MachineKeySet.

  • Related