Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET核心X509Certificate2的使用(在Windows/IIS、Docker和Linux下)_C#_Identityserver4_Asp.net Core 2.1_X509certificate2_.net Core 2.1 - Fatal编程技术网

C# .NET核心X509Certificate2的使用(在Windows/IIS、Docker和Linux下)

C# .NET核心X509Certificate2的使用(在Windows/IIS、Docker和Linux下),c#,identityserver4,asp.net-core-2.1,x509certificate2,.net-core-2.1,C#,Identityserver4,Asp.net Core 2.1,X509certificate2,.net Core 2.1,我真的花了很长时间在.NET核心API中使用证书 基本上,我需要在IIS和docker上运行的.NET核心web api中使用它们 我需要使用的证书用于: 注意:此代码从VS2017开始在开发人员计算机上工作,但在Windows 2008 R2 IIS测试服务器上引发这些异常 services.AddIdentityServer() .AddSigningCredential ( new X509Certificate2(tokenCertificatePath, toke

我真的花了很长时间在.NET核心API中使用证书

基本上,我需要在IIS和docker上运行的.NET核心web api中使用它们

我需要使用的证书用于:

注意:此代码从VS2017开始在开发人员计算机上工作,但在Windows 2008 R2 IIS测试服务器上引发这些异常

services.AddIdentityServer()
  .AddSigningCredential
  (
    new X509Certificate2(tokenCertificatePath, tokenCertificatePassphrase)
  )
  // other setup
  ;
这三种方法都意味着放置一个证书文件,使用构造函数加载它,传递秘密,然后开始

sarkasm>让我高兴,这太容易了萨尔卡斯姆

所以我创建了一个certs子目录来保存证书。为机密添加了设置。已验证是否按预期加载/创建了所有值。已验证文件是否位于预期位置,是否存在。简言之:

string dataProtectionKeystorePath = System.Path.Combine(Environment.ContentRootPath, "keystore");
string dataProtectionCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "keystore.pfx");
string dataProtectionSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("keystoreSecret", null);

string tokenCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "token.pfx");
string tokenCertificateSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("tokenSecret", null);

string sslCertificatePath = System.Path.Combine(Environment.ContentRootPath, "certs", "ssl.pfx");
string sslCertificateSecret = Configuration.GetSection("CertificateSecrets").GetValue<string>("tokenSecret", null);
SSL证书的异常

Unhandled Exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at AuthServer.Program.<>c.<BuildWebHost>b__1_3(ListenOptions listenOptions) in [intentionally removed for post]\Program.cs:line 58
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.Listen(IPEndPoint endPoint, Action`1 configure)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions.Listen(IPAddress address, Int32 port, Action`1 configure)
   at Microsoft.Extensions.Options.ConfigureNamedOptions`1.Configure(String name, TOptions options)
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
   at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
   at System.Lazy`1.CreateValue()
   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
   at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
   at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.CreateServiceContext(IOptions`1 options, ILoggerFactory loggerFactory)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer..ctor(IOptions`1 options, ITransportFactory transportFactory, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitSingleton(SingletonCallSite singletonCallSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureServer()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   at Microsoft.AspNetCore.Hosting.Internal.WebHost.StartAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token, String shutdownMessage)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token)
   at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
   at MyProject.Program.Main(String[] args) in [intentionally removed for post]\Program.cs:line 47
我是否确定密码正确:是,否则会出现异常

System.Security.Cryptography.CryptographicException: System cannot find specified file.
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: The specified network password is not correct.
文件权限:感谢CheshireCat提醒我。在Windows Server 2008 R2 IIS 7.5上,我检查了用户DefaultAppPool对certs子目录的文件权限(认为它现在是另一个用户unitl)。已将证书子目录的完全访问文件权限授予用户DefaultAppPool

通常IS4签名凭据异常发生在应用程序启动时。使用X509KeystrageFlags.MachineKeySet不会在启动时抛出,但会显示登录窗口并在登录后抛出。不会返回任何令牌,但会创建一个会话,以便用户可以修改ASP NET标识帐户设置

