Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docfx/docs/profile-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ The following profile would allow issuing DNS and IP certificates for any accoun
"Default": {
"SupportedIdentifiers": [ "dns", "ip" ],

// Optionally you can set allowed challenge-types:
"AllowedChallengeTypes": {
"dns": ["dns-01"],
"ip": ["http-01"]
}

"ADCSOptions": {
"CAServer": "CA.FQDN.com\\CA Name",
"TemplateName": "Default-ACME-Template"
Expand All @@ -23,6 +29,23 @@ The following profile would allow issuing DNS and IP certificates for any accoun
}
```

Foreach identifier you can also define the allowed challenge types. This list shows all identifer types as well as their supported challenge types. Defaults are printed bold.

- dns, e.g www.example.com
- **http-01**
- **dns-01**
- **tls-alpn-01**
- dns-persist-01
- dns (wildcard), e.g *.example.com
- **dns-01**
- dns-persist-01
- ip, e.g. 10.94.95.96
- **http-01**
- **tls-alpn-01**
- permanent-identifier
- **device-attest-01**


The profile selection process will run the identifier validation and only select profiles which match the parameters, e.g. if you want to use different CAs depending on DNS names, you could do something like this:

```json
Expand Down
2 changes: 1 addition & 1 deletion src/ACMEServer.ADCS/ACMEServer.ADCS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

<ItemGroup>
<ProjectReference Include="..\ACMEServer.CertProvider.ADCS\ACMEServer.CertProvider.ADCS.csproj" />
<ProjectReference Include="..\ACMEServer.CLI\ACMEServer.CLI.csproj" />
<ProjectReference Include="..\ACMEServer.CLI\ACMEServer.CLI.csproj" />
<ProjectReference Include="..\ACMEServer.Storage.FileSystem\ACMEServer.Storage.FileSystem.csproj" />
<ProjectReference Include="..\ACMEServer\ACMEServer.csproj" />
</ItemGroup>
Expand Down
13 changes: 13 additions & 0 deletions src/ACMEServer.ADCS/appsettings-sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@
"TemplateName": "DNS-ACME-Template"
},

// [Optional] Allowed challenge types can be used to enable additional or restrict challenge types for this profile.
// It's a map of identifier types to allowed challenge types, if you omit a identifier type, the defaults will be applied (see docs).
// Use this to enable dns-persist-01 challenges for dns identifiers, for example.
"AllowedChallengeTypes": {
"dns": [ "http-01", "dns-01", "tls-alpn-01" ],
"ip": [ "http-01", "tls-alpn-01" ],
"permanent-identifier": [ "device-attest-01" ],
"hardware-module": [ "device-attest-01" ]
},

// [Optional] The validity period of the authorization challenge. The default is one day.
// After this period, the authorization will be invalid and a new challenge must be requested.
"AuthorizationValidityPeriod": "23:59:59",
Expand All @@ -134,6 +144,9 @@
// Skipping CAA evaluation may have security implications and should only be used in scenarios where CAA compliance is not required.
"SkipCAAEvaluation": false,

// [Optional] Disable DNS wildcards. Default is false.
"DisableWildcards": false,

// [Optional] AllowedDNSNames is used to restrict the DNS names. It's an endsWith case-insensitive match.
// 'example.com' will allow *.example.com and example.com, '.example.com' will allow *.example.com but not example.com
// The default is an empty string - so no restriction (everything ends with an empty string).
Expand Down
47 changes: 47 additions & 0 deletions src/ACMEServer.ADCS/appsettings-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,48 @@
}
}
},
"AllowedChallengeTypes": {
"type": "object",
"description": "A map of identifier types to allowed challenge types, if you omit a identifier type, the defaults will be applied (see docs). Use this to enable dns-persist-01 challenges for dns identifiers, for example.",
"properties": {
"dns": {
"type": "array",
"items": {
"enum": [
"http-01",
"dns-01",
"tls-alpn-01",
"dns-persist-01"
]
}
},
"ip": {
"type": "array",
"items": {
"enum": [
"http-01",
"tls-alpn-01"
]
}
},
"permanent-identifier": {
"type": "array",
"items": {
"enum": [
"device-attest-01"
]
}
},
"hardware-module": {
"type": "array",
"items": {
"enum": [
"device-attest-01"
]
}
}
}
},
"AuthorizationValidityPeriod": {
"type": "string",
"format": "time",
Expand All @@ -191,6 +233,11 @@
"description": "If true, the ACME server will skip CAA evaluation for DNS identifiers during validation. The default is false."
},

"DisableWildcards": {
"type": "boolean",
"description": "If true, the ACME server will reject wildcard DNS names during validation. The default is false."
},

