Skip to content

Commit ded2e5e

Browse files
authored
Remove logging of contact email addresses (#7833)
Fixes #7801
1 parent c394831 commit ded2e5e

File tree

7 files changed

+37
-50
lines changed

7 files changed

+37
-50
lines changed

cmd/bad-key-revoker/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func (bkr *badKeyRevoker) revokeCerts(revokerEmails []string, emailToCerts map[s
284284
err := bkr.sendMessage(email, revokedSerials)
285285
if err != nil {
286286
mailErrors.Inc()
287-
bkr.logger.Errf("failed to send message to %q: %s", email, err)
287+
bkr.logger.Errf("failed to send message: %s", err)
288288
continue
289289
}
290290
}
@@ -370,9 +370,11 @@ func (bkr *badKeyRevoker) invoke(ctx context.Context) (bool, error) {
370370
}
371371
}
372372

373-
revokerEmails := idToEmails[unchecked.RevokedBy]
374-
bkr.logger.AuditInfo(fmt.Sprintf("revoking certs. revoked emails=%v, emailsToCerts=%s",
375-
revokerEmails, emailsToCerts))
373+
var serials []string
374+
for _, cert := range unrevokedCerts {
375+
serials = append(serials, cert.Serial)
376+
}
377+
bkr.logger.AuditInfo(fmt.Sprintf("revoking serials %v for key with hash %s", serials, unchecked.KeyHash))
376378

377379
// revoke each certificate and send emails to their owners
378380
err = bkr.revokeCerts(idToEmails[unchecked.RevokedBy], emailsToCerts)

cmd/expiration-mailer/main.go

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (lim *limiter) check(address string) error {
106106

107107
lim.maybeBumpDay()
108108
if lim.counts[address] >= lim.limit {
109-
return fmt.Errorf("daily mail limit exceeded for %q", address)
109+
return errors.New("daily mail limit exceeded for this email address")
110110
}
111111
return nil
112112
}
@@ -155,7 +155,7 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
155155
for _, contact := range contacts {
156156
parsed, err := url.Parse(contact)
157157
if err != nil {
158-
m.log.Errf("parsing contact email %s: %s", contact, err)
158+
m.log.Errf("parsing contact email: %s", err)
159159
continue
160160
}
161161
if parsed.Scheme != "mailto" {
@@ -164,7 +164,7 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
164164
address := parsed.Opaque
165165
err = policy.ValidEmail(address)
166166
if err != nil {
167-
m.log.Debugf("skipping invalid email %q: %s", address, err)
167+
m.log.Debugf("skipping invalid email: %s", err)
168168
continue
169169
}
170170
err = m.addressLimiter.check(address)
@@ -249,28 +249,24 @@ func (m *mailer) sendNags(conn bmail.Conn, contacts []string, certs []*x509.Cert
249249
}
250250

251251
logItem := struct {
252-
Rcpt []string
253252
DaysToExpiration int
254253
TruncatedDNSNames []string
255254
TruncatedSerials []string
256255
}{
257-
Rcpt: emails,
258256
DaysToExpiration: email.DaysToExpiration,
259257
TruncatedDNSNames: truncatedDomains,
260258
TruncatedSerials: truncatedSerials,
261259
}
262260
logStr, err := json.Marshal(logItem)
263261
if err != nil {
264-
m.log.Errf("logItem could not be serialized to JSON. Raw: %+v", logItem)
265-
return err
262+
return fmt.Errorf("failed to serialize log line: %w", err)
266263
}
267-
m.log.Infof("attempting send JSON=%s", string(logStr))
264+
m.log.Infof("attempting send for JSON=%s", string(logStr))
268265

269266
startSending := m.clk.Now()
270267
err = conn.SendMail(emails, subjBuf.String(), msgBuf.String())
271268
if err != nil {
272-
m.log.Errf("failed send JSON=%s err=%s", string(logStr), err)
273-
return err
269+
return fmt.Errorf("failed send for %s: %w", string(logStr), err)
274270
}
275271
finishSending := m.clk.Now()
276272
elapsed := finishSending.Sub(startSending)

cmd/expiration-mailer/main_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,10 @@ func TestSendNags(t *testing.T) {
180180
test.AssertErrorIs(t, err, errNoValidEmail)
181181
test.AssertEquals(t, len(mc.Messages), 0)
182182

183-
sendLogs := log.GetAllMatching("INFO: attempting send JSON=.*")
183+
sendLogs := log.GetAllMatching("INFO: attempting send for JSON=.*")
184184
if len(sendLogs) != 2 {
185185
t.Errorf("expected 2 'attempting send' log line, got %d: %s", len(sendLogs), strings.Join(sendLogs, "\n"))
186186
}
187-
if !strings.Contains(sendLogs[0], `"Rcpt":["[email protected]"]`) {
188-
t.Errorf("expected first 'attempting send' log line to have one address, got %q", sendLogs[0])
189-
}
190187
if !strings.Contains(sendLogs[0], `"TruncatedSerials":["000000000000000000000000000000000304"]`) {
191188
t.Errorf("expected first 'attempting send' log line to have one serial, got %q", sendLogs[0])
192189
}
@@ -196,6 +193,9 @@ func TestSendNags(t *testing.T) {
196193
if !strings.Contains(sendLogs[0], `"TruncatedDNSNames":["example.com"]`) {
197194
t.Errorf("expected first 'attempting send' log line to have 1 domain, 'example.com', got %q", sendLogs[0])
198195
}
196+
if strings.Contains(sendLogs[0], `"@gmail.com"`) {
197+
t.Errorf("log line should not contain email address, got %q", sendLogs[0])
198+
}
199199
}
200200

201201
func TestSendNagsAddressLimited(t *testing.T) {

policy/pa.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -336,23 +336,18 @@ var forbiddenMailDomains = map[string]bool{
336336
func ValidEmail(address string) error {
337337
email, err := mail.ParseAddress(address)
338338
if err != nil {
339-
if len(address) > 254 {
340-
address = address[:254] + "..."
341-
}
342-
return berrors.InvalidEmailError("%q is not a valid e-mail address", address)
339+
return berrors.InvalidEmailError("unable to parse email address")
343340
}
344341
splitEmail := strings.SplitN(email.Address, "@", -1)
345342
domain := strings.ToLower(splitEmail[len(splitEmail)-1])
346343
err = validNonWildcardDomain(domain)
347344
if err != nil {
348-
return berrors.InvalidEmailError(
349-
"contact email %q has invalid domain : %s",
350-
email.Address, err)
345+
return berrors.InvalidEmailError("contact email has invalid domain: %s", err)
351346
}
352347
if forbiddenMailDomains[domain] {
353-
return berrors.InvalidEmailError(
354-
"invalid contact domain. Contact emails @%s are forbidden",
355-
domain)
348+
// We're okay including the domain in the error message here because this
349+
// case occurs only for a small block-list of domains listed above.
350+
return berrors.InvalidEmailError("contact email has forbidden domain %q", domain)
356351
}
357352
return nil
358353
}

policy/pa_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,16 +473,16 @@ func TestMalformedExactBlocklist(t *testing.T) {
473473

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

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

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

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

488488
func TestCheckAuthzChallenges(t *testing.T) {

ra/ra.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -464,19 +464,16 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error {
464464
return berrors.InvalidEmailError("invalid contact")
465465
}
466466
if parsed.Scheme != "mailto" {
467-
return berrors.UnsupportedContactError("contact method %q is not supported", parsed.Scheme)
467+
return berrors.UnsupportedContactError("only contact scheme 'mailto:' is supported")
468468
}
469469
if parsed.RawQuery != "" || contact[len(contact)-1] == '?' {
470-
return berrors.InvalidEmailError("contact email %q contains a question mark", contact)
470+
return berrors.InvalidEmailError("contact email contains a question mark")
471471
}
472472
if parsed.Fragment != "" || contact[len(contact)-1] == '#' {
473-
return berrors.InvalidEmailError("contact email %q contains a '#'", contact)
473+
return berrors.InvalidEmailError("contact email contains a '#'")
474474
}
475475
if !core.IsASCII(contact) {
476-
return berrors.InvalidEmailError(
477-
"contact email [%q] contains non-ASCII characters",
478-
contact,
479-
)
476+
return berrors.InvalidEmailError("contact email contains non-ASCII characters")
480477
}
481478
err = policy.ValidEmail(parsed.Opaque)
482479
if err != nil {
@@ -490,10 +487,7 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []string) error {
490487
// That means the largest marshalled JSON value we can store is 191 bytes.
491488
const maxContactBytes = 191
492489
if jsonBytes, err := json.Marshal(contacts); err != nil {
493-
// This shouldn't happen with a simple []string but if it does we want the
494-
// error to be logged internally but served as a 500 to the user so we
495-
// return a bare error and not a berror here.
496-
return fmt.Errorf("failed to marshal reg.Contact to JSON: %#v", contacts)
490+
return fmt.Errorf("failed to marshal reg.Contact to JSON: %w", err)
497491
} else if len(jsonBytes) >= maxContactBytes {
498492
return berrors.InvalidEmailError(
499493
"too many/too long contact(s). Please use shorter or fewer email addresses")

test/integration/errors_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ func TestAccountEmailError(t *testing.T) {
6666
name: "empty proto",
6767
contacts: []string{"mailto:[email protected]", " "},
6868
expectedProbType: "urn:ietf:params:acme:error:unsupportedContact",
69-
expectedProbDetail: `contact method "" is not supported`,
69+
expectedProbDetail: `only contact scheme 'mailto:' is supported`,
7070
},
7171
{
7272
name: "empty mailto",
7373
contacts: []string{"mailto:[email protected]", "mailto:"},
7474
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
75-
expectedProbDetail: `"" is not a valid e-mail address`,
75+
expectedProbDetail: `unable to parse email address`,
7676
},
7777
{
7878
name: "non-ascii mailto",
7979
contacts: []string{"mailto:[email protected]", "mailto:cpu@l̴etsencrypt.org"},
8080
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
81-
expectedProbDetail: `contact email ["mailto:cpu@l̴etsencrypt.org"] contains non-ASCII characters`,
81+
expectedProbDetail: `contact email contains non-ASCII characters`,
8282
},
8383
{
8484
name: "too many contacts",
@@ -90,25 +90,25 @@ func TestAccountEmailError(t *testing.T) {
9090
name: "invalid contact",
9191
contacts: []string{"mailto:[email protected]", "mailto:a@"},
9292
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
93-
expectedProbDetail: `"a@" is not a valid e-mail address`,
93+
expectedProbDetail: `unable to parse email address`,
9494
},
9595
{
9696
name: "forbidden contact domain",
9797
contacts: []string{"mailto:[email protected]", "mailto:[email protected]"},
9898
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
99-
expectedProbDetail: "invalid contact domain. Contact emails @example.com are forbidden",
99+
expectedProbDetail: "contact email has forbidden domain \"example.com\"",
100100
},
101101
{
102102
name: "contact domain invalid TLD",
103103
contacts: []string{"mailto:[email protected]", "mailto:[email protected]"},
104104
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
105-
expectedProbDetail: `contact email "[email protected]" has invalid domain : Domain name does not end with a valid public suffix (TLD)`,
105+
expectedProbDetail: `contact email has invalid domain: Domain name does not end with a valid public suffix (TLD)`,
106106
},
107107
{
108108
name: "contact domain invalid",
109109
contacts: []string{"mailto:[email protected]", "mailto:a@example./.com"},
110110
expectedProbType: "urn:ietf:params:acme:error:invalidContact",
111-
expectedProbDetail: "contact email \"a@example./.com\" has invalid domain : Domain name contains an invalid character",
111+
expectedProbDetail: "contact email has invalid domain: Domain name contains an invalid character",
112112
},
113113
{
114114
name: "too long contact",

0 commit comments

Comments
 (0)