证书过期:证书可能过期。数据保护似乎没有检查过期日期,因此证书即使在过期后也可以使用。仍然可以使用Identity Server 4签名凭据,但如果证书过期,ASP.NET核心令牌验证将引发未经授权的问题


问题解决方案 一年半后,解决方案是:一个不知何故损坏的(自签名/自创建的)证书

如果可以使用此代码检查证书是否有效:

  static void Main(string[] args)
  {
    X509Certificate2 cert = new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "cert.pfx"), "password");
    Console.WriteLine("cert private key: " + cert.PrivateKey);
  }
如果您看到以下输出,则证书是良好的,否则您将获得如上所述的异常

cert private key: System.Security.Cryptography.RSACng
创建发展证书 SSL证书 使用dotnet工具devcerts。此调用打开提示,然后将localhost SSL证书导入CurrentUser证书存储()。不需要在程序中更改代码

dotnet dev-certs https --trust
其他证书 已创建“损坏”证书。我切换到,但也可以使用工具(如果您使用Win 10)

如果OpenSSL安装正确并添加到PATH变量,则以下批处理文件将创建工作证书(需要用户交互!)

本地开发的设置(Win 7,VS 2017,IIS Express/Kestrel) 正如柴郡猫(再次表示感谢)所描述的.NETCore2.1下所有部件工作的代码一样。包括数据保护和Identity Server 4签名凭据


在Windows 2008 R2上部署到IIS 7.5 乐趣还在继续。让证书在本地开发计算机上工作并将其部署到IIS会引发“新”异常

  • 已检查IIS上的文件权限(DefaultAppPool具有完全权限)
  • 证书与在本地计算机上工作的证书相同
  • 未安装使用的证书(不在开发计算机上,也不在IIS计算机上),因此应获取实际文件
日志显示基本良好的设置

  using data protection keystore path C:\inetpub\wwwroot\auth\keystore
  data protection keystore is protected with certificate at path 'C:\inetpub\wwwroot\auth\certs\keystore.pfx'
  loading keystore certificate from file 'C:\inetpub\wwwroot\auth\certs\keystore.pfx'
  loading keystore certificate with passphrase ********
参考行57为:

  cert = new X509Certificate2(certPath, certPassphrase);
Identity Server 4签名凭据也会发生相同的异常

再给我100英镑,让我在WindowsServer2008R2的IIS上运行

IIS和docker解决方案(以及本地开发):使用此解决方案,IIS和docker安装程序都不会抱怨:

cert = new X509Certificate2(certPath, certPassphrase, X509KeyStorageFlags.MachineKeySet);

我在IS4项目上运行的实际代码如下:

X509Certificate2 certificate = null;

// Load certificate from Certificate Store using the configured Thumbprint
using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, appConfiguration.CertificateThumbprint, false);

    if (certificates.Count > 0)
        certificate = certificates[0];
}

// Fallback to load certificate from local file
if (certificate == null)
{
    string path = Path.Combine("C:\\Certificates", appConfiguration.CertificateFilename);

    try
    {
        certificate = new X509Certificate2(path, "CertificateSecret123$");
        logger.LogInformation($"Found from file {certificate.Thumbprint}");
    }
    catch (Exception ex)
    {
        logger.LogError(ex, $"Certificate file error {path}");
        certificate = null;
    }
}

if (certificate == null)
    throw new Exception($"Certificate {appConfiguration.CertificateThumbprint} not found.");

builder.AddSigningCredential(certificate);
如果我更改指纹以强制代码从本地文件中查找证书,则会得到预期结果:

更新2018/11/19

我纠正了代码中的一个错误,因为如果找不到证书文件,
X509Certificate2
类构造函数会抛出一个异常。因此,实际上,在
certificate=new X509Certificate2…
行之后的先前
if(certificate==null)
控件永远不会到达

