Certes is an ACME client runs on .NET 4.5+ and .NET Standard 2.0+, supports ACME v2 and wildcard certificates. It is aimed to provide an easy to use API for managing certificates during deployment processes.
Install Certes nuget package into your project:
Install-Package Certesor using .NET CLI:
dotnet add package Certes
Let's Encrypt is the primary CA we supported. It's recommend testing against staging environment before using production environment, to avoid hitting the rate limits.
Creating new ACME account:
var acme = new AcmeContext(WellKnownServers.LetsEncryptStagingV2);
var account = await acme.NewAccount("admin@example.com", true);
// Save the account key for later use
var pemKey = acme.AccountKey.ToPem();Use an existing ACME account:
// Load the saved account key
var accountKey = KeyFactory.FromPem(pemKey);
var acme = new AcmeContext(WellKnownServers.LetsEncryptStagingV2, accountKey);
var account = await acme.Account();See API doc for additional operations.
Place a wildcard certificate order (DNS validation is required for wildcard certificates)
var order = await acme.NewOrder(new[] { "*.your.domain.name" });Generate the value for DNS TXT record
var authz = (await order.Authorizations()).First();
var dnsChallenge = await authz.Dns();
var dnsTxt = acme.AccountKey.DnsTxt(dnsChallenge.Token);Add a DNS TXT record to _acme-challenge.your.domain.name
with dnsTxt value.
For non-wildcard certificate, HTTP challenge is also available
var order = await acme.NewOrder(new[] { "your.domain.name" });If the ACME server supports certificate profiles, you can discover available profiles from the directory metadata and request a specific profile when placing an order:
// Check available profiles
var dir = await acme.GetDirectory();
foreach (var (name, description) in dir.Meta.Profiles)
{
Console.WriteLine($"{name}: {description}");
}
// Place an order with a specific profile
var order = await acme.NewOrder(new[] { "your.domain.name" }, profile: "shortLived");
// The profile is also available on the returned order resource
var resource = await order.Resource();
Console.WriteLine(resource.Profile);Get the token and key authorization string
var authz = (await order.Authorizations()).First();
var httpChallenge = await authz.Http();
var keyAuthz = httpChallenge.KeyAuthz;Save the key authorization string in a text file,
and upload it to http://your.domain.name/.well-known/acme-challenge/<token>
Ask the ACME server to validate our domain ownership
await challenge.Validate();Download the certificate once validation is done
var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
var cert = await order.Generate(new CsrInfo
{
CountryName = "CA",
State = "Ontario",
Locality = "Toronto",
Organization = "Certes",
OrganizationUnit = "Dev",
CommonName = "your.domain.name",
}, privateKey);Export full chain certification
var certPem = cert.ToPem();Export PFX
var pfxBuilder = cert.ToPfx(privateKey);
var pfx = pfxBuilder.Build("my-cert", "abcd1234");Check the APIs for more details.
For ACME v1, please see the doc here.
The CLI is available as a dotnet global tool. .NET Core Runtime 2.1+ is required to use dotnet tools.
To install Certes CLI (you may need to restart the console session if this is the first dotnet tool installed)
dotnet tool install --global dotnet-certes
See CLI usage, or simply use the --help option to get started
certes --help
Also check this AppVeyor script for renewing certificates on Azure apps.
We use SemVer for versioning. For the versions available, see the tags on this repository.
Also check the changelog to see what's we are working on.
Unit tests run standalone. Integration tests require a local Pebble ACME server with pebble-challtestsrv:
# Start the test infrastructure
cd test
docker compose up -d
# Run unit tests
dotnet test test/Certes.Tests/Certes.Tests.csproj -m:1
# Run integration tests
dotnet test test/Certes.Tests.Integration/Certes.Tests.Integration.csproj -m:1
# Stop the test infrastructure
cd test
docker compose downFor this fork, use fork-specific package identities to avoid conflicts with upstream:
- Library package:
CertKit.Certes - CLI tool package:
dotnet-certkit-certes - CLI command name:
certes-certkit
Pack using build.ps1 (auto-increments version and copies to .nuget-local feed):
.\build.ps1
.\build.ps1 -Project ".\src\Certes.Cli\Certes.Cli.csproj"
# With an explicit version
.\build.ps1 -Version "3.0.0-certkit.5"
# Copy to an additional output directory
.\build.ps1 -OutputDir "..\my-packages"Or pack directly with dotnet:
dotnet pack src/Certes/Certes.csproj -c Release -p:CERTES_PACKAGE_VERSION=3.0.0-certkit.1
dotnet pack src/Certes.Cli/Certes.Cli.csproj -c Release -p:CERTES_PACKAGE_VERSION=3.0.0-certkit.1# Set your GitHub PAT (needs write:packages scope)
$env:GITHUB_TOKEN = "ghp_..."
# Publish a package
.\publish-nuget.ps1 -Package ".\.nuget-local\CertKit.Certes.3.0.0-certkit.1.nupkg"