来自 ASP.NET Windows 服务应用程序中本地存储的证书

问题描述 投票:0回答:1

根据此文档,我尝试在作为 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)

我检查了以下提到的需要的几点:

  1. 证书有私钥
  2. 证书具有增强的密钥用法
    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
  • 以 CSV 形式完成主题

通过

*.pfx
文件指定证书可以正常工作。那么访问本地安装的证书出了什么问题呢?

注意:这个答案https://stackoverflow.com/a/65958649/2477582提到了

1.3.6.1.4.1.311.84.1.1
扩展,但根据引用的源代码,这仅适用于开发证书。

我正在尝试设置生产环境。

c# asp.net-core certificate .net-5
1个回答
2
投票

我的应用程序有所不同,但这可能会对您有所帮助。我需要通过 Visual Studio 启动配置文件使用自定义 DNS 名称和自定义证书通过 Kestrel 运行 graphql 服务。这对我有用。

几个要点:

  • Kestrel 在幕后使用
    CertificateLoader.LoadFromStoreCert
    。此API将NOT找到不满足以下条件的证书:(它不会给出警告或反馈,只是简单地返回null。oof)
  • 证书必须在 Windows 证书存储区中具有私钥。据我所知,执行此操作的唯一方法是以
    pkcs12
    格式导入证书。 (
    .pfx
    文件扩展名)您将看到包含私钥的证书的特殊图标。
  • 在查看存储中包含其私钥的证书时,您也会看到此消息。
  • CertificateLoader.LoadFromStoreCert
    文档提到它搜索证书“主题”,据我所知,这不是一个东西或标准术语。它实际上搜索证书的专有名称,该名称由一堆单独的键/值对组成。将专有名称下的
    description
    commonName
    字段设置为对您的特定证书 100% 唯一的内容即可。
  1. 这样我们就可以在本地获得自定义的 DNS 名称。

C:\Windows\System32\drivers tc\hosts

127.0.0.1 local.whatever.io
127.0.0.1 local.admin.whatever.io
  1. 在启动配置文件中设置我们的自定义 DNS 名称以及我们要在 kestrel 中使用的端口

属性/launchSettings.json

{
  "profiles": {
    "Whatever.GraphQL": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "graphql",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
      },
      "dotnetRunMessages": true,
      "applicationUrl": "https://local.whatever.io:36305"
    }
}
  1. 告诉 Kestrel 如何在 Windows 证书存储中找到我们想要的证书

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
用于 traefiknginx 或您设置的任何代理服务(如果还需要)。

您可以使用

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
© www.soinside.com 2019 - 2024. All rights reserved.