Create Certificates for IdentityServer4 signing using .NET Core

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

http://docs.identityserver.io/en/latest/topics/mtls.html

https://docs.microsoft.com/en-us/dotnet/core/get-started

11 comments

  1. […] Create Certificates for IdentityServer4 signing using .NET Core (Damien Bowden) […]

  2. […] Create Certificates for IdentityServer4 signing using .NET Core – Damien Bowden […]

  3. 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

    1. Hi normail

      This sounds really cool, yes please share

      Greetings Damien

      1. 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

  4. Reblogged this on Neel Bhatt and commented:
    Nice article

  5. […] CREATE CERTIFICATES FOR IDENTITYSERVER4 SIGNING USING .NET CORE Authors shows how to create certificate in identity server 4. asp.net core Identity server […]

  6. Shawn Zheng · · Reply

    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?

    1. John Jardine · · Reply

      Shawn did you ever figure out the cause for this error?

      1. 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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: