Skip to content
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
9 changes: 5 additions & 4 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,13 @@ type stdoutWriter struct {
isatty bool
}

// LogLineChecksum computes a CRC32 over the log line, which can be checked by
// log-validator to ensure no unexpected log corruption has occurred.
func LogLineChecksum(line string) string {
crc := crc32.ChecksumIEEE([]byte(line))
// Using the hash.Hash32 doesn't make this any easier
// as it also returns a uint32 rather than []byte
buf := make([]byte, binary.MaxVarintLen32)
binary.PutUvarint(buf, uint64(crc))
buf := make([]byte, crc32.Size)
// Error is unreachable because we provide a supported type and buffer size
_, _ = binary.Encode(buf, binary.LittleEndian, crc)
return base64.RawURLEncoding.EncodeToString(buf)
}

Expand Down
30 changes: 28 additions & 2 deletions log/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/jmhodges/clock"

"github.com/letsencrypt/boulder/test"
)

Expand Down Expand Up @@ -101,8 +102,8 @@ func TestStdoutLogger(t *testing.T) {
logger.Warning("Warning log")
logger.Info("Info log")

test.AssertEquals(t, stdout.String(), "1970-01-01 prefix 6 log.test pcbo7wk Info log\n")
test.AssertEquals(t, stderr.String(), "1970-01-01 prefix 3 log.test 46_ghQg [AUDIT] Error Audit\n1970-01-01 prefix 4 log.test 97r2xAw Warning log\n")
test.AssertEquals(t, stdout.String(), "1970-01-01 prefix 6 log.test JSP6nQ Info log\n")
test.AssertEquals(t, stderr.String(), "1970-01-01 prefix 3 log.test 4xe4gA [AUDIT] Error Audit\n1970-01-01 prefix 4 log.test d52dyA Warning log\n")
}

func TestSyslogMethods(t *testing.T) {
Expand Down Expand Up @@ -342,3 +343,28 @@ func TestLogAtLevelEscapesNewlines(t *testing.T) {

test.Assert(t, strings.Contains(buf.String(), "foo\\nbar"), "failed to escape newline")
}

func TestLogLineChecksum(t *testing.T) {
testCases := []struct {
name string
function func(string) string
input string
expected string
}{
{
name: "LogLineChecksum with Hello, World!",
function: LogLineChecksum,
input: "Hello, World!",
expected: "0MNK7A",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
checksum := tc.function(tc.input)
if checksum != tc.expected {
t.Fatalf("got %q, want %q", checksum, tc.expected)
}
})
}
}
7 changes: 4 additions & 3 deletions log/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ func lineValid(text string) error {
}
checksum := fields[5]
_, err := base64.RawURLEncoding.DecodeString(checksum)
if err != nil || len(checksum) != 7 {
if err != nil || len(checksum) != 6 {
return fmt.Errorf(
"%s expected a 7 character base64 raw URL decodable string, got %q: %w",
"%s expected a 6 character base64 raw URL decodable string, got %q: %w",
errorPrefix,
checksum,
errInvalidChecksum,
Expand All @@ -204,7 +204,8 @@ func lineValid(text string) error {
return nil
}
// Check the extracted checksum against the computed checksum
if computedChecksum := log.LogLineChecksum(line); checksum != computedChecksum {
computedChecksum := log.LogLineChecksum(line)
if checksum != computedChecksum {
return fmt.Errorf("%s invalid checksum (expected %q, got %q)", errorPrefix, computedChecksum, checksum)
}
return nil
Expand Down
15 changes: 10 additions & 5 deletions log/validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ import (
"github.com/letsencrypt/boulder/test"
)

func TestLineValidAccepts(t *testing.T) {
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: kKG6cwA Caught SIGTERM")
func TestLineValidAcceptsNew(t *testing.T) {
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: kJBuDg Caught SIGTERM")
test.AssertNotError(t, err, "errored on valid checksum")
}

func TestLineValidRejectsOld(t *testing.T) {
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: kKG6cwA Caught SIGTERM")
test.AssertError(t, err, "didn't error on old checksum format")
}

func TestLineValidRejects(t *testing.T) {
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: xxxxxxx Caught SIGTERM")
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: xxxxxx Caught SIGTERM")
test.AssertError(t, err, "didn't error on invalid checksum")
}

Expand All @@ -23,10 +28,10 @@ func TestLineValidRejectsNotAChecksum(t *testing.T) {
}

func TestLineValidNonOurobouros(t *testing.T) {
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: xxxxxxx Caught SIGTERM")
err := lineValid("2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 boulder-wfe[1595]: xxxxxx Caught SIGTERM")
test.AssertError(t, err, "didn't error on invalid checksum")

selfOutput := "2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 log-validator[1337]: xxxxxxx " + err.Error()
selfOutput := "2020-07-06T18:07:43.109389+00:00 70877f679c72 datacenter 6 log-validator[1337]: xxxxxx " + err.Error()
err2 := lineValid(selfOutput)
test.AssertNotError(t, err2, "expected no error when feeding lineValid's error output into itself")
}