.NET 6中HttpClient附加PEM证书发起请求失败的问题求助
.NET 6中HttpClient附加PEM证书发起请求失败的问题求助
我最近在ASP.NET Core 6应用里遇到一个棘手的问题:需要向一个HTTPS保护的接口发送请求,必须附加带私钥的PEM证书,但怎么都搞不定,想请教大家帮忙看看!
证书文件情况
我有两个证书相关文件:
mtls.pem:包含3个连续的证书块,结构如下:
-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----
(上述结构重复3次)
mtls.key:标准的RSA私钥文件,结构如下:
-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----
我当前的HttpClient配置代码
我在依赖注入中注册HttpClient时,手动添加证书,代码如下:
services.AddHttpClient<IIntegrationClient, IntegrationClient>() .ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual }; var path = Path.Combine(environment.ContentRootPath, "Certificates"); var certificate = X509Certificate2.CreateFromPemFile( Path.Combine(path, "mtls.pem"), Path.Combine(path, "mtls.key")); handler.ClientCertificates.Add(certificate); return handler; });
遇到的异常
当调用httpClient.SendAsync(request)时,抛出了SSL连接失败的异常,核心错误是Win32Exception (0x8009030E): No credentials are available in the security package,完整的异常堆栈如下:
Unhandled exception. System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: Authentication 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(SslAuthenticationOptions authOptions) at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) --- End of inner exception stack trace --- at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) at System.Net.Security.SslStream.AcquireCredentialsHandle(SslAuthenticationOptions sslAuthenticationOptions) at System.Net.Security.SslStream.AcquireClientCredentials(Byte[]& thumbPrint) at System.Net.Security.SslStream.GenerateToken(ReadOnlySpan`1 inputBuffer, Byte[]& output) at System.Net.Security.SslStream.NextMessage(ReadOnlySpan`1 incomingBuffer) at System.Net.Security.SslStream.ProcessBlob(Int32 frameSize) at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](CancellationToken cancellationToken) at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken) at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(QueueItem queueItem) at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.HttpConnectionWaiter`1.WaitForConnectionAsync(Boolean async, CancellationToken requestCancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) ...
我尝试过的解决方法
- 转换证书为PFX格式:看到有建议说转成PFX能解决问题,我修改了代码:
var certificate = X509Certificate2.CreateFromPemFile( Path.Combine(path, "mtls.pem"), Path.Combine(path, "mtls.key")); certificate = new X509Certificate2(certificate.Export(X509ContentType.Pfx));
修改后不再抛出异常,但目标接口返回400 Bad Request - The SSL certificate error,证书还是不被认可。
- 控制台应用POC测试:用同样的.NET 6版本写了一个控制台应用做测试,结果和Web应用完全一致,还是遇到相同的问题。
- Node.js+axios测试:用Node.js写了一个简单的测试程序,通过
httpsAgent附加证书后请求成功了,这说明我的证书本身是有效的,问题应该出在.NET的处理上。
我的应用环境是ASP.NET Core 6,运行在Windows 10系统上,实在找不到问题所在了,希望大家能给点思路!
备注:内容来源于stack exchange,提问作者mmvidal
相关产品推荐
相关产品推荐

