Compare commits

...

No commits in common. "af04121ff6aa4976f5619dee92646ef261d02825" and "1d562e7aa4c29b139d5eb4705813d4e4f407ce1d" have entirely different histories.

2 changed files with 23 additions and 16 deletions

View file

@ -36,6 +36,7 @@ func (p *caaProvider) ParseForm(r *http.Request) (sdk.CheckerOptions, error) {
return nil, errors.New("domain is required") return nil, errors.New("domain is required")
} }
domain = dns.Fqdn(domain) domain = dns.Fqdn(domain)
bare := strings.TrimSuffix(domain, ".")
records, err := lookupCAA(domain) records, err := lookupCAA(domain)
if err != nil { if err != nil {
@ -55,12 +56,12 @@ func (p *caaProvider) ParseForm(r *http.Request) (sdk.CheckerOptions, error) {
svc := serviceMessage{ svc := serviceMessage{
Type: serviceType, Type: serviceType,
Domain: strings.TrimSuffix(domain, "."), Domain: bare,
Service: svcBody, Service: svcBody,
} }
return sdk.CheckerOptions{ return sdk.CheckerOptions{
"domain": strings.TrimSuffix(domain, "."), "domain": bare,
"service": svc, "service": svc,
}, nil }, nil
} }
@ -74,12 +75,12 @@ func lookupCAA(fqdn string) ([]CAARecord, error) {
return nil, err return nil, err
} }
c := new(dns.Client)
for name := fqdn; name != "" && name != "."; { for name := fqdn; name != "" && name != "."; {
msg := new(dns.Msg) msg := new(dns.Msg)
msg.SetQuestion(name, dns.TypeCAA) msg.SetQuestion(name, dns.TypeCAA)
msg.RecursionDesired = true msg.RecursionDesired = true
c := new(dns.Client)
in, _, err := c.Exchange(msg, resolver) in, _, err := c.Exchange(msg, resolver)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -32,7 +32,6 @@ type issuerAgg struct {
severity string severity string
code string code string
msg string msg string
fix string
endpoints map[string]bool endpoints map[string]bool
} }
@ -117,7 +116,7 @@ func (r *caaRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
// info just because one probe happened to be unresolvable. // info just because one probe happened to be unresolvable.
agg := map[string]*issuerAgg{} // keyed by AKI+DN agg := map[string]*issuerAgg{} // keyed by AKI+DN
issue := func(p *tlsProbeView, severity, code, msg, fix string) { issue := func(p *tlsProbeView, severity, code, msg string) {
k := p.IssuerAKI + "|" + p.IssuerDN k := p.IssuerAKI + "|" + p.IssuerDN
cur, ok := agg[k] cur, ok := agg[k]
if !ok { if !ok {
@ -128,7 +127,6 @@ func (r *caaRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
cur.severity = severity cur.severity = severity
cur.code = code cur.code = code
cur.msg = msg cur.msg = msg
cur.fix = fix
} }
if addr := p.address(); addr != "" { if addr := p.address(); addr != "" {
cur.endpoints[addr] = true cur.endpoints[addr] = true
@ -138,16 +136,14 @@ func (r *caaRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
for _, p := range probes { for _, p := range probes {
if al.disallowIssue { if al.disallowIssue {
issue(p, SeverityCrit, CodeIssuanceDisallowed, issue(p, SeverityCrit, CodeIssuanceDisallowed,
fmt.Sprintf("CAA policy forbids issuance (issue \";\") but a certificate was observed on %s", p.address()), fmt.Sprintf("CAA policy forbids issuance (issue \";\") but a certificate was observed on %s", p.address()))
"Remove the CA 0 issue \";\" record, or stop serving TLS certificates for this domain.")
continue continue
} }
domains, ok := Lookup(p.IssuerAKI, p.IssuerDN) domains, ok := Lookup(p.IssuerAKI, p.IssuerDN)
if !ok { if !ok {
issue(p, SeverityInfo, CodeIssuerUnknown, issue(p, SeverityInfo, CodeIssuerUnknown,
fmt.Sprintf("Observed issuer not found in CCADB (AKI=%q, DN=%q)", p.IssuerAKI, p.IssuerDN), fmt.Sprintf("Observed issuer not found in CCADB (AKI=%q, DN=%q)", p.IssuerAKI, p.IssuerDN))
"File a CCADB update for this CA, or verify the cert was issued by a real CA.")
continue continue
} }
@ -158,21 +154,18 @@ func (r *caaRule) Evaluate(ctx context.Context, obs sdk.ObservationGetter, opts
if !hasPolicy { if !hasPolicy {
issue(p, SeverityInfo, CodeOK, issue(p, SeverityInfo, CodeOK,
fmt.Sprintf("No CAA records published; certificate on %s issued by %s (CAA identifier %s).", fmt.Sprintf("No CAA records published; certificate on %s issued by %s (CAA identifier %s).",
p.address(), issuerLabel(p), strings.Join(domains, ", ")), p.address(), issuerLabel(p), strings.Join(domains, ", ")))
fmt.Sprintf("Publish %q IN CAA 0 issue %q to lock future issuance to %s.",
data.Domain, domains[0], domains[0]))
continue continue
} }
if !intersects(domains, al.issueAll) { if !intersects(domains, al.issueAll) {
issue(p, SeverityCrit, CodeNotAuthorized, issue(p, SeverityCrit, CodeNotAuthorized,
fmt.Sprintf("Certificate on %s issued by %s (CAA identifier %s) is not authorized by the zone's CAA issue records", fmt.Sprintf("Certificate on %s issued by %s (CAA identifier %s) is not authorized by the zone's CAA issue records",
p.address(), issuerLabel(p), strings.Join(domains, ", ")), p.address(), issuerLabel(p), strings.Join(domains, ", ")))
"Either update the CAA record to authorize this CA, or re-issue with an authorized CA.")
continue continue
} }
issue(p, "", "", "", "") issue(p, "", "", "")
} }
// Emit one CheckState per distinct issuer, keyed deterministically so // Emit one CheckState per distinct issuer, keyed deterministically so
@ -239,6 +232,19 @@ func severityRank(s string) int {
} }
} }
func severityToStatus(s string) sdk.Status {
switch s {
case SeverityCrit:
return sdk.StatusCrit
case SeverityWarn:
return sdk.StatusWarn
case SeverityInfo:
return sdk.StatusInfo
default:
return sdk.StatusOK
}
}
// intersects reports whether any element of lhs is present in the set. // intersects reports whether any element of lhs is present in the set.
func intersects(lhs []string, set map[string]bool) bool { func intersects(lhs []string, set map[string]bool) bool {
for _, s := range lhs { for _, s := range lhs {