You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 07:18:01