Protoacme

Protoacme is a .NET Core 2.1 ACME client that leverages the ACME protocol from Lets Encrypt to issue and renew SSL certificates. This Api leverages the v2 endpoints from Lets Encrypt. Currently wildcard certificates are supported by the Lets Encrypt v2 endpoint but are not currently working through this Api. (should be working soon.)


Keywords
protoacme, acme, lets, encrypt, ssl, https, secure, api
License
MIT
Install
Install-Package Protoacme -Version 1.0.8

Documentation

Protoacme

Protoacme is a .NET Core 2.1 ACME client that leverages the ACME protocol from Lets Encrypt to issue and renew SSL certificates. This Api leverages the v2 endpoints from Lets Encrypt. Currently wildcard certificates are supported by the Lets Encrypt v2 endpoint but are not currently working through this Api. (should be working soon.)

Getting Started

To get started, install the NuGet package in your project or download and compile the project in to your solution.

Prerequisites

Protoacme requires .NET Core 2.1 or newer.

Installing

Register the protoacme service in DI.

using Protoacme.Services;

...

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddProtoacme(options => 
            {
                //Uses the Lets Encrypt staging endpoint if an ASPNETCORE_ENVIRONMENT variable is set.
                if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
                    options.UseStaging = true;
            });
        }

Examples

Create an account in Lets Encrypt

//Create the account model
AcmeCreateAccount accountInfo = new AcmeCreateAccount();
accountInfo.Contact = new List<string>(){ "mailto:bob@toast.com" };
accountInfo.TermsOfServiceAgreed = true;

//Create the account in Lets Encrypt
AcmeAccount acmeAccount = await _protoacmeClient.Account.CreateAsync(accountInfo);

//Save the account info to disk for later use.
acmeAccount.SaveToFile(@"c:\temp\myaccount.dat");

Create a new CSR

CSR csr = CertificateUtility.GenerateCsr(new List<string>(){ "domain1.com", "domain2.com" });

Request a new certificate and challenge

var domains = new List<string>(){ "domain1.com", "domain2.com" }
AcmeCertificateRequest certRequest = new AcmeCertificateRequest();
foreach (var dnsName in domains)
{
    certRequest.Identifiers.Add(new DnsCertificateIdentifier() { Value = dnsName.Domain });
}

AcmeCertificateFulfillmentPromise promise = await _protoacmeClient.Certificate.RequestCertificateAsync(acmeAccount, certRequest);

ChallengeCollection challenges = await _protoacmeClient.Challenge.GetChallengesAsync(acmeAccount, promise, ChallengeType.Http);

Setup your challenge

Depending on the challenge type you chose, you will need to setup your challenge so Lets Encrypt can verify that you own the domain name.

  • Http Challenge
    • Place a file in your web server with the authorization key contents from the challenges response. The file should be located at .well-known/acme-challenge/{token from challenge response}

Currently, only http challenges are working. DNS and TLS Challenges coming soon.

Verify your challenge with Lets Encrypt

foreach (var challenge in challenges)
{
    var startVerifyResult = await client.Challenge.ExecuteChallengeVerification(challenge);
    AcmeChallengeStatus challengeStatus = null;
    while (challengeStatus == null || challengeStatus.Status == "pending")
    {
        challengeStatus = await client.Challenge.GetChallengeVerificationStatus(challenge);
        //We need to wait at least 3 seconds before checking the status again.
        await Task.Delay(3000);
    }

    if (challengeStatus.Status != "valid")
    throw new Exception($"Failed to validate challenge token {challenge.Token}");
}

Download your certificate

var cert = await client.Certificate.DownloadCertificateAsync(account, promise, csr, CertificateType.Cert);

//Save Certificate to file
using (FileStream fs = new FileStream(@"c:\temp\mycert.cer", FileMode.Create))
{
    byte[] buffer = cert.Array;
    fs.Write(buffer, 0, buffer.Length);
}

Authors

License

This project is licensed under the MIT License

Acknowledgments

  • To the Lets Encrypt Team! Support Lets Encrypt if you can so they can continue to provide free SSL certificates to the world!
  • Lets Encrypt