使用 ASP.NET Core 3.0 内置 API 从 .crt 和 .key 文件创建 X509Certificate2

Posted

技术标签:

【中文标题】使用 ASP.NET Core 3.0 内置 API 从 .crt 和 .key 文件创建 X509Certificate2【英文标题】:Create X509Certificate2 from .crt and .key files using ASP.NET Core 3.0 built-in API 【发布时间】:2020-01-04 11:09:39 【问题描述】:

我正在使用 ASP.NET Core 3.0 preview 8 开发一个 Web 应用程序。 我想要实现的是直接从 .crt 和 .key (PKCS#1) 文件创建一个 X509Certificate2,以便使用此链接中介绍的内置 Api 的新 .NET Core 3.0 将其与 Kestrel 一起使用。

What's new in .NET Core 3.0 (Preview 8)

目前我正在使用此命令将证书转换为 .pfx 文件

openssl pkcs12 -export -in $CERTIFICATE_FILE -inkey $KEY_FILE -out $OUTPUT_CERTIFICATE_FILE -passout pass:$OUTPUT_CERTIFICATE_PASSWORD

然后我创建 X509Certificate2 并将其与 Kestrel 一起使用:

webBuilder.ConfigureKestrel((context, options) =>

    options.ConfigureHttpsDefaults(httpsOptions =>
    
        if (!context.HostingEnvironment.IsProduction())
            return;

            string outputCertificateFile = context.Configuration["OUTPUT_CERTIFICATE_FILE"];
            string outputCertificatePassword = context.Configuration["OUTPUT_CERTIFICATE_PASSWORD"];

            var tlsCertificate = new X509Certificate2(outputCertificateFile, outputCertificatePassword);
            httpsOptions.ServerCertificate = tlsCertificate;
    );
);

编辑:-

我已经根据上面链接中的示例实现了新的 Api:

using (var privateKey = RSA.Create())

    byte[] keyBytes = File.ReadAllBytes(context.Configuration["KEY_FILE"]);

    privateKey.ImportRSAPrivateKey(keyBytes, out int bytesRead);

    X509Certificate2 certificateFile = new X509Certificate2(context.Configuration["CERTIFICATE_FILE"]);

    X509Certificate2 tlsCertificate = certificateFile.CopyWithPrivateKey(privateKey);

    httpsOptions.ServerCertificate = tlsCertificate;

但是新代码抛出了这个异常:

Unhandled exception. System.Security.Cryptography.CryptographicException: ASN1 corrupted data.
at System.Security.Cryptography.Asn1.AsnReader.CheckExpectedTag(Asn1Tag tag, Asn1Tag expectedTag, UniversalTagNumber tagNumber)
at System.Security.Cryptography.Asn1.AsnReader.ReadSequence(Asn1Tag expectedTag)
at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(AsnReader reader, Asn1Tag expectedTag, RSAPrivateKeyAsn& decoded)
at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(Asn1Tag expectedTag, ReadOnlyMemory`1 encoded, AsnEncodingRules ruleSet)
at System.Security.Cryptography.Asn1.RSAPrivateKeyAsn.Decode(ReadOnlyMemory`1 encoded, AsnEncodingRules ruleSet)
at System.Security.Cryptography.RSAKeyFormatHelper.FromPkcs1PrivateKey(ReadOnlyMemory`1 keyData, AlgorithmIdentifierAsn& algId, RSAParameters& ret)
at System.Security.Cryptography.RSA.ImportRSAPrivateKey(ReadOnlySpan`1 source, Int32& bytesRead)
at Example.Program.<>c__DisplayClass1_0.<CreateWebHostBuilder>b__3(HttpsConnectionAdapterOptions httpsOptions) in /src/Example/Program.cs:line 47
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.ApplyHttpsDefaults(HttpsConnectionAdapterOptions httpsOptions)
at Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(ListenOptions listenOptions, Action`1 configureOptions)
at Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(ListenOptions listenOptions)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Example.Program.Main(String[] args) in /src/Example/Program.cs:line 16

【问题讨论】:

.NET Core 3.0 应该直接支持 .crt 和 .key,***.com/questions/48077748/… 您能举个例子吗?由于提供的链接不包含任何使用新内置 API 的代码 docs.microsoft.com/en-us/dotnet/core/whats-new/… 我已经实现了链接中的示例,不幸的是它没有工作。我已经用异常详细信息@LexLi 更新了问题 @Waxren 有更新吗?我们也有这个问题。 【参考方案1】:

以下内容应将 PEM 编码的证书和密钥文件加载到 Kestral 中:

public static IHostBuilder CreateHostBuilder(string[] args)

    return Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        
            webBuilder.ConfigureKestrel(serverOptions =>
            
                serverOptions.ConfigureHttpsDefaults(listenOptions =>
                
                    using var privateKey = RSA.Create();
                    privateKey.ImportRSAPrivateKey(
                        PemBytes(pemKeyFile), out var bytesRead);
                    X509Certificate2 certificate = 
                        new X509Certificate2(PemBytes(pemCertFile));
                    listenOptions.ServerCertificate = 
                        certificate.CopyWithPrivateKey(privateKey);
                );
            );
            webBuilder.UseStartup<Startup>();
        );


public static byte[] PemBytes(string fileName) => 
    Convert.FromBase64String(
        File.ReadAllLines(fileName)
            .Where(l => !l.Contains('-'))
            .Aggregate("", (current, next) => current + next));

【讨论】:

以上是关于使用 ASP.NET Core 3.0 内置 API 从 .crt 和 .key 文件创建 X509Certificate2的主要内容,如果未能解决你的问题,请参考以下文章

.NET Core 3.0及ASP.NET Core 3.0 前瞻

将 OpenID Connect 与 .NET Core 3.0 ASP.NET Core API 服务一起使用时出错

深入研究 Angular 和 ASP.NET Core 3.0

Linq 查询在 ASP.NET-Core 3.0 及更高版本中对数字等字符串进行排序

这是如何使用 Entity Framework Core 和 ASP.NET Core MVC 2.2+ 和 3.0 创建数据传输对象 (DTO)

属性路由在 asp.net core 3.0 中无法正常工作