使代码正常工作的步骤包括:

  • 创建证书并将其放入目录中
  • 检查运行代码的用户在文件夹上的目录权限。
    • 如果您在开发计算机上,请检查运行VS的用户是否具有访问文件所在目录的权限
    • 如果您使用的是IIS,请检查承载应用程序的
      AppPool
      ,以及执行应用程序的用户。它需要对证书目录具有权限
  • 使用示例代码从文件加载证书。确保路径的正确性
  • 使用指纹从存储加载证书。要获取证书指纹,您可以:
    • 使用PowerShell命令
      Get ChildItem-path cert:\LocalMachine\My
      指定存储中注册证书的正确位置
    • 使用Windows资源管理器,右键单击.pfx文件->打开->在MMC控制台中查找文件->双击文件->详细信息->指纹重要注意事项:在预览文本框中复制/粘贴指纹值时,Windows中存在一个众所周知的丑陋错误粘贴值时,在指纹的开头添加隐藏字符。因此,首先在文本编辑器上复制/粘贴它,然后在第一个字符附近移动箭头键进行检查。另见

  • 请记住,如果您正在运行mul
      openssl genrsa 2048 > private.pem
      openssl req -x509 -days 365 -new -key private.pem -out public.pem
      openssl pkcs12 -export -in public.pem -inkey private.pem -out cert.pfx
      REM openssl pkcs12 -info -in cert.pfx
      certutil -dump cert.pfx
      PAUSE
    
      using data protection keystore path C:\inetpub\wwwroot\auth\keystore
      data protection keystore is protected with certificate at path 'C:\inetpub\wwwroot\auth\certs\keystore.pfx'
      loading keystore certificate from file 'C:\inetpub\wwwroot\auth\certs\keystore.pfx'
      loading keystore certificate with passphrase ********
    
    
      Application startup exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
         at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
         at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
         at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
         at [SomeOfMyNamespaces].X509Certificate2Loader.LoadFromFile(String certName, String certPath, String certPassphrase, ILogger logger) in [intentionally-blanked]\X509Certificate2Loader.cs:line 57
         at [SomeOfMyNamespaces].DataProtectionExtensions.AddDataProtection(IServiceCollection services, IConfiguration config, IHostingEnvironment environment, String applicationName, String applicationVersion, ILogger logger) in [intentionally-blanked]\DataProtectionExtensions.cs:line 207
         at [SomeOfMyNamespaces].Startup.ConfigureServices(IServiceCollection services) in [intentionally-blanked]\Startup.cs:line 96
      --- End of stack trace from previous location where exception was thrown ---
         at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
      --- End of stack trace from previous location where exception was thrown ---
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
      crit: Microsoft.AspNetCore.Hosting.Internal.WebHost[6]
            Application startup exception
      Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred
         at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
         at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
         at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
         at [SomeOfMyNamespaces].X509Certificate2Loader.LoadFromFile(String certName, String certPath, String certPassphrase, ILogger logger) in [intentionally-blanked]\X509Certificate2Loader.cs:line 57
         at [SomeOfMyNamespaces].DataProtectionExtensions.AddDataProtection(IServiceCollection services, IConfiguration config, IHostingEnvironment environment, String applicationName, String applicationVersion, ILogger logger) in [intentionally-blanked]\DataProtectionExtensions.cs:line 207
         at [SomeOfMyNamespaces].Startup.ConfigureServices(IServiceCollection services) in [intentionally-blanked]\Startup.cs:line 96
      --- End of stack trace from previous location where exception was thrown ---
         at Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
      --- End of stack trace from previous location where exception was thrown ---
         at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
    
      cert = new X509Certificate2(certPath, certPassphrase);
    
    cert = new X509Certificate2(certPath, certPassphrase, X509KeyStorageFlags.MachineKeySet);
    
    X509Certificate2 certificate = null;
    
    // Load certificate from Certificate Store using the configured Thumbprint
    using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
    {
        store.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, appConfiguration.CertificateThumbprint, false);
    
        if (certificates.Count > 0)
            certificate = certificates[0];
    }
    
    // Fallback to load certificate from local file
    if (certificate == null)
    {
        string path = Path.Combine("C:\\Certificates", appConfiguration.CertificateFilename);
    
        try
        {
            certificate = new X509Certificate2(path, "CertificateSecret123$");
            logger.LogInformation($"Found from file {certificate.Thumbprint}");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"Certificate file error {path}");
            certificate = null;
        }
    }
    
    if (certificate == null)
        throw new Exception($"Certificate {appConfiguration.CertificateThumbprint} not found.");
    
    builder.AddSigningCredential(certificate);