I want to create or obtain a certificate, create a pfx-file, load it and have IdentityServer use it. However, IdentityServer is not able to use my pfx.
How to successfully create a pfx and have IdentityServer use it?
I have an IdentityServer4 web solution running on localhost with ASP.Net Core. I am preparing the solution for production running on Azure, and is adding a certificate to the IdentityServer pipeline instead of the developer signing certificate.
Typically this means to swap code like
services.AddIdentityServer()
.AddDeveloperSigningCredential()
with
services.AddIdentityServer()
.AddSigningCredential(cert)
where "cert" is an object instance of X509Certificate2 which has loaded a PFX-file containing the certificate (with public and private keys).
The certificate I am using is self signed and is created by following the steps on Ben Cull's Blog https://benjii.me/2017/06/creating-self-signed-certificate-identity-server-azure/
The certicate and private key is exported to a PFX-file in order for both public and private key to be contained in the file.
The loading of the PFX-file succeeds. The code for loading is
cert = new X509Certificate2(Path.Combine(Environment.ContentRootPath, "MyPfxFile.pfx"), "password-used-when-exporting-pfx");
The Pfx-file is located within the web project and is found and read into the X509Certificate object.
When inspecting the X509Certificate2 in Visual Studio the property HasPrivateKey return true, but the PrivateKey property resolves to an exception in the watcher.
'cert.PrivateKey' threw an exception of type 'Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException'
All other properties look sound and good in the watcher.
Also, when I execute the GetRSAPrivateKey in the Immediate Window method on the certificate object instance, it returns an exception.
cert.GetRSAPrivateKey()
'cert.GetRSAPrivateKey()' threw an exception of type 'Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146893798
HelpLink: null
InnerException: null
Message: "Keyset as registered is invalid"
Source: "System.Security.Cryptography.Csp"
StackTrace: " at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSA
PrivateKey(X509Certificate2 certificate)"
TargetSite: {System.Security.Cryptography.SafeProvHandle CreateProvHandle(System.Security.Cryptography.CspParameters, Boolean)}
I have tried loading the pfx-file with different settings for X509KeyStorageFlags, but the behaviour and exceptions are the same.
I have also tried to install the PFX into the Windows machine's certificate manager, and I am successfully loading it from there, but the same exceptions are thrown.
At last, when requesting an access token from IdentityServer, the same exception is thrown. I have pasted the exception trace below.
IdentityServer4.Hosting.IdentityServerMiddleware:Critical: Unhandled exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset as registered is invalid
at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKey()
at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_HasPrivateKey()
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.HasPrivateKey(SecurityKey key)
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt) in C:localidentityserver4IdentityServer4srcIdentityServer4ServicesDefaultTokenCreationService.cs:line 209
at IdentityServer4.Services.DefaultTokenCreationService.<CreateTokenAsync>d__4.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4ServicesDefaultTokenCreationService.cs:line 67
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Services.DefaultTokenService.<CreateSecurityTokenAsync>d__9.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4ServicesDefaultTokenService.cs:line 210
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.ResponseHandling.TokenResponseGenerator.<CreateAccessTokenAsync>d__14.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4ResponseHandlingTokenResponseGenerator.cs:line 313
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessAuthorizationCodeRequestAsync>d__10.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4ResponseHandlingTokenResponseGenerator.cs:line 133
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.ResponseHandling.TokenResponseGenerator.<ProcessAsync>d__7.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4ResponseHandlingTokenResponseGenerator.cs:line 88
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Endpoints.TokenEndpoint.<ProcessTokenRequestAsync>d__7.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4EndpointsTokenEndpoint.cs:line 98
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Endpoints.TokenEndpoint.<ProcessAsync>d__6.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4EndpointsTokenEndpoint.cs:line 70
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Hosting.IdentityServerMiddleware.<Invoke>d__3.MoveNext() in C:localidentityserver4IdentityServer4srcIdentityServer4HostingIdentityServerMiddleware.cs:line 54
Application Insights Telemetry (unconfigured): {"name":"Microsoft.ApplicationInsights.Dev.Message","time":"2018-10-17T09:19:34.1583055Z","tags":{"ai.application.ver":"1.0.0.0","ai.cloud.roleInstance":"HEBE","ai.operation.id":"d7c51fcd-421c862dd08fe813","ai.operation.parentId":"|d7c51fcd-421c862dd08fe813.","ai.operation.name":"POST /connect/token","ai.location.ip":"127.0.0.1","ai.internal.sdkVersion":"aspnet5c:2.1.1","ai.internal.nodeName":"HEBE"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Unhandled exception: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset as registered is invalid
at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
at System.Security.Cryptography.X509Certificates.RSACertificateExtensions.GetRSAPrivateKey(X509Certificate2 certificate)
at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKey()
at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_HasPrivateKey()
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.HasPrivateKey(SecurityKey key)
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorith