mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
httpcaddyfile: Add preferred_chains
global option and issuer subdirective (#4192)
* Added preferred_chains option to Caddyfile * Caddyfile adapt tests for preferred_chains
This commit is contained in:
parent
76913b19ff
commit
1e92258dd6
5 changed files with 187 additions and 1 deletions
|
@ -49,6 +49,7 @@ func init() {
|
||||||
RegisterGlobalOption("servers", parseServerOptions)
|
RegisterGlobalOption("servers", parseServerOptions)
|
||||||
RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions)
|
RegisterGlobalOption("ocsp_stapling", parseOCSPStaplingOptions)
|
||||||
RegisterGlobalOption("log", parseLogOptions)
|
RegisterGlobalOption("log", parseLogOptions)
|
||||||
|
RegisterGlobalOption("preferred_chains", parseOptPreferredChains)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOptTrue(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) { return true, nil }
|
func parseOptTrue(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) { return true, nil }
|
||||||
|
@ -452,3 +453,8 @@ func parseLogOptions(d *caddyfile.Dispenser, existingVal interface{}) (interface
|
||||||
|
|
||||||
return configValues, nil
|
return configValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseOptPreferredChains(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
|
||||||
|
d.Next()
|
||||||
|
return caddytls.ParseCaddyfilePreferredChainsOptions(d)
|
||||||
|
}
|
||||||
|
|
|
@ -321,7 +321,8 @@ func (st ServerType) buildTLSApp(
|
||||||
globalACMECARoot := options["acme_ca_root"]
|
globalACMECARoot := options["acme_ca_root"]
|
||||||
globalACMEDNS := options["acme_dns"]
|
globalACMEDNS := options["acme_dns"]
|
||||||
globalACMEEAB := options["acme_eab"]
|
globalACMEEAB := options["acme_eab"]
|
||||||
hasGlobalACMEDefaults := globalEmail != nil || globalACMECA != nil || globalACMECARoot != nil || globalACMEDNS != nil || globalACMEEAB != nil
|
globalPreferredChains := options["preferred_chains"]
|
||||||
|
hasGlobalACMEDefaults := globalEmail != nil || globalACMECA != nil || globalACMECARoot != nil || globalACMEDNS != nil || globalACMEEAB != nil || globalPreferredChains != nil
|
||||||
if hasGlobalACMEDefaults {
|
if hasGlobalACMEDefaults {
|
||||||
for _, ap := range tlsApp.Automation.Policies {
|
for _, ap := range tlsApp.Automation.Policies {
|
||||||
if len(ap.Issuers) == 0 {
|
if len(ap.Issuers) == 0 {
|
||||||
|
@ -405,6 +406,7 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]interf
|
||||||
globalACMECARoot := options["acme_ca_root"]
|
globalACMECARoot := options["acme_ca_root"]
|
||||||
globalACMEDNS := options["acme_dns"]
|
globalACMEDNS := options["acme_dns"]
|
||||||
globalACMEEAB := options["acme_eab"]
|
globalACMEEAB := options["acme_eab"]
|
||||||
|
globalPreferredChains := options["preferred_chains"]
|
||||||
|
|
||||||
if globalEmail != nil && acmeIssuer.Email == "" {
|
if globalEmail != nil && acmeIssuer.Email == "" {
|
||||||
acmeIssuer.Email = globalEmail.(string)
|
acmeIssuer.Email = globalEmail.(string)
|
||||||
|
@ -425,6 +427,9 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]interf
|
||||||
if globalACMEEAB != nil && acmeIssuer.ExternalAccount == nil {
|
if globalACMEEAB != nil && acmeIssuer.ExternalAccount == nil {
|
||||||
acmeIssuer.ExternalAccount = globalACMEEAB.(*acme.EAB)
|
acmeIssuer.ExternalAccount = globalACMEEAB.(*acme.EAB)
|
||||||
}
|
}
|
||||||
|
if globalPreferredChains != nil && acmeIssuer.PreferredChains == nil {
|
||||||
|
acmeIssuer.PreferredChains = globalPreferredChains.(*caddytls.ChainPreference)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
preferred_chains smallest
|
||||||
|
}
|
||||||
|
|
||||||
|
localhost
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"automation": {
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"subjects": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"issuers": [
|
||||||
|
{
|
||||||
|
"module": "acme",
|
||||||
|
"preferred_chains": {
|
||||||
|
"smallest": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"module": "zerossl",
|
||||||
|
"preferred_chains": {
|
||||||
|
"smallest": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
localhost
|
||||||
|
|
||||||
|
tls {
|
||||||
|
issuer acme {
|
||||||
|
preferred_chains {
|
||||||
|
any_common_name "Generic CA 1" "Generic CA 2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----------
|
||||||
|
{
|
||||||
|
"apps": {
|
||||||
|
"http": {
|
||||||
|
"servers": {
|
||||||
|
"srv0": {
|
||||||
|
"listen": [
|
||||||
|
":443"
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": [
|
||||||
|
{
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"terminal": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tls": {
|
||||||
|
"automation": {
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"subjects": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"issuers": [
|
||||||
|
{
|
||||||
|
"module": "acme",
|
||||||
|
"preferred_chains": {
|
||||||
|
"any_common_name": [
|
||||||
|
"Generic CA 1",
|
||||||
|
"Generic CA 2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -265,6 +265,10 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
|
||||||
// trusted_roots <pem_files...>
|
// trusted_roots <pem_files...>
|
||||||
// dns <provider_name> [<options>]
|
// dns <provider_name> [<options>]
|
||||||
// resolvers <dns_servers...>
|
// resolvers <dns_servers...>
|
||||||
|
// preferred_chains [smallest] {
|
||||||
|
// root_common_name <common_names...>
|
||||||
|
// any_common_name <common_names...>
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
|
@ -416,6 +420,13 @@ func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
return d.ArgErr()
|
return d.ArgErr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "preferred_chains":
|
||||||
|
chainPref, err := ParseCaddyfilePreferredChainsOptions(d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iss.PreferredChains = chainPref
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return d.Errf("unrecognized ACME issuer property: %s", d.Val())
|
return d.Errf("unrecognized ACME issuer property: %s", d.Val())
|
||||||
}
|
}
|
||||||
|
@ -452,6 +463,57 @@ func onDemandAskRequest(ask string, name string) error {
|
||||||
return nil
|
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,
|
// ChainPreference describes the client's preferred certificate chain,
|
||||||
// useful if the CA offers alternate chains. The first matching chain
|
// useful if the CA offers alternate chains. The first matching chain
|
||||||
// will be selected.
|
// will be selected.
|
||||||
|
|
Loading…
Reference in a new issue