This article shows how to create certificates for an IdentityServer4 application to use for signing and token validation. The certificates are created using the CertificateManager nuget package. Both RSA and ECDsa certificates can be used for signing in IdentityServer4.
Code: Certificates for IdentityServer4 signing using .NET Core
Creating the Certificates in .NET Core
A simple .NET Core console application is used to create the certificates. This type of application can run on most of the standard operating systems. Create a new console application and add the package CertificateManager. The package Microsoft.Extensions.DependencyInjection is also required to initialize the package.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="CertificateManager" Version="1.0.3" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.1" /> </ItemGroup> </Project>
Creating a RSA certificate
A self signed RSA certificate can be created using the CertificateManager NewRsaSelfSignedCertificate method. The key size must be at least 2048. The following example also adds TLS server and client authentication OID extensions, so that the certificate could also be used for client authentication.
public static X509Certificate2 CreateRsaCertificate( string dnsName, int validityPeriodInYears) { var basicConstraints = new BasicConstraints { CertificateAuthority = false, HasPathLengthConstraint = false, PathLengthConstraint = 0, Critical = false }; var subjectAlternativeName = new SubjectAlternativeName { DnsName = new List<string>{ dnsName } }; var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; // only if certification authentication is used var enhancedKeyUsages = new OidCollection { new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth }; var certificate = _cc.NewRsaSelfSignedCertificate( new DistinguishedName { CommonName = dnsName }, basicConstraints, new ValidityPeriod { ValidFrom = DateTimeOffset.UtcNow, ValidTo = DateTimeOffset.UtcNow.AddYears(validityPeriodInYears) }, subjectAlternativeName, enhancedKeyUsages, x509KeyUsageFlags, new RsaConfiguration { KeySize = 2048 } ); return certificate; }
Creating a ECDsa certificate
A self signed ECDsa certificate can be created using the CertificateManager NewECDsaSelfSignedCertificate method.
public static X509Certificate2 CreateECDsaCertificate( string dnsName, int validityPeriodInYears) { var basicConstraints = new BasicConstraints { CertificateAuthority = false, HasPathLengthConstraint = false, PathLengthConstraint = 0, Critical = false }; var san = new SubjectAlternativeName { DnsName = new List<string>{ dnsName } }; var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature; // only if certification authentication is used var enhancedKeyUsages = new OidCollection { new Oid("1.3.6.1.5.5.7.3.1"), // TLS Server auth new Oid("1.3.6.1.5.5.7.3.2"), // TLS Client auth }; var certificate = _cc.NewECDsaSelfSignedCertificate( new DistinguishedName { CommonName = dnsName }, basicConstraints, new ValidityPeriod { ValidFrom = DateTimeOffset.UtcNow, ValidTo = DateTimeOffset.UtcNow.AddYears(validityPeriodInYears) }, san, enhancedKeyUsages, x509KeyUsageFlags, new ECDsaConfiguration()); return certificate; }
Creating and exporting the pfx files
The RSA and the ECDsa certificate can then be created and exported as a pfx file.
static CreateCertificates _cc; static void Main(string[] args) { var sp = new ServiceCollection() .AddCertificateManager() .BuildServiceProvider(); _cc = sp.GetService<CreateCertificates>(); var rsaCert = CreateRsaCertificate("localhost", 10); var ecdsaCert = CreateECDsaCertificate("localhost", 10); string password = "1234"; var iec = sp.GetService<ImportExportCertificate>(); var rsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(password, rsaCert); File.WriteAllBytes("rsaCert.pfx", rsaCertPfxBytes); var ecdsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(password, ecdsaCert); File.WriteAllBytes("ecdsaCert.pfx", ecdsaCertPfxBytes); }
Using the Certificates in IdentityServer4
The certificate pfx exports can then be used in IdentityServer4. Depending on how you deploy the web application which contains the IdentityServer4 library, you would choose the best way to load the certificates into the application, for example a thumbprint which loads from the host operating system, or a certificate loaded from Key Vault in Azure.
If using a RSA certificate, you can load this directly using the AddSigningCredential IdentityServer4 extension method.
var rsaCertificate = new X509Certificate2( Path.Combine(_environment.ContentRootPath, "rsaCert.pfx"), "1234"); services.AddIdentityServer() .AddSigningCredential(rsaCertificate) // rsaCertificate .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()) .AddAspNetIdentity<ApplicationUser>() .AddProfileService<IdentityWithAdditionalClaimsProfileService>();
using the jwks endpoint, you can view the certificate public details used for validation:
/.well-known/openid-configuration/jwks
When using an ECDsa certificate, you need to create a ECDsaSecurityKey instance from the ECDsa certificate private key. This can then be used as a parameter in the AddSigningCredential method.
var ecdsaCertificate = new X509Certificate2( Path.Combine(_environment.ContentRootPath, "ecdsaCert.pfx"), "1234"); ECDsaSecurityKey ecdsaCertificatePublicKey = new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey()); services.AddIdentityServer() .AddSigningCredential(ecdsaCertificatePublicKey, "ES256") .AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddInMemoryApiResources(Config.GetApiResources()) .AddInMemoryClients(Config.GetClients()) .AddAspNetIdentity<ApplicationUser>() .AddProfileService<IdentityWithAdditionalClaimsProfileService>();
The jwks endpoint uses an EC certificate.
Links:
https://github.com/damienbod/AspNetCoreCertificates
https://www.nuget.org/packages/CertificateManager/
http://docs.identityserver.io/en/latest/topics/crypto.html
[…] Create Certificates for IdentityServer4 signing using .NET Core (Damien Bowden) […]
[…] Create Certificates for IdentityServer4 signing using .NET Core – Damien Bowden […]
For a development process i’ve written small certificate authority. It doesn’t have CRLs, but it runs in docker and allows certificate issue for both ssl(basically has subjectAltName extension) and signing purposes. It has rest api for automation and Swagger UI. If anyone is interested i can share a github link
Hi normail
This sounds really cool, yes please share
Greetings Damien
The link is https://github.com/nomailme/TestAuthority
I plan to add CRLs as they are sometimes necessary, but this works for most of our development cases
Reblogged this on Neel Bhatt and commented:
Nice article
thanks
[…] CREATE CERTIFICATES FOR IDENTITYSERVER4 SIGNING USING .NET CORE Authors shows how to create certificate in identity server 4. asp.net core Identity server […]
Do you have updated version for this blog? I tried your code in this blog, but it does not work for me. I use Visual Studio 2019 profession. The X509Certificate2 codes are copied from this post. But new X509Certificate2(pfx, password) call throw an exception to ‘The specified network password is not correct’. Do you know the reason I got this issue?
Shawn did you ever figure out the cause for this error?
Hi John, Shawn, I’ll check if the blog needs updating, the git repo attached with this blog has been updated and works
Greetigns Damien
Thank you Damien, I used your code from the Github link at the top of this post and everything works. I am using a webapp client built with ASP.NE Core 3.1 to authenticate to a different webapp with IdentityProvider4 also using Core3.1 Both hosted in Azure. I replaced localhost in your code with the MyownNameIDPwebapp dot azurewebsites dot net domain and it worked fine.
[…] creiamo la classe SelfSignedServerCertificate.cs (vedi doc doc […]