Self Signed RSA Certificate with .NET 7
Tags: dotnet7, rsa, cryptography, csharp
Published: 2023-02-21 22:01:03

Asymmetric encryption uses a public/private key pair to encrypt the data at one end and decrypt the data on the other end. Most of the times, the encryption keys are created in the form of certificates, which might have been created in advance. 

But for some scenarios such as IOT, certificates should be created for each device beforehand, which should be registered on the public cloud provider before using the IoT features. It will be tricky to create certificates beforehand if we have millions of devices to work with IoT and goes for production. 

In this case, we can create our own self-signed device certificates at runtime using RSA in .NET Core

I'm gonna create a console application that will create a random RSA certificate and export the certificate and its private and public keys locally. 

To do that, I'm gonna create a Console App project in VS2022.

![Choosing Console App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c47ywpv8wgybyfb3jnf7.png)

Choosing **.NET 7** as a framework


![Choosing .NET7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/icqcyzxoicwfbhbzfawa.png)

Now the project has been created.
Let's create a public record model that will store the certificate instance as well as its keys.

```public record CertificateModel(X509Certificate2 Certificate, string PublicKeyPEM, string PrivateKeyPEM, string PublicKeyPFX = "");```

Next, I'm gonna create a helper class to create RSA certificates and store its keys in a **CertificateModel** instance

``` 

internal class RSAHelper
{
    /// <summary>
    ///     Create a random RSA certificate for asymentric encryption
    /// </summary>
    /// <param name="subjectName">Subject name for the certificate. Ex, "cn=test"</param>
    /// <param name="hashAlgorithmName">Algorithm mode for creating hash keys</param>
    /// <param name="signaturePadding">Padding mode for the certificate signature</param>
    /// <returns>Certificate model</returns>
    public CertificateModel CreateRSACertificate(string subjectName
        , HashAlgorithmName hashAlgorithmName
        , RSASignaturePadding signaturePadding)
    {
        using var rsa = RSA.Create();
        var certRequest = new CertificateRequest(subjectName, rsa, hashAlgorithmName, signaturePadding);
        var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddDays(1));

        var privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks);
        var publicKey = certificate.ExportCertificatePem();
        var publicKeyPfx = Convert.ToBase64String(certificate.Export(X509ContentType.Pfx), Base64FormattingOptions.InsertLineBreaks);

        return new CertificateModel(certificate, publicKey, privateKey, publicKeyPfx);
    }
}

```

That's it. The method "**CreateRSACertificate**" will create random RSA Keys and create a self-signed X509Certificate2 instance using the RSA keys which we created. It exports the private key and public key in a PEM format and stores it in the CertificateModel instance which will be returned to the caller method.

Now, we have to call `RSAHelper.CreateRSACertificate()` instance from the `Program.cs` class.

```
RSAHelper rsaHelperInstance = new RSAHelper();

Console.Write("Enter the subject name of the certificate : ");
var subjectName = $"CN={Console.ReadLine()?.ToUpper()}";

CertificateModel certificate = rsaHelperInstance.CreateRSACertificate(subjectName: subjectName
    , hashAlgorithmName: HashAlgorithmName.SHA256
    , signaturePadding: RSASignaturePadding.Pkcs1);

Console.WriteLine("Certificate is ready !!");
Console.Write("Do you want to save it locally? Press y or n : ");

char choice = Console.ReadKey().KeyChar;

if (choice == 'y')
{
    if (!Directory.Exists("Certificates"))
        Directory.CreateDirectory("Certificates");

    File.WriteAllText("Certificates/certificate.pem", certificate.PublicKeyPEM);
    File.WriteAllText("Certificates/certificate.private.pem", certificate.PrivateKeyPEM);
    File.WriteAllText("Certificates/certificate.pfx", certificate.PublicKeyPFX);

    Console.WriteLine();
    string filesLocation = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location)?.FullName ?? "", "Certificates");
    Console.WriteLine($"Files are saved in {filesLocation}");

    Process.Start(fileName: "explorer.exe", arguments: filesLocation);
}


```

Here, I'm getting the subject name for the certificate from the user and passing it to the `CreateRSACertificate()` method which returns the CertificateModel Instance. Based on the user's interest, I'm saving the certificates and keys in a local file. 

We can also save the certificates in X509Stores for appropriate usage.

_

> Full source code is available here "[RSACertificateGenerator.NET7](https://github.com/sprabha1990/RSACertificateGenerator.NET7)"
_