根据此文档,我尝试在作为 Windows 服务运行的 net5 ASP.NET 实现中使用安装在本地计算机上的证书: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-5.0#listenoptionsusehttps
具体来说,我指的是这个配置片段:
"HttpsInlineCertStore": {
"Url": "https://localhost:5003",
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
我很挣扎,因为该文档缺乏参数所有值的描述。
所以我最终得到了这个:
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:7000"
},
"Https": {
"Url": "https://0.0.0.0:7001",
"Certificate": {
"Subject": "value-of-CN-parameter-of-subject-field",
"Store": "My",
"Location": "LocalMachine"
}
}
}
}
但是不起作用:
[15:53:59 FTL] Unable to start Kestrel.
System.InvalidOperationException: The requested certificate value-of-CN-parameter-of-subject-field could not be found in LocalMachine/My with AllowInvalid setting: False.
at Microsoft.AspNetCore.Server.Kestrel.Https.CertificateLoader.LoadFromStoreCert(String subject, String storeName, StoreLocation storeLocation, Boolean allowInvalid)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Certificates.CertificateConfigLoader.LoadFromStoreCert(CertificateConfig certInfo)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Certificates.CertificateConfigLoader.LoadCertificate(CertificateConfig certInfo, String endpointName)
at Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader.Reload()
at Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader.Load()
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
我检查了以下提到的需要的几点:
Server Authentication (1.3.6.1.5.5.7.3.1)
和 Client Authentication (1.3.6.1.5.5.7.3.2)
从证书的
Subject
字段,我尝试了所有变体:
CN
参数的值CN=value
通过
*.pfx
文件指定证书可以正常工作。那么访问本地安装的证书出了什么问题呢?
注意:这个答案https://stackoverflow.com/a/65958649/2477582提到了
1.3.6.1.4.1.311.84.1.1
扩展,但根据引用的源代码,这仅适用于开发证书。
我正在尝试设置生产环境。
我的应用程序有所不同,但这可能会对您有所帮助。我需要通过 Visual Studio 启动配置文件使用自定义 DNS 名称和自定义证书通过 Kestrel 运行 graphql 服务。这对我有用。
几个要点:
CertificateLoader.LoadFromStoreCert
。此API将NOT找到不满足以下条件的证书:(它不会给出警告或反馈,只是简单地返回null。oof)pkcs12
格式导入证书。 (.pfx
文件扩展名)您将看到包含私钥的证书的特殊图标。CertificateLoader.LoadFromStoreCert
文档提到它搜索证书“主题”,据我所知,这不是一个东西或标准术语。它实际上搜索证书的专有名称,该名称由一堆单独的键/值对组成。将专有名称下的 description
或 commonName
字段设置为对您的特定证书 100% 唯一的内容即可。C:\Windows\System32\drivers tc\hosts
127.0.0.1 local.whatever.io
127.0.0.1 local.admin.whatever.io
属性/launchSettings.json
{
"profiles": {
"Whatever.GraphQL": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "graphql",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
},
"dotnetRunMessages": true,
"applicationUrl": "https://local.whatever.io:36305"
}
}
appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Kestrel": {
"Certificates": {
"Default": {
// if you don't import your .pfx into the Windows Certificate Store you could just load it from disk here. the major 3 browsers will likely NOT trust your certificate, which is why importing it into the LocalMachine\Root store is recommended.
//"Path": "<path to .pfx file>",
//"Password": "$CREDENTIAL_PLACEHOLDER$"
"Subject": "Whatever Localhost Certificate V1",
"Store": "Root",
"Location": "LocalMachine",
"AllowInvalid": true
}
}
}
}
证书生成/配置以及破译它们周围的“标准”非常复杂,因此这里跳过大部分复杂性。我为 localhost 开发创建了一个 powershell 脚本,该脚本生成根证书颁发机构,将其导入 Windows 证书存储区,使用以下文本作为示例生成用于 localhost 开发的证书签名请求 (CSR),然后使用根证书颁发机构生成这些文件:
localhost.crt
、localhost.key
和 localhost.pfx
。然后可以将 .pfx
导入到 Windows 证书存储中,然后由 Kestrel 使用。在 docker 中,您可以将 .crt
和 .key
用于 traefik 或 nginx 或您设置的任何代理服务(如果还需要)。
您可以使用
openssl
使用此配置生成证书。
您需要已经生成根证书颁发机构证书 (rootCA.crt) 和私钥 (rootCA.key),并将其导入到证书存储中。
// create certificate signing request (.csr) and .key based on config
oppenssl req -new -sha256 -nodes -out localhost.csr -newkey rsa:4096 -keyout localhost.key -config localhost.conf -extensions v3_req
// sign the .csr using the root CA cert to generate localhost.crt
oppenssl x509 -req -in localhost.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out localhost.crt -days 3600 -sha256 -extfile localhost.conf -extensions v3_req
// append full certificate chain to the .crt for all browsers/proxies/all-the-things
rootCA.crt >> localhost.crt
// convert to .pfx format so we have the cert and key in one format
oppenssl pkcs12 -inkey localhost.key -in localhost.crt -export -out localhost.pfx
// import .pfx into store. you now have the cert and key in the certificate store that Kestrel will find
Import-PfxCertificate -FilePath "localhost.pfx" -CertStoreLocation cert:\LocalMachine\Root -Password (ConvertTo-SecureString $standardPassword -AsPlainText -Force)
localhost.conf
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
serial = 12345678
authorityKeyIdentifier = keyid, issuer
[req_distinguished_name]
countryName = US
stateOrProvinceName = TX
localityName = Austin
organizationName = Whatever LLC
description = Whatever Localhost Certificate V1
name = Whatever Localhost Certificate V1
commonName = Whatever Localhost Certificate V1
businessCategory = Ecommerce
owner = Indiana Jones
emailAddress = [email protected]
serialNumber = 12345678
streetAddress = 1234 Wherever Lane
postalCode = 78758
jurisdictionLocalityName = Austin
jurisdictionStateOrProvinceName = TX
jurisdictionCountryName = US
[v3_req]
basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, nonRepudiation, keyEncipherment, keyAgreement, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth, codeSigning, timeStamping, emailProtection
subjectAltName = @alt_names
[alt_names]
# add as many wildcards or non-wildcards as you want. just make sure to always increment the number
# note: every sub-level of a domain requires a wildcard
DNS.1 = *.whatever.io
DNS.2 = *.admin.whatever.io
DNS.3 = *.funtimes.whatever.io
# adding the current machine's full list of IPV4 & IPV6 ips, as well as the usual loopback adapters
IP.1 = 172.19.16.1
IP.2 = 172.20.224.1
IP.3 = 172.24.80.1
IP.4 = 172.30.64.1
IP.5 = 172.30.80.1
IP.6 = 192.168.56.1
IP.7 = 192.168.88.59
IP.8 = 0.0.0.0
IP.9 = 127.0.0.1
IP.10 = ::
IP.11 = ::1
IP.12 = FE80:0000:0000:0000:177B:3CA1:44E3:0000
IP.13 = FE80:0000:0000:0000:53AF:9CDB:A86D:0000
IP.14 = FE80:0000:0000:0000:592B:C5D5:30A0:0000
IP.15 = FE80:0000:0000:0000:86D2:F50A:E0C8:0000
IP.16 = FE80:0000:0000:0000:C08A:C61F:10DF:0000
IP.17 = FE80:0000:0000:0000:D2C2:A734:A360:0000
IP.18 = FE80:0000:0000:0000:EC80:EB1F:C21D:0000