"AllowedDNSNames": {
"type": "array",
"description": "AllowedDNSNames restricts the DNS names. It's an endsWith case-insensitive match. 'example.com' allows *.example.com and example.com, '.example.com' allows *.example.com but not example.com. The default is an empty string, so no restriction.",
Expand Down
4 changes: 4 additions & 0 deletions src/ACMEServer.ADCS/appsettings.Test.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
"TemplateName": "DNS-ACME-Template"
},

"AllowedChallengeTypes": {
"ip": [ "http-01" ]
},

"IdentifierValidation": {
"DNS": {
"AllowedDNSNames": [ "example.com" ]
Expand Down
17 changes: 17 additions & 0 deletions src/ACMEServer.HttpModel/Challenge.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Text.Json.Serialization;

namespace Th11s.ACMEServer.HttpModel;

Expand Down Expand Up @@ -27,6 +28,16 @@ public static Challenge FromModel(Model.Challenge model, string challengeUrl)
Error = tokenChallenge.Error != null ? new AcmeError(tokenChallenge.Error) : null,
},

Model.DnsPersistChallenge dnsPersistChallenge => new DnsPersistChallenge()
{
Type = dnsPersistChallenge.Type,
Status = EnumMappings.GetEnumString(dnsPersistChallenge.Status),
Url = challengeUrl,
IssuerDomainNames = dnsPersistChallenge.IssuerDomainNames,
Validated = dnsPersistChallenge.Validated?.ToString("o", CultureInfo.InvariantCulture),
Error = dnsPersistChallenge.Error != null ? new AcmeError(dnsPersistChallenge.Error) : null,
},

_ => throw new NotSupportedException($"Challenge type '{model.GetType().FullName}' is not supported.")
};
}
Expand All @@ -46,3 +57,9 @@ public class TokenChallenge : Challenge
{
public required string Token { get; init; }
}

public class DnsPersistChallenge : Challenge
{
[JsonPropertyName("issuer-domain-names")]
public required string[] IssuerDomainNames { get; init; }
}
22 changes: 22 additions & 0 deletions src/ACMEServer.Model/Challenge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,27 @@ public DeviceAttestChallenge(
}

public string? Payload { get; set; }
}

public class DnsPersistChallenge : Challenge
{
public DnsPersistChallenge(Authorization authorization, string[] issuerDomainNames)
: base(authorization, ChallengeTypes.DnsPersist01)
{
IssuerDomainNames = issuerDomainNames;
}

public DnsPersistChallenge(
ChallengeId challengeId,
ChallengeStatus status,
string type,
string[] issuerDomainNames,
DateTimeOffset? validated,
AcmeError? error
) : base(challengeId, status, type, validated, error)
{
IssuerDomainNames = issuerDomainNames;
}

public string[] IssuerDomainNames { get; }
}
10 changes: 9 additions & 1 deletion src/ACMEServer.Model/ChallengeTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ public static class ChallengeTypes
public const string Dns01 = "dns-01";
public const string TlsAlpn01 = "tls-alpn-01";
public const string DeviceAttest01 = "device-attest-01";
public const string DnsPersist01 = "dns-persist-01";

public static readonly string[] AllTypes = [Http01, Dns01, TlsAlpn01, DeviceAttest01];
public static readonly string[] AllTypes = [Http01, Dns01, TlsAlpn01, DeviceAttest01, DnsPersist01];
public static readonly string[] TokenChallenges = [Http01, Dns01, TlsAlpn01, DeviceAttest01];

public static readonly string[] DnsChallenges = [Http01, Dns01, DnsPersist01, TlsAlpn01];
public static readonly string[] DnsWildcardChallenges = [Dns01, DnsPersist01];
public static readonly string[] IpChallenges = [Http01, TlsAlpn01];
public static readonly string[] EmailChallenges = [];
public static readonly string[] PermanentIdentifierChallenges = [DeviceAttest01];
public static readonly string[] HardwareModuleChallenges = [DeviceAttest01];
}
5 changes: 5 additions & 0 deletions src/ACMEServer.Model/Configuration/DNSValidationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public class DNSValidationParameters : IValidatableObject
/// in scenarios where CAA compliance is not required.</remarks>
public bool SkipCAAEvaluation { get; set; }

/// <summary>
/// If true, the ACME server will reject wildcard DNS names during validation. The default is false.
/// </summary>
public bool DisableWildcards { get; set; }

/// <summary>
/// The DNS names that are allowed for this profile, e.g. "example.com"
/// The values will be checked by using a case-insenstive, trimmed "EndsWith"
Expand Down
2 changes: 2 additions & 0 deletions src/ACMEServer.Model/Configuration/ProfileConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class ProfileConfiguration : IValidatableObject
[NotNull]
public string[] SupportedIdentifiers { get; set; } = default!;

[NotNull]
public Dictionary<string, string[]> AllowedChallengeTypes { get; set; } = default!;

public TimeSpan AuthorizationValidityPeriod { get; set; } = TimeSpan.FromDays(1);

Expand Down
Loading