From 1e92258dd670dc62a55b100d1e68e7f482da14a1 Mon Sep 17 00:00:00 2001 From: Klooven Date: Tue, 8 Jun 2021 23:10:37 +0300 Subject: httpcaddyfile: Add `preferred_chains` global option and issuer subdirective (#4192) * Added preferred_chains option to Caddyfile * Caddyfile adapt tests for preferred_chains --- modules/caddytls/acmeissuer.go | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'modules/caddytls') diff --git a/modules/caddytls/acmeissuer.go b/modules/caddytls/acmeissuer.go index 6085044..b60e560 100644 --- a/modules/caddytls/acmeissuer.go +++ b/modules/caddytls/acmeissuer.go @@ -265,6 +265,10 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss } // trusted_roots // dns [] // resolvers +// preferred_chains [smallest] { +// root_common_name +// any_common_name +// } // } // func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { @@ -416,6 +420,13 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { return d.ArgErr() } + case "preferred_chains": + chainPref, err := ParseCaddyfilePreferredChainsOptions(d) + if err != nil { + return err + } + iss.PreferredChains = chainPref + default: return d.Errf("unrecognized ACME issuer property: %s", d.Val()) } @@ -452,6 +463,57 @@ func onDemandAskRequest(ask string, name string) error { return nil } +func ParseCaddyfilePreferredChainsOptions(d *caddyfile.Dispenser) (*ChainPreference, error) { + chainPref := new(ChainPreference) + if d.NextArg() { + smallestOpt := d.Val() + if smallestOpt == "smallest" { + trueBool := true + chainPref.Smallest = &trueBool + if d.NextArg() { // Only one argument allowed + return nil, d.ArgErr() + } + if d.NextBlock(d.Nesting()) { // Don't allow other options when smallest == true + return nil, d.Err("No more options are accepted when using the 'smallest' option") + } + } else { // Smallest option should always be 'smallest' or unset + return nil, d.Errf("Invalid argument '%s'", smallestOpt) + } + } + for nesting := d.Nesting(); d.NextBlock(nesting); { + switch d.Val() { + case "root_common_name": + rootCommonNameOpt := d.RemainingArgs() + chainPref.RootCommonName = rootCommonNameOpt + if rootCommonNameOpt == nil { + return nil, d.ArgErr() + } + if chainPref.AnyCommonName != nil { + return nil, d.Err("Can't set root_common_name when any_common_name is already set") + } + + case "any_common_name": + anyCommonNameOpt := d.RemainingArgs() + chainPref.AnyCommonName = anyCommonNameOpt + if anyCommonNameOpt == nil { + return nil, d.ArgErr() + } + if chainPref.RootCommonName != nil { + return nil, d.Err("Can't set any_common_name when root_common_name is already set") + } + + default: + return nil, d.Errf("Received unrecognized parameter '%s'", d.Val()) + } + } + + if chainPref.Smallest == nil && chainPref.RootCommonName == nil && chainPref.AnyCommonName == nil { + return nil, d.Err("No options for preferred_chains received") + } + + return chainPref, nil +} + // ChainPreference describes the client's preferred certificate chain, // useful if the CA offers alternate chains. The first matching chain // will be selected. -- cgit v1.2.3