Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove logging of contact email addresses #7833

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
10 changes: 6 additions & 4 deletions cmd/bad-key-revoker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func (bkr *badKeyRevoker) revokeCerts(revokerEmails []string, emailToCerts map[s
err := bkr.sendMessage(email, revokedSerials)
if err != nil {
mailErrors.Inc()
bkr.logger.Errf("failed to send message to %q: %s", email, err)
bkr.logger.Errf("failed to send message: %s", err)
continue
}
}
Expand Down Expand Up @@ -370,9 +370,11 @@ func (bkr *badKeyRevoker) invoke(ctx context.Context) (bool, error) {
}
}

revokerEmails := idToEmails[unchecked.RevokedBy]
bkr.logger.AuditInfo(fmt.Sprintf("revoking certs. revoked emails=%v, emailsToCerts=%s",
revokerEmails, emailsToCerts))
serials := make([]string, 0)
for _, cert := range unrevokedCerts {
serials = append(serials, cert.Serial)
}
bkr.logger.AuditInfo(fmt.Sprintf("revoking serials %v for key with hash %s", serials, unchecked.KeyHash))

// revoke each certificate and send emails to their owners
err = bkr.revokeCerts(idToEmails[unchecked.RevokedBy], emailsToCerts)
Expand Down
16 changes: 6 additions & 10 deletions cmd/expiration-mailer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (lim *limiter) check(address string) error {

lim.maybeBumpDay()
if lim.counts[address] >= lim.limit {
return fmt.Errorf("daily mail limit exceeded for %q", address)
return errors.New("daily mail limit exceeded for this email address")
}
return nil
}
Expand Down Expand Up @@ -155,7 +155,7 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
for _, contact := range contacts {
parsed, err := url.Parse(contact)
if err != nil {
m.log.Errf("parsing contact email %s: %s", contact, err)
m.log.Errf("parsing contact email: %s", err)
continue
}
if parsed.Scheme != "mailto" {
Expand All @@ -164,7 +164,7 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
address := parsed.Opaque
err = policy.ValidEmail(address)
if err != nil {
m.log.Debugf("skipping invalid email %q: %s", address, err)
m.log.Debugf("skipping invalid email: %s", err)
continue
}
err = m.addressLimiter.check(address)
Expand Down Expand Up @@ -249,28 +249,24 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
}

logItem := struct {
Rcpt []string
DaysToExpiration int
TruncatedDNSNames []string
TruncatedSerials []string
}{
Rcpt: emails,
DaysToExpiration: email.DaysToExpiration,
TruncatedDNSNames: truncatedDomains,
TruncatedSerials: truncatedSerials,
}
logStr, err := json.Marshal(logItem)
if err != nil {
m.log.Errf("logItem could not be serialized to JSON. Raw: %+v", logItem)
return err
return fmt.Errorf("failed to serialize log line: %w", err)
}
m.log.Infof("attempting send JSON=%s", string(logStr))
m.log.Infof("attempting send for JSON=%s", string(logStr))

startSending := m.clk.Now()
err = conn.SendMail(emails, subjBuf.String(), msgBuf.String())
if err != nil {
m.log.Errf("failed send JSON=%s err=%s", string(logStr), err)
return err
return fmt.Errorf("failed send for %s: %w", string(logStr), err)
}
finishSending := m.clk.Now()
elapsed := finishSending.Sub(startSending)
Expand Down
8 changes: 4 additions & 4 deletions cmd/expiration-mailer/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,10 @@ func TestSendNags(t *testing.T) {
test.AssertErrorIs(t, err, errNoValidEmail)
test.AssertEquals(t, len(mc.Messages), 0)

sendLogs := log.GetAllMatching("INFO: attempting send JSON=.*")
sendLogs := log.GetAllMatching("INFO: attempting send for JSON=.*")
if len(sendLogs) != 2 {
t.Errorf("expected 2 'attempting send' log line, got %d: %s", len(sendLogs), strings.Join(sendLogs, "\n"))
}
if !strings.Contains(sendLogs[0], `"Rcpt":["[email protected]"]`) {
t.Errorf("expected first 'attempting send' log line to have one address, got %q", sendLogs[0])
}
if !strings.Contains(sendLogs[0], `"TruncatedSerials":["000000000000000000000000000000000304"]`) {
t.Errorf("expected first 'attempting send' log line to have one serial, got %q", sendLogs[0])
}
Expand All @@ -196,6 +193,9 @@ func TestSendNags(t *testing.T) {
if !strings.Contains(sendLogs[0], `"TruncatedDNSNames":["example.com"]`) {
t.Errorf("expected first 'attempting send' log line to have 1 domain, 'example.com', got %q", sendLogs[0])
}
if strings.Contains(sendLogs[0], `"@gmail.com"`) {
t.Errorf("log line should not contain email address, got %q", sendLogs[0])
}
}

func TestSendNagsAddressLimited(t *testing.T) {
Expand Down
15 changes: 5 additions & 10 deletions policy/pa.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,23 +336,18 @@ var forbiddenMailDomains = map[string]bool{
func ValidEmail(address string) error {
email, err := mail.ParseAddress(address)
if err != nil {
if len(address) > 254 {
address = address[:254] + "..."
}
return berrors.InvalidEmailError("%q is not a valid e-mail address", address)
return berrors.InvalidEmailError("unable to parse email address")
}
splitEmail := strings.SplitN(email.Address, "@", -1)
domain := strings.ToLower(splitEmail[len(splitEmail)-1])
err = validNonWildcardDomain(domain)
if err != nil {
return berrors.InvalidEmailError(
"contact email %q has invalid domain : %s",
email.Address, err)
return berrors.InvalidEmailError("contact email has invalid domain: %s", err)
}
if forbiddenMailDomains[domain] {
return berrors.InvalidEmailError(
"invalid contact domain. Contact emails @%s are forbidden",
aarongable marked this conversation as resolved.
Show resolved Hide resolved
domain)
// We're okay including the domain in the error message here because this
// case occurs only for a small block-list of domains listed above.
return berrors.InvalidEmailError("contact email has forbidden domain %q", domain)
}
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions policy/pa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,16 +473,16 @@ func TestMalformedExactBlocklist(t *testing.T) {

func TestValidEmailError(t *testing.T) {
err := ValidEmail("(๑•́ ω •̀๑)")
test.AssertEquals(t, err.Error(), "\"(๑•́ ω •̀๑)\" is not a valid e-mail address")
test.AssertEquals(t, err.Error(), "unable to parse email address")

err = ValidEmail("[email protected] #replace with real email")
test.AssertEquals(t, err.Error(), "\"[email protected] #replace with real email\" is not a valid e-mail address")
test.AssertEquals(t, err.Error(), "unable to parse email address")

err = ValidEmail("[email protected]")
test.AssertEquals(t, err.Error(), "invalid contact domain. Contact emails @example.com are forbidden")
test.AssertEquals(t, err.Error(), "contact email has forbidden domain \"example.com\"")

err = ValidEmail("[email protected]")
test.AssertEquals(t, err.Error(), "contact email \"[email protected]\" has invalid domain : Domain name contains an invalid character")
test.AssertEquals(t, err.Error(), "contact email has invalid domain: Domain name contains an invalid character")
}

func TestCheckAuthzChallenges(t *testing.T) {
Expand Down
16 changes: 5 additions & 11 deletions ra/ra.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,19 +464,16 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error {
return berrors.InvalidEmailError("invalid contact")
}
if parsed.Scheme != "mailto" {
return berrors.UnsupportedContactError("contact method %q is not supported", parsed.Scheme)
return berrors.UnsupportedContactError("only contact scheme 'mailto:' is supported")
}
if parsed.RawQuery != "" || contact[len(contact)-1] == '?' {
return berrors.InvalidEmailError("contact email %q contains a question mark", contact)
return berrors.InvalidEmailError("contact email contains a question mark")
}
if parsed.Fragment != "" || contact[len(contact)-1] == '#' {
return berrors.InvalidEmailError("contact email %q contains a '#'", contact)
return berrors.InvalidEmailError("contact email contains a '#'")
}
if !core.IsASCII(contact) {
return berrors.InvalidEmailError(
"contact email [%q] contains non-ASCII characters",
contact,
)
return berrors.InvalidEmailError("contact email contains non-ASCII characters")
}
err = policy.ValidEmail(parsed.Opaque)
if err != nil {
Expand All @@ -490,10 +487,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error {
// That means the largest marshalled JSON value we can store is 191 bytes.
const maxContactBytes = 191
if jsonBytes, err := json.Marshal(contacts); err != nil {
// This shouldn't happen with a simple []string but if it does we want the
// error to be logged internally but served as a 500 to the user so we
// return a bare error and not a berror here.
return fmt.Errorf("failed to marshal reg.Contact to JSON: %#v", contacts)
return fmt.Errorf("failed to marshal reg.Contact to JSON: %w", err)
} else if len(jsonBytes) >= maxContactBytes {
return berrors.InvalidEmailError(
"too many/too long contact(s). Please use shorter or fewer email addresses")
Expand Down
14 changes: 7 additions & 7 deletions test/integration/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@ func TestAccountEmailError(t *testing.T) {
name: "empty proto",
contacts: []string{"mailto:[email protected]", " "},
expectedProbType: "urn:ietf:params:acme:error:unsupportedContact",
expectedProbDetail: `contact method "" is not supported`,
expectedProbDetail: `only contact scheme 'mailto:' is supported`,
},
{
name: "empty mailto",
contacts: []string{"mailto:[email protected]", "mailto:"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: `"" is not a valid e-mail address`,
expectedProbDetail: `unable to parse email address`,
},
{
name: "non-ascii mailto",
contacts: []string{"mailto:[email protected]", "mailto:cpu@l̴etsencrypt.org"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: `contact email ["mailto:cpu@l̴etsencrypt.org"] contains non-ASCII characters`,
expectedProbDetail: `contact email contains non-ASCII characters`,
},
{
name: "too many contacts",
Expand All @@ -90,25 +90,25 @@ func TestAccountEmailError(t *testing.T) {
name: "invalid contact",
contacts: []string{"mailto:[email protected]", "mailto:a@"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: `"a@" is not a valid e-mail address`,
expectedProbDetail: `unable to parse email address`,
},
{
name: "forbidden contact domain",
contacts: []string{"mailto:[email protected]", "mailto:[email protected]"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: "invalid contact domain. Contact emails @example.com are forbidden",
expectedProbDetail: "contact email has forbidden domain \"example.com\"",
},
{
name: "contact domain invalid TLD",
contacts: []string{"mailto:[email protected]", "mailto:[email protected]"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: `contact email "[email protected]" has invalid domain : Domain name does not end with a valid public suffix (TLD)`,
expectedProbDetail: `contact email has invalid domain: Domain name does not end with a valid public suffix (TLD)`,
},
{
name: "contact domain invalid",
contacts: []string{"mailto:[email protected]", "mailto:a@example./.com"},
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
expectedProbDetail: "contact email \"a@example./.com\" has invalid domain : Domain name contains an invalid character",
expectedProbDetail: "contact email has invalid domain: Domain name contains an invalid character",
},
{
name: "too long contact",
Expand Down
Loading