mirror of
https://github.com/outbackdingo/labca.git
synced 2026-01-27 10:19:34 +00:00
135 lines
4.3 KiB
Diff
135 lines
4.3 KiB
Diff
diff --git a/policy/pa.go b/policy/pa.go
|
|
index 599dcdb10..084cb3ba8 100644
|
|
--- a/policy/pa.go
|
|
+++ b/policy/pa.go
|
|
@@ -30,6 +30,8 @@ type AuthorityImpl struct {
|
|
blocklist map[string]bool
|
|
exactBlocklist map[string]bool
|
|
wildcardExactBlocklist map[string]bool
|
|
+ whitelist map[string]bool
|
|
+ lockdown map[string]bool
|
|
blocklistMu sync.RWMutex
|
|
|
|
enabledChallenges map[core.AcmeChallenge]bool
|
|
@@ -70,6 +72,9 @@ type blockedNamesPolicy struct {
|
|
// time above and beyond the high-risk domains. Managing these entries separately
|
|
// from HighRiskBlockedNames makes it easier to vet changes accurately.
|
|
AdminBlockedNames []string `yaml:"AdminBlockedNames"`
|
|
+
|
|
+ Whitelist []string `yaml:"Whitelist"`
|
|
+ Lockdown []string `yaml:"Lockdown"`
|
|
}
|
|
|
|
// SetHostnamePolicyFile will load the given policy file, returning error if it
|
|
@@ -138,10 +143,20 @@ func (pa *AuthorityImpl) processHostnamePolicy(policy blockedNamesPolicy) error
|
|
// wildcardNameMap to block issuance for `*.`+parts[1]
|
|
wildcardNameMap[parts[1]] = true
|
|
}
|
|
+ whiteMap := make(map[string]bool)
|
|
+ for _, v := range policy.Whitelist {
|
|
+ whiteMap[v] = true
|
|
+ }
|
|
+ lockMap := make(map[string]bool)
|
|
+ for _, v := range policy.Lockdown {
|
|
+ lockMap[v] = true
|
|
+ }
|
|
pa.blocklistMu.Lock()
|
|
pa.blocklist = nameMap
|
|
pa.exactBlocklist = exactNameMap
|
|
pa.wildcardExactBlocklist = wildcardNameMap
|
|
+ pa.whitelist = whiteMap
|
|
+ pa.lockdown = lockMap
|
|
pa.blocklistMu.Unlock()
|
|
return nil
|
|
}
|
|
@@ -214,7 +229,7 @@ var (
|
|
// * exactly equal to an IANA registered TLD
|
|
//
|
|
// It does _not_ check that the domain isn't on any PA blocked lists.
|
|
-func ValidDomain(domain string) error {
|
|
+func (pa *AuthorityImpl) ValidDomain(domain string) error {
|
|
if domain == "" {
|
|
return errEmptyName
|
|
}
|
|
@@ -281,6 +296,14 @@ func ValidDomain(domain string) error {
|
|
}
|
|
}
|
|
|
|
+ ok, err := pa.checkWhitelist(domain)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ if ok {
|
|
+ return nil
|
|
+ }
|
|
+
|
|
// Names must end in an ICANN TLD, but they must not be equal to an ICANN TLD.
|
|
icannTLD, err := iana.ExtractSuffix(domain)
|
|
if err != nil {
|
|
@@ -308,7 +331,7 @@ var forbiddenMailDomains = map[string]bool{
|
|
// ValidEmail returns an error if the input doesn't parse as an email address,
|
|
// the domain isn't a valid hostname in Preferred Name Syntax, or its on the
|
|
// list of domains forbidden for mail (because they are often used in examples).
|
|
-func ValidEmail(address string) error {
|
|
+func (pa *AuthorityImpl) ValidEmail(address string) error {
|
|
email, err := mail.ParseAddress(address)
|
|
if err != nil {
|
|
if len(address) > 254 {
|
|
@@ -318,7 +341,7 @@ func ValidEmail(address string) error {
|
|
}
|
|
splitEmail := strings.SplitN(email.Address, "@", -1)
|
|
domain := strings.ToLower(splitEmail[len(splitEmail)-1])
|
|
- if err := ValidDomain(domain); err != nil {
|
|
+ if err := pa.ValidDomain(domain); err != nil {
|
|
return berrors.InvalidEmailError(
|
|
"contact email %q has invalid domain : %s",
|
|
email.Address, err)
|
|
@@ -357,10 +380,14 @@ func (pa *AuthorityImpl) WillingToIssue(id identifier.ACMEIdentifier) error {
|
|
}
|
|
domain := id.Value
|
|
|
|
- if err := ValidDomain(domain); err != nil {
|
|
+ if err := pa.ValidDomain(domain); err != nil {
|
|
return err
|
|
}
|
|
|
|
+ if ok, _ := pa.checkWhitelist(domain); ok {
|
|
+ return nil
|
|
+ }
|
|
+
|
|
// Require no match against hostname block lists
|
|
if err := pa.checkHostLists(domain); err != nil {
|
|
return err
|
|
@@ -369,6 +396,31 @@ func (pa *AuthorityImpl) WillingToIssue(id identifier.ACMEIdentifier) error {
|
|
return nil
|
|
}
|
|
|
|
+func (pa *AuthorityImpl) checkWhitelist(domain string) (bool, error) {
|
|
+ pa.blocklistMu.RLock()
|
|
+ defer pa.blocklistMu.RUnlock()
|
|
+
|
|
+ if (pa.whitelist == nil) || (pa.lockdown == nil) {
|
|
+ return false, fmt.Errorf("Hostname policy not yet loaded.")
|
|
+ }
|
|
+
|
|
+ labels := strings.Split(domain, ".")
|
|
+ for i := range labels {
|
|
+ joined := strings.Join(labels[i:], ".")
|
|
+ if pa.whitelist[joined] || pa.lockdown[joined] {
|
|
+ return true, nil
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if len(pa.lockdown) > 0 {
|
|
+ // In Lockdown mode, the domain MUST be in the list, so return an error if not found
|
|
+ return false, errPolicyForbidden
|
|
+ } else {
|
|
+ // In Whitelist mode, if the domain is not in the list, continue with the other checks
|
|
+ return false, nil
|
|
+ }
|
|
+}
|
|
+
|
|
// WillingToIssueWildcards is an extension of WillingToIssue that accepts DNS
|
|
// identifiers for well formed wildcard domains in addition to regular
|
|
// identifiers.
|