diff --git a/va/validation-authority.go b/va/validation-authority.go index 0da035d05..7f77f13f8 100644 --- a/va/validation-authority.go +++ b/va/validation-authority.go @@ -373,8 +373,9 @@ func (va *ValidationAuthorityImpl) validateHTTP01(ctx context.Context, identifie } if expectedKeyAuth != payload { + truncBody := truncateBody(payload) errString := fmt.Sprintf("The key authorization file from the server did not match this challenge [%v] != [%v]", - expectedKeyAuth, string(body)) + expectedKeyAuth, truncBody) va.log.Info(fmt.Sprintf("%s for %s", errString, identifier)) return validationRecords, &probs.ProblemDetails{ Type: probs.UnauthorizedProblem, @@ -385,6 +386,19 @@ func (va *ValidationAuthorityImpl) validateHTTP01(ctx context.Context, identifie return validationRecords, nil } +// truncateBody will cut off a string at 45 UTF-8 characters. +func truncateBody(str string) string { + count := 0 + const max = 45 + for index, _ := range str { + count++ + if count > max { + return fmt.Sprintf("%s…", str[:index]) + } + } + return str +} + func (va *ValidationAuthorityImpl) validateTLSSNI01(ctx context.Context, identifier core.AcmeIdentifier, challenge core.Challenge) ([]core.ValidationRecord, *probs.ProblemDetails) { if identifier.Type != "dns" { va.log.Info(fmt.Sprintf("Identifier type for TLS-SNI was not DNS: %s", identifier)) diff --git a/va/validation-authority_test.go b/va/validation-authority_test.go index 72572bc4a..784172578 100644 --- a/va/validation-authority_test.go +++ b/va/validation-authority_test.go @@ -541,6 +541,36 @@ func TestValidateHTTP(t *testing.T) { test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status) } +func TestValidateHTTPResponseDocument(t *testing.T) { + chall := core.HTTPChallenge01(accountKey) + setChallengeToken(&chall, core.NewToken()) + + hs := httpSrv(t, `a.StartOfLine.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.PastTruncationPoint.aaaaaaaaaaaaaaaaaaaa`) + port, err := getPort(hs) + test.AssertNotError(t, err, "failed to get test server port") + stats, _ := statsd.NewNoopClient() + va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default()) + va.DNSResolver = &bdns.MockDNSResolver{} + mockRA := &MockRegistrationAuthority{} + va.RA = mockRA + + defer hs.Close() + + var authz = core.Authorization{ + ID: core.NewToken(), + RegistrationID: 1, + Identifier: ident, + Challenges: []core.Challenge{chall}, + } + va.validate(ctx, authz, 0) + + test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status) + test.Assert(t, len(log.GetAllMatching("StartOfLine")) > 1, "Beginning of response body not logged") + test.Assert(t, len(log.GetAllMatching("…")) > 1, "Ellipsis not logged") + test.AssertEquals(t, len(log.GetAllMatching("PastTruncationPoint")), 0) // End of response body was logged + +} + // challengeType == "tls-sni-00" or "dns-00", since they're the same func createChallenge(challengeType string) core.Challenge { chall := core.Challenge{ @@ -1008,6 +1038,27 @@ func TestCAAFailure(t *testing.T) { test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status) } +func TestTruncateBody(t *testing.T) { + testCases := []struct { + Case string + Expected string + }{ + {"", ""}, + {"a", "a"}, + {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…"}, + {"ááááááááááááááááááááááááááááááááááááááááááááá", "ááááááááááááááááááááááááááááááááááááááááááááá"}, + {"áááááááááááááááááááááááááááááááááááááááááááááá", "ááááááááááááááááááááááááááááááááááááááááááááá…"}, + } + + for _, v := range testCases { + result := truncateBody(v.Case) + if result != v.Expected { + t.Errorf("got %q, expected %q", result, v.Expected) + } + } +} + type MockRegistrationAuthority struct { lastAuthz *core.Authorization }