C#
self-signed certificate
programming tutorial
SSL/TLS
cryptography

How can I create a self-signed certificate using C?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In modern .NET, the cleanest way to create a self-signed certificate in C# is to use CertificateRequest. That API lets you generate a key pair, define the subject and extensions, create the certificate, and export it as a PFX or CER file for development or internal testing.

What a Self-Signed Certificate Is

A self-signed certificate signs itself with its own private key instead of being signed by a trusted certificate authority. That makes it useful for:

  • local HTTPS development
  • internal testing
  • temporary lab environments

It is not appropriate for public production endpoints where clients must trust the certificate automatically.

A Complete Example

The example below creates a self-signed certificate for localhost, valid for one year, and exports it as a PFX.

csharp
1using System;
2using System.IO;
3using System.Security.Cryptography;
4using System.Security.Cryptography.X509Certificates;
5
6class Program
7{
8    static void Main()
9    {
10        using RSA rsa = RSA.Create(2048);
11
12        var request = new CertificateRequest(
13            "CN=localhost",
14            rsa,
15            HashAlgorithmName.SHA256,
16            RSASignaturePadding.Pkcs1);
17
18        request.CertificateExtensions.Add(
19            new X509BasicConstraintsExtension(false, false, 0, false));
20
21        request.CertificateExtensions.Add(
22            new X509KeyUsageExtension(
23                X509KeyUsageFlags.DigitalSignature |
24                X509KeyUsageFlags.KeyEncipherment,
25                false));
26
27        request.CertificateExtensions.Add(
28            new X509SubjectKeyIdentifierExtension(request.PublicKey, false));
29
30        var sanBuilder = new SubjectAlternativeNameBuilder();
31        sanBuilder.AddDnsName("localhost");
32        request.CertificateExtensions.Add(sanBuilder.Build());
33
34        var notBefore = DateTimeOffset.UtcNow.AddMinutes(-5);
35        var notAfter = notBefore.AddYears(1);
36
37        using X509Certificate2 cert = request.CreateSelfSigned(notBefore, notAfter);
38
39        byte[] pfxBytes = cert.Export(X509ContentType.Pfx, "password123");
40        File.WriteAllBytes("localhost.pfx", pfxBytes);
41
42        Console.WriteLine("Certificate written to localhost.pfx");
43    }
44}

This is a practical baseline for local development.

Why SubjectAlternativeName Matters

Modern TLS clients care about the Subject Alternative Name extension more than the old common name field alone. If you want the certificate to work for localhost, an IP address, or a custom dev hostname, put those names in the SAN extension explicitly.

For example:

csharp
1var sanBuilder = new SubjectAlternativeNameBuilder();
2sanBuilder.AddDnsName("localhost");
3sanBuilder.AddIpAddress(System.Net.IPAddress.Loopback);
4request.CertificateExtensions.Add(sanBuilder.Build());

Without the correct SAN entries, the certificate may still be created successfully but fail hostname validation.

Export Formats

The two most common export choices are:

  • 'X509ContentType.Pfx when you need the private key'
  • 'X509ContentType.Cert when you only need the public certificate'

PFX is useful for local servers such as Kestrel or IIS development setups. CER is useful when distributing the public certificate separately.

Installing or Trusting the Certificate

Generating the certificate is only part of the job. For local HTTPS development, you may also need to trust it in the local certificate store or import it into the tool that will consume it.

That trust step is platform- and environment-specific, but the main idea is the same: clients must explicitly trust a self-signed certificate because no external authority vouches for it.

Common Pitfalls

The biggest mistake is thinking "self-signed" means "production-ready but cheaper." It does not. The trust model is completely different.

Another issue is forgetting the Subject Alternative Name extension. Many clients will reject certificates that rely only on the common name.

Developers also sometimes export only the public certificate when the server actually needs the private key too. In that case, you need a PFX.

Finally, be deliberate about key size, validity period, and storage. Even for local certificates, weak defaults and casual private-key handling are still bad habits.

Summary

  • In modern C#, use CertificateRequest to create self-signed certificates.
  • Add useful extensions such as key usage, subject key identifier, and Subject Alternative Name.
  • Export as PFX when you need the private key, or CER when you only need the public certificate.
  • Self-signed certificates are appropriate for development and internal testing, not for normal public production trust.
  • Creating the certificate and trusting it are separate steps.

Course illustration
Course illustration

All Rights Reserved.