From acc6781f296d7a7644d5544964d5057317629cc2 Mon Sep 17 00:00:00 2001 From: Jonathan Rudenberg Date: Thu, 28 Jul 2016 14:55:46 -0400 Subject: [PATCH] Run gofmt Signed-off-by: Jonathan Rudenberg --- asn1.go | 17 ++-- asn1time.go | 96 +++++++++++++++------- asn1time_test.go | 111 +++++++++++++------------ auditing.go | 26 +++--- cmd/certspotter/main.go | 53 ++++++------ cmd/common.go | 42 +++++----- cmd/ctparsewatch/main.go | 14 ++-- ct/client/logclient.go | 12 +-- ct/types.go | 6 +- helpers.go | 160 ++++++++++++++++++------------------ helpers_test.go | 2 +- identifiers.go | 62 +++++++------- logs.go | 24 +++--- precerts.go | 37 +++++---- scanner.go | 26 +++--- x509.go | 173 ++++++++++++++++++++------------------- 16 files changed, 451 insertions(+), 410 deletions(-) diff --git a/asn1.go b/asn1.go index a775641..279ae57 100644 --- a/asn1.go +++ b/asn1.go @@ -10,14 +10,14 @@ package certspotter import ( - "errors" "bytes" - "encoding/binary" "encoding/asn1" + "encoding/binary" + "errors" "unicode/utf8" ) -func stringFromByteSlice (chars []byte) string { +func stringFromByteSlice(chars []byte) string { runes := make([]rune, len(chars)) for i, ch := range chars { runes[i] = rune(ch) @@ -25,7 +25,7 @@ func stringFromByteSlice (chars []byte) string { return string(runes) } -func stringFromUint16Slice (chars []uint16) string { +func stringFromUint16Slice(chars []uint16) string { runes := make([]rune, len(chars)) for i, ch := range chars { runes[i] = rune(ch) @@ -33,7 +33,7 @@ func stringFromUint16Slice (chars []uint16) string { return string(runes) } -func stringFromUint32Slice (chars []uint32) string { +func stringFromUint32Slice(chars []uint32) string { runes := make([]rune, len(chars)) for i, ch := range chars { runes[i] = rune(ch) @@ -41,7 +41,7 @@ func stringFromUint32Slice (chars []uint32) string { return string(runes) } -func decodeASN1String (value *asn1.RawValue) (string, error) { +func decodeASN1String(value *asn1.RawValue) (string, error) { if !value.IsCompound && value.Class == 0 { if value.Tag == 12 { // UTF8String @@ -59,14 +59,14 @@ func decodeASN1String (value *asn1.RawValue) (string, error) { return stringFromByteSlice(value.Bytes), nil } else if value.Tag == 30 { // BMPString - Unicode, encoded in big-endian format using two octets - runes := make([]uint16, len(value.Bytes) / 2) + runes := make([]uint16, len(value.Bytes)/2) if err := binary.Read(bytes.NewReader(value.Bytes), binary.BigEndian, runes); err != nil { return "", errors.New("Malformed BMPString: " + err.Error()) } return stringFromUint16Slice(runes), nil } else if value.Tag == 28 { // UniversalString - Unicode, encoded in big-endian format using four octets - runes := make([]uint32, len(value.Bytes) / 4) + runes := make([]uint32, len(value.Bytes)/4) if err := binary.Read(bytes.NewReader(value.Bytes), binary.BigEndian, runes); err != nil { return "", errors.New("Malformed UniversalString: " + err.Error()) } @@ -75,4 +75,3 @@ func decodeASN1String (value *asn1.RawValue) (string, error) { } return "", errors.New("Not a string") } - diff --git a/asn1time.go b/asn1time.go index c545820..29e0d8a 100644 --- a/asn1time.go +++ b/asn1time.go @@ -10,22 +10,22 @@ package certspotter import ( - "time" - "strconv" - "errors" - "unicode" "encoding/asn1" + "errors" + "strconv" + "time" + "unicode" ) -func isDigit (b byte) bool { +func isDigit(b byte) bool { return unicode.IsDigit(rune(b)) } -func bytesToInt (bytes []byte) (int, error) { +func bytesToInt(bytes []byte) (int, error) { return strconv.Atoi(string(bytes)) } -func parseUTCTime (bytes []byte) (time.Time, error) { +func parseUTCTime(bytes []byte) (time.Time, error) { var err error var year, month, day int var hour, min, sec int @@ -36,19 +36,29 @@ func parseUTCTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("UTCTime is too short") } year, err = bytesToInt(bytes[0:2]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } month, err = bytesToInt(bytes[2:4]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } day, err = bytesToInt(bytes[4:6]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } hour, err = bytesToInt(bytes[6:8]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } min, err = bytesToInt(bytes[8:10]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } bytes = bytes[10:] @@ -72,12 +82,16 @@ func parseUTCTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("UTCTime positive timezone offset is too short") } tzHour, err := bytesToInt(bytes[1:3]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } tzMin, err := bytesToInt(bytes[3:5]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } - tz = time.FixedZone("", tzHour * 3600 + tzMin * 60) + tz = time.FixedZone("", tzHour*3600+tzMin*60) bytes = bytes[5:] } else if bytes[0] == '-' { // -hhmm @@ -85,12 +99,16 @@ func parseUTCTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("UTCTime negative timezone offset is too short") } tzHour, err := bytesToInt(bytes[1:3]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } tzMin, err := bytesToInt(bytes[3:5]) - if err != nil { return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("UTCTime contains invalid integer: " + err.Error()) + } - tz = time.FixedZone("", -1 * (tzHour * 3600 + tzMin * 60)) + tz = time.FixedZone("", -1*(tzHour*3600+tzMin*60)) bytes = bytes[5:] } } else { @@ -111,7 +129,7 @@ func parseUTCTime (bytes []byte) (time.Time, error) { return time.Date(year, time.Month(month), day, hour, min, sec, 0, tz), nil } -func parseGeneralizedTime (bytes []byte) (time.Time, error) { +func parseGeneralizedTime(bytes []byte) (time.Time, error) { var err error var year, month, day int var hour, min, sec, ms int @@ -122,16 +140,24 @@ func parseGeneralizedTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("GeneralizedTime is too short") } year, err = bytesToInt(bytes[0:4]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } month, err = bytesToInt(bytes[4:6]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } day, err = bytesToInt(bytes[6:8]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } hour, err = bytesToInt(bytes[8:10]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } bytes = bytes[10:] @@ -174,12 +200,16 @@ func parseGeneralizedTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("GeneralizedTime positive timezone offset is too short") } tzHour, err := bytesToInt(bytes[1:3]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } tzMin, err := bytesToInt(bytes[3:5]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } - tz = time.FixedZone("", tzHour * 3600 + tzMin * 60) + tz = time.FixedZone("", tzHour*3600+tzMin*60) bytes = bytes[5:] } else if bytes[0] == '-' { // -hhmm @@ -187,12 +217,16 @@ func parseGeneralizedTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("GeneralizedTime negative timezone offset is too short") } tzHour, err := bytesToInt(bytes[1:3]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } tzMin, err := bytesToInt(bytes[3:5]) - if err != nil { return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) } + if err != nil { + return time.Time{}, errors.New("GeneralizedTime contains invalid integer: " + err.Error()) + } - tz = time.FixedZone("", -1 * (tzHour * 3600 + tzMin * 60)) + tz = time.FixedZone("", -1*(tzHour*3600+tzMin*60)) bytes = bytes[5:] } } else { @@ -203,10 +237,10 @@ func parseGeneralizedTime (bytes []byte) (time.Time, error) { return time.Time{}, errors.New("GeneralizedTime has trailing garbage") } - return time.Date(year, time.Month(month), day, hour, min, sec, ms * 1000 * 1000, tz), nil + return time.Date(year, time.Month(month), day, hour, min, sec, ms*1000*1000, tz), nil } -func decodeASN1Time (value *asn1.RawValue) (time.Time, error) { +func decodeASN1Time(value *asn1.RawValue) (time.Time, error) { if !value.IsCompound && value.Class == 0 { if value.Tag == asn1.TagUTCTime { return parseUTCTime(value.Bytes) diff --git a/asn1time_test.go b/asn1time_test.go index 54b3ebf..9ecbec2 100644 --- a/asn1time_test.go +++ b/asn1time_test.go @@ -15,31 +15,31 @@ import ( ) type timeTest struct { - in string - ok bool - out time.Time + in string + ok bool + out time.Time } var utcTimeTests = []timeTest{ - { "9502101525Z", true, time.Date(1995, time.February, 10, 15, 25, 0, 0, time.UTC) }, - { "950210152542Z", true, time.Date(1995, time.February, 10, 15, 25, 42, 0, time.UTC) }, - { "1502101525Z", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC) }, - { "150210152542Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC) }, - { "1502101525+1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10 * 3600)) }, - { "1502101525-1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1 * (10 * 3600))) }, - { "1502101525+1035", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10 * 3600 + 35 * 60)) }, - { "1502101525-1035", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1 * (10 * 3600 + 35 * 60))) }, - { "150210152542+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10 * 3600)) }, - { "150210152542-1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1 * (10 * 3600))) }, - { "150210152542+1035", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10 * 3600 + 35 * 60)) }, - { "150210152542-1035", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1 * (10 * 3600 + 35 * 60))) }, - { "1502101525", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC) }, - { "150210152542", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC) }, - { "", false, time.Time{} }, - { "123", false, time.Time{} }, - { "150210152542-10", false, time.Time{} }, - { "150210152542F", false, time.Time{} }, - { "150210152542ZF", false, time.Time{} }, + {"9502101525Z", true, time.Date(1995, time.February, 10, 15, 25, 0, 0, time.UTC)}, + {"950210152542Z", true, time.Date(1995, time.February, 10, 15, 25, 42, 0, time.UTC)}, + {"1502101525Z", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC)}, + {"150210152542Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC)}, + {"1502101525+1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10*3600))}, + {"1502101525-1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1*(10*3600)))}, + {"1502101525+1035", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10*3600+35*60))}, + {"1502101525-1035", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1*(10*3600+35*60)))}, + {"150210152542+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10*3600))}, + {"150210152542-1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1*(10*3600)))}, + {"150210152542+1035", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10*3600+35*60))}, + {"150210152542-1035", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1*(10*3600+35*60)))}, + {"1502101525", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC)}, + {"150210152542", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC)}, + {"", false, time.Time{}}, + {"123", false, time.Time{}}, + {"150210152542-10", false, time.Time{}}, + {"150210152542F", false, time.Time{}}, + {"150210152542ZF", false, time.Time{}}, } func TestUTCTime(t *testing.T) { @@ -62,44 +62,43 @@ func TestUTCTime(t *testing.T) { } var generalizedTimeTests = []timeTest{ - { "2015021015", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.UTC) }, - { "201502101525", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC) }, - { "20150210152542", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC) }, - { "20150210152542.123", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.UTC) }, - { "20150210152542.12", false, time.Time{} }, - { "20150210152542.1", false, time.Time{} }, - { "20150210152542.", false, time.Time{} }, + {"2015021015", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.UTC)}, + {"201502101525", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC)}, + {"20150210152542", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC)}, + {"20150210152542.123", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.UTC)}, + {"20150210152542.12", false, time.Time{}}, + {"20150210152542.1", false, time.Time{}}, + {"20150210152542.", false, time.Time{}}, - { "2015021015Z", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.UTC) }, - { "201502101525Z", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC) }, - { "20150210152542Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC) }, - { "20150210152542.123Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.UTC) }, - { "20150210152542.12Z", false, time.Time{} }, - { "20150210152542.1Z", false, time.Time{} }, - { "20150210152542.Z", false, time.Time{} }, + {"2015021015Z", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.UTC)}, + {"201502101525Z", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.UTC)}, + {"20150210152542Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.UTC)}, + {"20150210152542.123Z", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.UTC)}, + {"20150210152542.12Z", false, time.Time{}}, + {"20150210152542.1Z", false, time.Time{}}, + {"20150210152542.Z", false, time.Time{}}, - { "2015021015+1000", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.FixedZone("", 10 * 3600)) }, - { "201502101525+1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10 * 3600)) }, - { "20150210152542+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10 * 3600)) }, - { "20150210152542.123+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.FixedZone("", 10 * 3600)) }, - { "20150210152542.12+1000", false, time.Time{} }, - { "20150210152542.1+1000", false, time.Time{} }, - { "20150210152542.+1000", false, time.Time{} }, + {"2015021015+1000", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.FixedZone("", 10*3600))}, + {"201502101525+1000", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", 10*3600))}, + {"20150210152542+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", 10*3600))}, + {"20150210152542.123+1000", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.FixedZone("", 10*3600))}, + {"20150210152542.12+1000", false, time.Time{}}, + {"20150210152542.1+1000", false, time.Time{}}, + {"20150210152542.+1000", false, time.Time{}}, - { "2015021015-0835", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.FixedZone("", -1 * (8 * 3600 + 35 * 60))) }, - { "201502101525-0835", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1 * (8 * 3600 + 35 * 60))) }, - { "20150210152542-0835", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1 * (8 * 3600 + 35 * 60))) }, - { "20150210152542.123-0835", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.FixedZone("", -1 * (8 * 3600 + 35 * 60))) }, - { "20150210152542.12-0835", false, time.Time{} }, - { "20150210152542.1-0835", false, time.Time{} }, - { "20150210152542.-0835", false, time.Time{} }, + {"2015021015-0835", true, time.Date(2015, time.February, 10, 15, 0, 0, 0, time.FixedZone("", -1*(8*3600+35*60)))}, + {"201502101525-0835", true, time.Date(2015, time.February, 10, 15, 25, 0, 0, time.FixedZone("", -1*(8*3600+35*60)))}, + {"20150210152542-0835", true, time.Date(2015, time.February, 10, 15, 25, 42, 0, time.FixedZone("", -1*(8*3600+35*60)))}, + {"20150210152542.123-0835", true, time.Date(2015, time.February, 10, 15, 25, 42, 123000000, time.FixedZone("", -1*(8*3600+35*60)))}, + {"20150210152542.12-0835", false, time.Time{}}, + {"20150210152542.1-0835", false, time.Time{}}, + {"20150210152542.-0835", false, time.Time{}}, - - { "", false, time.Time{} }, - { "123", false, time.Time{} }, - { "2015021015+1000Z", false, time.Time{} }, - { "2015021015x", false, time.Time{} }, - { "201502101525Zf", false, time.Time{} }, + {"", false, time.Time{}}, + {"123", false, time.Time{}}, + {"2015021015+1000Z", false, time.Time{}}, + {"2015021015x", false, time.Time{}}, + {"201502101525Zf", false, time.Time{}}, } func TestGeneralizedTime(t *testing.T) { diff --git a/auditing.go b/auditing.go index 781834c..6ef1527 100644 --- a/auditing.go +++ b/auditing.go @@ -10,19 +10,19 @@ package certspotter import ( - "software.sslmate.com/src/certspotter/ct" "bytes" "crypto/sha256" + "software.sslmate.com/src/certspotter/ct" ) -func reverseHashes (hashes []ct.MerkleTreeNode) { - for i := 0; i < len(hashes) / 2; i++ { +func reverseHashes(hashes []ct.MerkleTreeNode) { + for i := 0; i < len(hashes)/2; i++ { j := len(hashes) - i - 1 hashes[i], hashes[j] = hashes[j], hashes[i] } } -func VerifyConsistencyProof (proof ct.ConsistencyProof, first *ct.SignedTreeHead, second *ct.SignedTreeHead) (bool, *MerkleTreeBuilder) { +func VerifyConsistencyProof(proof ct.ConsistencyProof, first *ct.SignedTreeHead, second *ct.SignedTreeHead) (bool, *MerkleTreeBuilder) { if second.TreeSize < first.TreeSize { // Can't be consistent if tree got smaller return false, nil @@ -46,7 +46,7 @@ func VerifyConsistencyProof (proof ct.ConsistencyProof, first *ct.SignedTreeHead lastNode := second.TreeSize - 1 // While we're the right child, everything is in both trees, so move one level up. - for node % 2 == 1 { + for node%2 == 1 { node /= 2 lastNode /= 2 } @@ -68,7 +68,7 @@ func VerifyConsistencyProof (proof ct.ConsistencyProof, first *ct.SignedTreeHead leftHashes = append(leftHashes, newHash) for node > 0 { - if node % 2 == 1 { + if node%2 == 1 { // node is a right child; left sibling exists in both trees if len(proof) == 0 { return false, nil @@ -112,14 +112,14 @@ func VerifyConsistencyProof (proof ct.ConsistencyProof, first *ct.SignedTreeHead return true, &MerkleTreeBuilder{stack: leftHashes, size: first.TreeSize} } -func hashLeaf (leafBytes []byte) ct.MerkleTreeNode { +func hashLeaf(leafBytes []byte) ct.MerkleTreeNode { hasher := sha256.New() hasher.Write([]byte{0x00}) hasher.Write(leafBytes) return hasher.Sum(nil) } -func hashChildren (left ct.MerkleTreeNode, right ct.MerkleTreeNode) ct.MerkleTreeNode { +func hashChildren(left ct.MerkleTreeNode, right ct.MerkleTreeNode) ct.MerkleTreeNode { hasher := sha256.New() hasher.Write([]byte{0x01}) hasher.Write(left) @@ -128,15 +128,15 @@ func hashChildren (left ct.MerkleTreeNode, right ct.MerkleTreeNode) ct.MerkleTre } type MerkleTreeBuilder struct { - stack []ct.MerkleTreeNode - size uint64 // number of hashes added so far + stack []ct.MerkleTreeNode + size uint64 // number of hashes added so far } -func (builder *MerkleTreeBuilder) Add (hash ct.MerkleTreeNode) { +func (builder *MerkleTreeBuilder) Add(hash ct.MerkleTreeNode) { builder.stack = append(builder.stack, hash) builder.size++ size := builder.size - for size % 2 == 0 { + for size%2 == 0 { left, right := builder.stack[len(builder.stack)-2], builder.stack[len(builder.stack)-1] builder.stack = builder.stack[:len(builder.stack)-2] builder.stack = append(builder.stack, hashChildren(left, right)) @@ -144,7 +144,7 @@ func (builder *MerkleTreeBuilder) Add (hash ct.MerkleTreeNode) { } } -func (builder *MerkleTreeBuilder) Finish () ct.MerkleTreeNode { +func (builder *MerkleTreeBuilder) Finish() ct.MerkleTreeNode { if len(builder.stack) == 0 { panic("MerkleTreeBuilder.Finish called on an empty tree") } diff --git a/cmd/certspotter/main.go b/cmd/certspotter/main.go index 34ba4eb..49492db 100644 --- a/cmd/certspotter/main.go +++ b/cmd/certspotter/main.go @@ -10,29 +10,29 @@ package main import ( + "bufio" "flag" "fmt" - "os" "io" - "bufio" - "strings" + "os" "path/filepath" + "strings" "golang.org/x/net/idna" "software.sslmate.com/src/certspotter" - "software.sslmate.com/src/certspotter/ct" "software.sslmate.com/src/certspotter/cmd" + "software.sslmate.com/src/certspotter/ct" ) -func defaultStateDir () string { +func defaultStateDir() string { if envVar := os.Getenv("CERTSPOTTER_STATE_DIR"); envVar != "" { return envVar } else { return cmd.DefaultStateDir("certspotter") } } -func defaultConfigDir () string { +func defaultConfigDir() string { if envVar := os.Getenv("CERTSPOTTER_CONFIG_DIR"); envVar != "" { return envVar } else { @@ -40,9 +40,9 @@ func defaultConfigDir () string { } } -func trimTrailingDots (value string) string { +func trimTrailingDots(value string) string { length := len(value) - for length > 0 && value[length - 1] == '.' { + for length > 0 && value[length-1] == '.' { length-- } return value[0:length] @@ -52,15 +52,16 @@ var stateDir = flag.String("state_dir", defaultStateDir(), "Directory for storin var watchlistFilename = flag.String("watchlist", filepath.Join(defaultConfigDir(), "watchlist"), "File containing identifiers to watch (- for stdin)") type watchlistItem struct { - Domain []string - AcceptSuffix bool + Domain []string + AcceptSuffix bool } + var watchlist []watchlistItem -func parseWatchlistItem (str string) (watchlistItem, error) { +func parseWatchlistItem(str string) (watchlistItem, error) { if str == "." { // "." as in root zone (matches everything) return watchlistItem{ - Domain: []string{}, + Domain: []string{}, AcceptSuffix: true, }, nil } else { @@ -74,13 +75,13 @@ func parseWatchlistItem (str string) (watchlistItem, error) { return watchlistItem{}, fmt.Errorf("Invalid domain `%s': %s", str, err) } return watchlistItem{ - Domain: strings.Split(asciiDomain, "."), + Domain: strings.Split(asciiDomain, "."), AcceptSuffix: acceptSuffix, }, nil } } -func readWatchlist (reader io.Reader) ([]watchlistItem, error) { +func readWatchlist(reader io.Reader) ([]watchlistItem, error) { items := []watchlistItem{} scanner := bufio.NewScanner(reader) for scanner.Scan() { @@ -97,18 +98,18 @@ func readWatchlist (reader io.Reader) ([]watchlistItem, error) { return items, scanner.Err() } -func dnsLabelMatches (certLabel string, watchLabel string) bool { +func dnsLabelMatches(certLabel string, watchLabel string) bool { // For fail-safe behavior, if a label was unparsable, it matches everything. // Similarly, redacted labels match everything, since the label _might_ be // for a name we're interested in. return certLabel == "*" || - certLabel == "?" || - certLabel == certspotter.UnparsableDNSLabelPlaceholder || - certspotter.MatchesWildcard(watchLabel, certLabel) + certLabel == "?" || + certLabel == certspotter.UnparsableDNSLabelPlaceholder || + certspotter.MatchesWildcard(watchLabel, certLabel) } -func dnsNameMatches (dnsName []string, watchDomain []string, acceptSuffix bool) bool { +func dnsNameMatches(dnsName []string, watchDomain []string, acceptSuffix bool) bool { for len(dnsName) > 0 && len(watchDomain) > 0 { certLabel := dnsName[len(dnsName)-1] watchLabel := watchDomain[len(watchDomain)-1] @@ -124,7 +125,7 @@ func dnsNameMatches (dnsName []string, watchDomain []string, acceptSuffix bool) return len(watchDomain) == 0 && (acceptSuffix || len(dnsName) == 0) } -func dnsNameIsWatched (dnsName string) bool { +func dnsNameIsWatched(dnsName string) bool { labels := strings.Split(dnsName, ".") for _, item := range watchlist { if dnsNameMatches(labels, item.Domain, item.AcceptSuffix) { @@ -134,7 +135,7 @@ func dnsNameIsWatched (dnsName string) bool { return false } -func anyDnsNameIsWatched (dnsNames []string) bool { +func anyDnsNameIsWatched(dnsNames []string) bool { for _, dnsName := range dnsNames { if dnsNameIsWatched(dnsName) { return true @@ -143,12 +144,12 @@ func anyDnsNameIsWatched (dnsNames []string) bool { return false } -func processEntry (scanner *certspotter.Scanner, entry *ct.LogEntry) { +func processEntry(scanner *certspotter.Scanner, entry *ct.LogEntry) { info := certspotter.EntryInfo{ - LogUri: scanner.LogUri, - Entry: entry, - IsPrecert: certspotter.IsPrecert(entry), - FullChain: certspotter.GetFullChain(entry), + LogUri: scanner.LogUri, + Entry: entry, + IsPrecert: certspotter.IsPrecert(entry), + FullChain: certspotter.GetFullChain(entry), } info.CertInfo, info.ParseError = certspotter.MakeCertInfoFromLogEntry(entry) diff --git a/cmd/common.go b/cmd/common.go index fd42e49..f434ec5 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -10,18 +10,18 @@ package cmd import ( + "bytes" + "encoding/json" "flag" "fmt" "log" "os" - "bytes" "os/user" - "encoding/json" - "sync" - "strings" "path/filepath" - "time" "strconv" + "strings" + "sync" + "time" "software.sslmate.com/src/certspotter" "software.sslmate.com/src/certspotter/ct" @@ -39,7 +39,7 @@ var stateDir string var printMutex sync.Mutex -func homedir () string { +func homedir() string { home := os.Getenv("HOME") if home != "" { return home @@ -51,15 +51,15 @@ func homedir () string { panic("Unable to determine home directory") } -func DefaultStateDir (programName string) string { - return filepath.Join(homedir(), "." + programName) +func DefaultStateDir(programName string) string { + return filepath.Join(homedir(), "."+programName) } -func DefaultConfigDir (programName string) string { - return filepath.Join(homedir(), "." + programName) +func DefaultConfigDir(programName string) string { + return filepath.Join(homedir(), "."+programName) } -func LogEntry (info *certspotter.EntryInfo) { +func LogEntry(info *certspotter.EntryInfo) { if !*noSave { var alreadyPresent bool var err error @@ -84,24 +84,24 @@ func LogEntry (info *certspotter.EntryInfo) { } } -func defangLogUri (logUri string) string { +func defangLogUri(logUri string) string { return strings.Replace(strings.Replace(logUri, "://", "_", 1), "/", "_", -1) } -func saveEvidence (logUri string, firstSTH *ct.SignedTreeHead, secondSTH *ct.SignedTreeHead, proof ct.ConsistencyProof) (string, string, string, error) { +func saveEvidence(logUri string, firstSTH *ct.SignedTreeHead, secondSTH *ct.SignedTreeHead, proof ct.ConsistencyProof) (string, string, string, error) { now := strconv.FormatInt(time.Now().Unix(), 10) - firstFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".first") + firstFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri)+".inconsistent."+now+".first") if err := certspotter.WriteSTHFile(firstFilename, firstSTH); err != nil { return "", "", "", err } - secondFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".second") + secondFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri)+".inconsistent."+now+".second") if err := certspotter.WriteSTHFile(secondFilename, secondSTH); err != nil { return "", "", "", err } - proofFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri) + ".inconsistent." + now + ".proof") + proofFilename := filepath.Join(stateDir, "evidence", defangLogUri(logUri)+".inconsistent."+now+".proof") if err := certspotter.WriteProofFile(proofFilename, proof); err != nil { return "", "", "", err } @@ -109,7 +109,7 @@ func saveEvidence (logUri string, firstSTH *ct.SignedTreeHead, secondSTH *ct.Sig return firstFilename, secondFilename, proofFilename, nil } -func Main (argStateDir string, processCallback certspotter.ProcessCallback) int { +func Main(argStateDir string, processCallback certspotter.ProcessCallback) int { stateDir = argStateDir var logs []certspotter.LogInfo @@ -171,9 +171,9 @@ func Main (argStateDir string, processCallback certspotter.ProcessCallback) int } opts := certspotter.ScannerOptions{ - BatchSize: *batchSize, - NumWorkers: *numWorkers, - Quiet: !*verbose, + BatchSize: *batchSize, + NumWorkers: *numWorkers, + Quiet: !*verbose, } scanner := certspotter.NewScanner(logUri, logKey, &opts) @@ -186,7 +186,7 @@ func Main (argStateDir string, processCallback certspotter.ProcessCallback) int if *verbose { if prevSTH != nil { - log.Printf("Existing log; scanning %d new entries since previous scan (previous size %d, previous root hash = %x)", latestSTH.TreeSize - prevSTH.TreeSize, prevSTH.TreeSize, prevSTH.SHA256RootHash) + log.Printf("Existing log; scanning %d new entries since previous scan (previous size %d, previous root hash = %x)", latestSTH.TreeSize-prevSTH.TreeSize, prevSTH.TreeSize, prevSTH.SHA256RootHash) } else if *allTime { log.Printf("new log; scanning all %d entries in the log", latestSTH.TreeSize) } else { diff --git a/cmd/ctparsewatch/main.go b/cmd/ctparsewatch/main.go index 4a971ab..71987bb 100644 --- a/cmd/ctparsewatch/main.go +++ b/cmd/ctparsewatch/main.go @@ -14,11 +14,11 @@ import ( "os" "software.sslmate.com/src/certspotter" - "software.sslmate.com/src/certspotter/ct" "software.sslmate.com/src/certspotter/cmd" + "software.sslmate.com/src/certspotter/ct" ) -func DefaultStateDir () string { +func DefaultStateDir() string { if envVar := os.Getenv("CTPARSEWATCH_STATE_DIR"); envVar != "" { return envVar } else { @@ -28,12 +28,12 @@ func DefaultStateDir () string { var stateDir = flag.String("state_dir", DefaultStateDir(), "Directory for storing state") -func processEntry (scanner *certspotter.Scanner, entry *ct.LogEntry) { +func processEntry(scanner *certspotter.Scanner, entry *ct.LogEntry) { info := certspotter.EntryInfo{ - LogUri: scanner.LogUri, - Entry: entry, - IsPrecert: certspotter.IsPrecert(entry), - FullChain: certspotter.GetFullChain(entry), + LogUri: scanner.LogUri, + Entry: entry, + IsPrecert: certspotter.IsPrecert(entry), + FullChain: certspotter.GetFullChain(entry), } info.CertInfo, info.ParseError = certspotter.MakeCertInfoFromLogEntry(entry) diff --git a/ct/client/logclient.go b/ct/client/logclient.go index aaa09f8..438e907 100644 --- a/ct/client/logclient.go +++ b/ct/client/logclient.go @@ -13,15 +13,15 @@ import ( "net/http" "time" - "software.sslmate.com/src/certspotter/ct" "github.com/mreiferson/go-httpclient" + "software.sslmate.com/src/certspotter/ct" ) // URI paths for CT Log endpoints const ( - GetSTHPath = "/ct/v1/get-sth" - GetEntriesPath = "/ct/v1/get-entries" - GetSTHConsistencyPath = "/ct/v1/get-sth-consistency" + GetSTHPath = "/ct/v1/get-sth" + GetEntriesPath = "/ct/v1/get-entries" + GetSTHConsistencyPath = "/ct/v1/get-sth-consistency" ) // LogClient represents a client for a given CT Log instance @@ -84,7 +84,7 @@ func (c *LogClient) fetchAndParse(uri string, res interface{}) error { if err != nil { return err } -// req.Header.Set("Keep-Alive", "timeout=15, max=100") + // req.Header.Set("Keep-Alive", "timeout=15, max=100") resp, err := c.httpClient.Do(req) var body []byte if resp != nil { @@ -97,7 +97,7 @@ func (c *LogClient) fetchAndParse(uri string, res interface{}) error { if err != nil { return err } - if resp.StatusCode / 100 != 2 { + if resp.StatusCode/100 != 2 { return fmt.Errorf("GET %s: %s (%s)", uri, resp.Status, string(body)) } if err = json.Unmarshal(body, &res); err != nil { diff --git a/ct/types.go b/ct/types.go index 98f1356..561e369 100644 --- a/ct/types.go +++ b/ct/types.go @@ -232,9 +232,9 @@ func (d *DigitallySigned) UnmarshalJSON(b []byte) error { // LogEntry represents the contents of an entry in a CT log, see section 3.1. type LogEntry struct { - Index int64 - Leaf MerkleTreeLeaf - Chain []ASN1Cert + Index int64 + Leaf MerkleTreeLeaf + Chain []ASN1Cert LeafBytes []byte } diff --git a/helpers.go b/helpers.go index 94c07da..5f10d35 100644 --- a/helpers.go +++ b/helpers.go @@ -10,26 +10,26 @@ package certspotter import ( - "fmt" - "time" - "os" - "os/exec" "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "encoding/pem" + "fmt" "io" "io/ioutil" "math/big" + "os" + "os/exec" "path/filepath" "strconv" "strings" - "crypto/sha256" - "encoding/hex" - "encoding/pem" - "encoding/json" + "time" "software.sslmate.com/src/certspotter/ct" ) -func ReadSTHFile (path string) (*ct.SignedTreeHead, error) { +func ReadSTHFile(path string) (*ct.SignedTreeHead, error) { content, err := ioutil.ReadFile(path) if err != nil { if os.IsNotExist(err) { @@ -46,7 +46,7 @@ func ReadSTHFile (path string) (*ct.SignedTreeHead, error) { return &sth, nil } -func WriteSTHFile (path string, sth *ct.SignedTreeHead) error { +func WriteSTHFile(path string, sth *ct.SignedTreeHead) error { sthJson, err := json.MarshalIndent(sth, "", "\t") if err != nil { return err @@ -55,7 +55,7 @@ func WriteSTHFile (path string, sth *ct.SignedTreeHead) error { return ioutil.WriteFile(path, sthJson, 0666) } -func WriteProofFile (path string, proof ct.ConsistencyProof) error { +func WriteProofFile(path string, proof ct.ConsistencyProof) error { proofJson, err := json.MarshalIndent(proof, "", "\t") if err != nil { return err @@ -64,12 +64,12 @@ func WriteProofFile (path string, proof ct.ConsistencyProof) error { return ioutil.WriteFile(path, proofJson, 0666) } -func IsPrecert (entry *ct.LogEntry) bool { +func IsPrecert(entry *ct.LogEntry) bool { return entry.Leaf.TimestampedEntry.EntryType == ct.PrecertLogEntryType } -func GetFullChain (entry *ct.LogEntry) [][]byte { - certs := make([][]byte, 0, len(entry.Chain) + 1) +func GetFullChain(entry *ct.LogEntry) [][]byte { + certs := make([][]byte, 0, len(entry.Chain)+1) if entry.Leaf.TimestampedEntry.EntryType == ct.X509LogEntryType { certs = append(certs, entry.Leaf.TimestampedEntry.X509Entry) @@ -81,7 +81,7 @@ func GetFullChain (entry *ct.LogEntry) [][]byte { return certs } -func formatSerialNumber (serial *big.Int) string { +func formatSerialNumber(serial *big.Int) string { if serial != nil { return fmt.Sprintf("%x", serial) } else { @@ -89,45 +89,45 @@ func formatSerialNumber (serial *big.Int) string { } } -func sha256sum (data []byte) []byte { +func sha256sum(data []byte) []byte { sum := sha256.Sum256(data) return sum[:] } -func sha256hex (data []byte) string { +func sha256hex(data []byte) string { return hex.EncodeToString(sha256sum(data)) } type EntryInfo struct { - LogUri string - Entry *ct.LogEntry - IsPrecert bool - FullChain [][]byte // first entry is logged X509 cert or pre-cert - CertInfo *CertInfo - ParseError error // set iff CertInfo is nil - Identifiers *Identifiers - IdentifiersParseError error - Filename string + LogUri string + Entry *ct.LogEntry + IsPrecert bool + FullChain [][]byte // first entry is logged X509 cert or pre-cert + CertInfo *CertInfo + ParseError error // set iff CertInfo is nil + Identifiers *Identifiers + IdentifiersParseError error + Filename string } type CertInfo struct { - TBS *TBSCertificate + TBS *TBSCertificate - Subject RDNSequence - SubjectParseError error - Issuer RDNSequence - IssuerParseError error - SANs []SubjectAltName - SANsParseError error - SerialNumber *big.Int - SerialNumberParseError error - Validity *CertValidity - ValidityParseError error - IsCA *bool - IsCAParseError error + Subject RDNSequence + SubjectParseError error + Issuer RDNSequence + IssuerParseError error + SANs []SubjectAltName + SANsParseError error + SerialNumber *big.Int + SerialNumberParseError error + Validity *CertValidity + ValidityParseError error + IsCA *bool + IsCAParseError error } -func MakeCertInfoFromTBS (tbs *TBSCertificate) *CertInfo { +func MakeCertInfoFromTBS(tbs *TBSCertificate) *CertInfo { info := &CertInfo{TBS: tbs} info.Subject, info.SubjectParseError = tbs.ParseSubject() @@ -140,7 +140,7 @@ func MakeCertInfoFromTBS (tbs *TBSCertificate) *CertInfo { return info } -func MakeCertInfoFromRawTBS (tbsBytes []byte) (*CertInfo, error) { +func MakeCertInfoFromRawTBS(tbsBytes []byte) (*CertInfo, error) { tbs, err := ParseTBSCertificate(tbsBytes) if err != nil { return nil, err @@ -148,7 +148,7 @@ func MakeCertInfoFromRawTBS (tbsBytes []byte) (*CertInfo, error) { return MakeCertInfoFromTBS(tbs), nil } -func MakeCertInfoFromRawCert (certBytes []byte) (*CertInfo, error) { +func MakeCertInfoFromRawCert(certBytes []byte) (*CertInfo, error) { cert, err := ParseCertificate(certBytes) if err != nil { return nil, err @@ -156,7 +156,7 @@ func MakeCertInfoFromRawCert (certBytes []byte) (*CertInfo, error) { return MakeCertInfoFromRawTBS(cert.GetRawTBSCertificate()) } -func MakeCertInfoFromLogEntry (entry *ct.LogEntry) (*CertInfo, error) { +func MakeCertInfoFromLogEntry(entry *ct.LogEntry) (*CertInfo, error) { switch entry.Leaf.TimestampedEntry.EntryType { case ct.X509LogEntryType: return MakeCertInfoFromRawCert(entry.Leaf.TimestampedEntry.X509Entry) @@ -169,7 +169,7 @@ func MakeCertInfoFromLogEntry (entry *ct.LogEntry) (*CertInfo, error) { } } -func (info *CertInfo) NotBefore () *time.Time { +func (info *CertInfo) NotBefore() *time.Time { if info.ValidityParseError == nil { return &info.Validity.NotBefore } else { @@ -177,7 +177,7 @@ func (info *CertInfo) NotBefore () *time.Time { } } -func (info *CertInfo) NotAfter () *time.Time { +func (info *CertInfo) NotAfter() *time.Time { if info.ValidityParseError == nil { return &info.Validity.NotAfter } else { @@ -185,44 +185,44 @@ func (info *CertInfo) NotAfter () *time.Time { } } -func (info *CertInfo) PubkeyHash () string { +func (info *CertInfo) PubkeyHash() string { return sha256hex(info.TBS.GetRawPublicKey()) } -func (info *CertInfo) PubkeyHashBytes () []byte { +func (info *CertInfo) PubkeyHashBytes() []byte { return sha256sum(info.TBS.GetRawPublicKey()) } -func (info *CertInfo) Environ () []string { +func (info *CertInfo) Environ() []string { env := make([]string, 0, 10) - env = append(env, "PUBKEY_HASH=" + info.PubkeyHash()) + env = append(env, "PUBKEY_HASH="+info.PubkeyHash()) if info.SerialNumberParseError != nil { - env = append(env, "SERIAL_PARSE_ERROR=" + info.SerialNumberParseError.Error()) + env = append(env, "SERIAL_PARSE_ERROR="+info.SerialNumberParseError.Error()) } else { - env = append(env, "SERIAL=" + formatSerialNumber(info.SerialNumber)) + env = append(env, "SERIAL="+formatSerialNumber(info.SerialNumber)) } if info.ValidityParseError != nil { - env = append(env, "VALIDITY_PARSE_ERROR=" + info.ValidityParseError.Error()) + env = append(env, "VALIDITY_PARSE_ERROR="+info.ValidityParseError.Error()) } else { - env = append(env, "NOT_BEFORE=" + info.Validity.NotBefore.String()) - env = append(env, "NOT_BEFORE_UNIXTIME=" + strconv.FormatInt(info.Validity.NotBefore.Unix(), 10)) - env = append(env, "NOT_AFTER=" + info.Validity.NotAfter.String()) - env = append(env, "NOT_AFTER_UNIXTIME=" + strconv.FormatInt(info.Validity.NotAfter.Unix(), 10)) + env = append(env, "NOT_BEFORE="+info.Validity.NotBefore.String()) + env = append(env, "NOT_BEFORE_UNIXTIME="+strconv.FormatInt(info.Validity.NotBefore.Unix(), 10)) + env = append(env, "NOT_AFTER="+info.Validity.NotAfter.String()) + env = append(env, "NOT_AFTER_UNIXTIME="+strconv.FormatInt(info.Validity.NotAfter.Unix(), 10)) } if info.SubjectParseError != nil { - env = append(env, "SUBJECT_PARSE_ERROR=" + info.SubjectParseError.Error()) + env = append(env, "SUBJECT_PARSE_ERROR="+info.SubjectParseError.Error()) } else { - env = append(env, "SUBJECT_DN=" + info.Subject.String()) + env = append(env, "SUBJECT_DN="+info.Subject.String()) } if info.IssuerParseError != nil { - env = append(env, "ISSUER_PARSE_ERROR=" + info.IssuerParseError.Error()) + env = append(env, "ISSUER_PARSE_ERROR="+info.IssuerParseError.Error()) } else { - env = append(env, "ISSUER_DN=" + info.Issuer.String()) + env = append(env, "ISSUER_DN="+info.Issuer.String()) } // TODO: include SANs in environment @@ -230,7 +230,7 @@ func (info *CertInfo) Environ () []string { return env } -func (info *EntryInfo) HasParseErrors () bool { +func (info *EntryInfo) HasParseErrors() bool { return info.ParseError != nil || info.IdentifiersParseError != nil || info.CertInfo.SubjectParseError != nil || @@ -241,7 +241,7 @@ func (info *EntryInfo) HasParseErrors () bool { info.CertInfo.IsCAParseError != nil } -func (info *EntryInfo) Fingerprint () string { +func (info *EntryInfo) Fingerprint() string { if len(info.FullChain) > 0 { return sha256hex(info.FullChain[0]) } else { @@ -249,7 +249,7 @@ func (info *EntryInfo) Fingerprint () string { } } -func (info *EntryInfo) FingerprintBytes () []byte { +func (info *EntryInfo) FingerprintBytes() []byte { if len(info.FullChain) > 0 { return sha256sum(info.FullChain[0]) } else { @@ -257,7 +257,7 @@ func (info *EntryInfo) FingerprintBytes () []byte { } } -func (info *EntryInfo) typeString () string { +func (info *EntryInfo) typeString() string { if info.IsPrecert { return "precert" } else { @@ -265,7 +265,7 @@ func (info *EntryInfo) typeString () string { } } -func (info *EntryInfo) typeFriendlyString () string { +func (info *EntryInfo) typeFriendlyString() string { if info.IsPrecert { return "Pre-certificate" } else { @@ -273,7 +273,7 @@ func (info *EntryInfo) typeFriendlyString () string { } } -func yesnoString (value bool) string { +func yesnoString(value bool) string { if value { return "yes" } else { @@ -281,7 +281,7 @@ func yesnoString (value bool) string { } } -func (info *EntryInfo) Environ () []string { +func (info *EntryInfo) Environ() []string { env := []string{ "FINGERPRINT=" + info.Fingerprint(), "CERT_TYPE=" + info.typeString(), @@ -291,25 +291,25 @@ func (info *EntryInfo) Environ () []string { } if info.Filename != "" { - env = append(env, "CERT_FILENAME=" + info.Filename) + env = append(env, "CERT_FILENAME="+info.Filename) } if info.ParseError != nil { - env = append(env, "PARSE_ERROR=" + info.ParseError.Error()) + env = append(env, "PARSE_ERROR="+info.ParseError.Error()) } else if info.CertInfo != nil { certEnv := info.CertInfo.Environ() env = append(env, certEnv...) } if info.IdentifiersParseError != nil { - env = append(env, "IDENTIFIERS_PARSE_ERROR=" + info.IdentifiersParseError.Error()) + env = append(env, "IDENTIFIERS_PARSE_ERROR="+info.IdentifiersParseError.Error()) } else if info.Identifiers != nil { - env = append(env, "DNS_NAMES=" + info.Identifiers.dnsNamesString(",")) - env = append(env, "IP_ADDRESSES=" + info.Identifiers.ipAddrsString(",")) + env = append(env, "DNS_NAMES="+info.Identifiers.dnsNamesString(",")) + env = append(env, "IP_ADDRESSES="+info.Identifiers.ipAddrsString(",")) } return env } -func writeField (out io.Writer, name string, value interface{}, err error) { +func writeField(out io.Writer, name string, value interface{}, err error) { if err == nil { fmt.Fprintf(out, "\t%13s = %s\n", name, value) } else { @@ -317,7 +317,7 @@ func writeField (out io.Writer, name string, value interface{}, err error) { } } -func (info *EntryInfo) Write (out io.Writer) { +func (info *EntryInfo) Write(out io.Writer) { fingerprint := info.Fingerprint() fmt.Fprintf(out, "%s:\n", fingerprint) if info.IdentifiersParseError != nil { @@ -331,7 +331,7 @@ func (info *EntryInfo) Write (out io.Writer) { } } if info.ParseError != nil { - writeField(out, "Parse Error", "*** " + info.ParseError.Error() + " ***", nil) + writeField(out, "Parse Error", "*** "+info.ParseError.Error()+" ***", nil) } else if info.CertInfo != nil { writeField(out, "Pubkey", info.CertInfo.PubkeyHash(), nil) writeField(out, "Issuer", info.CertInfo.Issuer, info.CertInfo.IssuerParseError) @@ -339,13 +339,13 @@ func (info *EntryInfo) Write (out io.Writer) { writeField(out, "Not After", info.CertInfo.NotAfter(), info.CertInfo.ValidityParseError) } writeField(out, "Log Entry", fmt.Sprintf("%d @ %s (%s)", info.Entry.Index, info.LogUri, info.typeFriendlyString()), nil) - writeField(out, "crt.sh", "https://crt.sh/?sha256=" + fingerprint, nil) + writeField(out, "crt.sh", "https://crt.sh/?sha256="+fingerprint, nil) if info.Filename != "" { writeField(out, "Filename", info.Filename, nil) } } -func (info *EntryInfo) InvokeHookScript (command string) error { +func (info *EntryInfo) InvokeHookScript(command string) error { cmd := exec.Command(command) cmd.Env = os.Environ() infoEnv := info.Environ() @@ -362,7 +362,7 @@ func (info *EntryInfo) InvokeHookScript (command string) error { return nil } -func WriteCertRepository (repoPath string, isPrecert bool, certs [][]byte) (bool, string, error) { +func WriteCertRepository(repoPath string, isPrecert bool, certs [][]byte) (bool, string, error) { if len(certs) == 0 { return false, "", fmt.Errorf("Cannot write an empty certificate chain") } @@ -378,7 +378,7 @@ func WriteCertRepository (repoPath string, isPrecert bool, certs [][]byte) (bool if err := os.Mkdir(prefixPath, 0777); err != nil && !os.IsExist(err) { return false, "", fmt.Errorf("Failed to create prefix directory %s: %s", prefixPath, err) } - path := filepath.Join(prefixPath, fingerprint + filenameSuffix) + path := filepath.Join(prefixPath, fingerprint+filenameSuffix) file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) if err != nil { if os.IsExist(err) { @@ -400,7 +400,7 @@ func WriteCertRepository (repoPath string, isPrecert bool, certs [][]byte) (bool return false, path, nil } -func MatchesWildcard (dnsName string, pattern string) bool { +func MatchesWildcard(dnsName string, pattern string) bool { for len(pattern) > 0 { if pattern[0] == '*' { if len(dnsName) > 0 && dnsName[0] != '.' && MatchesWildcard(dnsName[1:], pattern) { diff --git a/helpers_test.go b/helpers_test.go index 44e2cc5..5b1229c 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -13,7 +13,7 @@ import ( "testing" ) -func doWildcardTest (t *testing.T, dnsName string, wildcard string, expected bool) { +func doWildcardTest(t *testing.T, dnsName string, wildcard string, expected bool) { if MatchesWildcard(dnsName, wildcard) != expected { t.Errorf("MatchesWildcard(%q, %q) != %v", dnsName, wildcard, expected) } diff --git a/identifiers.go b/identifiers.go index dd9a2fd..707aa2a 100644 --- a/identifiers.go +++ b/identifiers.go @@ -11,10 +11,10 @@ package certspotter import ( "bytes" - "strings" - "net" - "unicode/utf8" "golang.org/x/net/idna" + "net" + "strings" + "unicode/utf8" ) const UnparsableDNSLabelPlaceholder = "" @@ -34,24 +34,24 @@ type UnknownIdentifier struct { */ type Identifiers struct { - DNSNames []string // stored as ASCII, with IDNs in Punycode - IPAddrs []net.IP + DNSNames []string // stored as ASCII, with IDNs in Punycode + IPAddrs []net.IP //Unknowns []UnknownIdentifier } -func NewIdentifiers () *Identifiers { +func NewIdentifiers() *Identifiers { return &Identifiers{ - DNSNames: []string{}, - IPAddrs: []net.IP{}, + DNSNames: []string{}, + IPAddrs: []net.IP{}, //Unknowns: []UnknownIdentifier{}, } } -func parseIPAddrString (str string) net.IP { +func parseIPAddrString(str string) net.IP { return net.ParseIP(str) } -func isASCIIString (value []byte) bool { +func isASCIIString(value []byte) bool { for _, b := range value { if b > 127 { return false @@ -59,10 +59,10 @@ func isASCIIString (value []byte) bool { } return true } -func isUTF8String (value []byte) bool { +func isUTF8String(value []byte) bool { return utf8.Valid(value) } -func latin1ToUTF8 (value []byte) string { +func latin1ToUTF8(value []byte) string { runes := make([]rune, len(value)) for i, b := range value { runes[i] = rune(b) @@ -72,10 +72,10 @@ func latin1ToUTF8 (value []byte) string { // Make sure the DNS label doesn't have any weird characters that // could cause trouble during later processing. -func isSaneDNSLabelChar (ch rune) bool { +func isSaneDNSLabelChar(ch rune) bool { return ch == '\t' || (ch >= 32 && ch <= 126) } -func isSaneDNSLabel (label string) bool { +func isSaneDNSLabel(label string) bool { for _, ch := range label { if !isSaneDNSLabelChar(ch) { return false @@ -84,7 +84,7 @@ func isSaneDNSLabel (label string) bool { return true } -func trimHttpPrefixString (value string) string { +func trimHttpPrefixString(value string) string { if strings.HasPrefix(value, "http://") { return value[7:] } else if strings.HasPrefix(value, "https://") { @@ -94,7 +94,7 @@ func trimHttpPrefixString (value string) string { } } -func trimHttpPrefixBytes (value []byte) []byte { +func trimHttpPrefixBytes(value []byte) []byte { if bytes.HasPrefix(value, []byte("http://")) { return value[7:] } else if bytes.HasPrefix(value, []byte("https://")) { @@ -104,9 +104,9 @@ func trimHttpPrefixBytes (value []byte) []byte { } } -func trimTrailingDots (value string) string { +func trimTrailingDots(value string) string { length := len(value) - for length > 0 && value[length - 1] == '.' { + for length > 0 && value[length-1] == '.' { length-- } return value[0:length] @@ -117,7 +117,7 @@ func trimTrailingDots (value string) string { // 2. Trim trailing dots // 3. Convert to lower case // 4. Replace totally nonsensical labels (e.g. having non-printable characters) with a placeholder -func sanitizeDNSName (value string) string { +func sanitizeDNSName(value string) string { value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value))) labels := strings.Split(value, ".") for i, label := range labels { @@ -129,7 +129,7 @@ func sanitizeDNSName (value string) string { } // Like sanitizeDNSName, but labels that are Unicode are converted to Punycode. -func sanitizeUnicodeDNSName (value string) string { +func sanitizeUnicodeDNSName(value string) string { value = strings.ToLower(trimTrailingDots(strings.TrimSpace(value))) labels := strings.Split(value, ".") for i, label := range labels { @@ -142,13 +142,13 @@ func sanitizeUnicodeDNSName (value string) string { return strings.Join(labels, ".") } -func (ids *Identifiers) appendDNSName (dnsName string) { +func (ids *Identifiers) appendDNSName(dnsName string) { if dnsName != "" { ids.DNSNames = append(ids.DNSNames, dnsName) } } -func (ids *Identifiers) addDnsSANfinal (value []byte) { +func (ids *Identifiers) addDnsSANfinal(value []byte) { if ipaddr := parseIPAddrString(string(value)); ipaddr != nil { // Stupid CAs put IP addresses in DNS SANs because stupid Microsoft // used to not support IP address SANs. Since there's no way for an IP @@ -169,7 +169,7 @@ func (ids *Identifiers) addDnsSANfinal (value []byte) { } } -func (ids *Identifiers) addDnsSANnonull (value []byte) { +func (ids *Identifiers) addDnsSANnonull(value []byte) { if slashIndex := bytes.IndexByte(value, '/'); slashIndex != -1 { // If the value contains a slash, then this might be a URL, // so process the part of the value up to the first slash, @@ -181,7 +181,7 @@ func (ids *Identifiers) addDnsSANnonull (value []byte) { ids.addDnsSANfinal(value) } -func (ids *Identifiers) AddDnsSAN (value []byte) { +func (ids *Identifiers) AddDnsSAN(value []byte) { // Trim http:// and https:// prefixes, which are all too common in the wild, // so http://example.com becomes just example.com. Even though clients // should never successfully validate a DNS name like http://example.com, @@ -198,7 +198,7 @@ func (ids *Identifiers) AddDnsSAN (value []byte) { ids.addDnsSANnonull(value) } -func (ids *Identifiers) addCNfinal (value string) { +func (ids *Identifiers) addCNfinal(value string) { if ipaddr := parseIPAddrString(value); ipaddr != nil { ids.IPAddrs = append(ids.IPAddrs, ipaddr) } else if !strings.ContainsRune(value, ' ') { @@ -207,7 +207,7 @@ func (ids *Identifiers) addCNfinal (value string) { } } -func (ids *Identifiers) addCNnonull (value string) { +func (ids *Identifiers) addCNnonull(value string) { if slashIndex := strings.IndexRune(value, '/'); slashIndex != -1 { // If the value contains a slash, then this might be a URL, // so process the part of the value up to the first slash, @@ -219,7 +219,7 @@ func (ids *Identifiers) addCNnonull (value string) { ids.addCNfinal(value) } -func (ids *Identifiers) AddCN (value string) { +func (ids *Identifiers) AddCN(value string) { // Trim http:// and https:// prefixes, which are all too common in the wild, // so http://example.com becomes just example.com. Even though clients // should never successfully validate a DNS name like http://example.com, @@ -236,15 +236,15 @@ func (ids *Identifiers) AddCN (value string) { ids.addCNnonull(value) } -func (ids *Identifiers) AddIPAddress (value net.IP) { +func (ids *Identifiers) AddIPAddress(value net.IP) { ids.IPAddrs = append(ids.IPAddrs, value) } -func (ids *Identifiers) dnsNamesString (sep string) string { +func (ids *Identifiers) dnsNamesString(sep string) string { return strings.Join(ids.DNSNames, sep) } -func (ids *Identifiers) ipAddrsString (sep string) string { +func (ids *Identifiers) ipAddrsString(sep string) string { str := "" for _, ipAddr := range ids.IPAddrs { if str != "" { @@ -255,7 +255,7 @@ func (ids *Identifiers) ipAddrsString (sep string) string { return str } -func (cert *CertInfo) ParseIdentifiers () (*Identifiers, error) { +func (cert *CertInfo) ParseIdentifiers() (*Identifiers, error) { ids := NewIdentifiers() if cert.SubjectParseError != nil { diff --git a/logs.go b/logs.go index af1a6f0..5dbea43 100644 --- a/logs.go +++ b/logs.go @@ -10,26 +10,26 @@ package certspotter import ( - "encoding/base64" "crypto" "crypto/x509" + "encoding/base64" ) type LogInfoFile struct { - Logs []LogInfo `json:"logs"` + Logs []LogInfo `json:"logs"` } type LogInfo struct { - Description string `json:"description"` - Key []byte `json:"key"` - Url string `json:"url"` - MMD int `json:"maximum_merge_delay"` + Description string `json:"description"` + Key []byte `json:"key"` + Url string `json:"url"` + MMD int `json:"maximum_merge_delay"` } -func (info *LogInfo) FullURI () string { +func (info *LogInfo) FullURI() string { return "https://" + info.Url } -func (info *LogInfo) ParsedPublicKey () (crypto.PublicKey, error) { +func (info *LogInfo) ParsedPublicKey() (crypto.PublicKey, error) { if info.Key != nil { return x509.ParsePKIXPublicKey(info.Key) } else { @@ -92,13 +92,13 @@ var DefaultLogs = []LogInfo{ var UnderwaterLogs = []LogInfo{ { Description: "Google 'Submariner' log", - Key: mustDecodeBase64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOfifIGLUV1Voou9JLfA5LZreRLSUMOCeeic8q3Dw0fpRkGMWV0Gtq20fgHQweQJeLVmEByQj9p81uIW4QkWkTw=="), - Url: "ct.googleapis.com/submariner", - MMD: 86400, + Key: mustDecodeBase64("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOfifIGLUV1Voou9JLfA5LZreRLSUMOCeeic8q3Dw0fpRkGMWV0Gtq20fgHQweQJeLVmEByQj9p81uIW4QkWkTw=="), + Url: "ct.googleapis.com/submariner", + MMD: 86400, }, } -func mustDecodeBase64 (str string) []byte { +func mustDecodeBase64(str string) []byte { bytes, err := base64.StdEncoding.DecodeString(str) if err != nil { panic("MustDecodeBase64: " + err.Error()) diff --git a/precerts.go b/precerts.go index dbc2151..2f2b963 100644 --- a/precerts.go +++ b/precerts.go @@ -10,22 +10,23 @@ package certspotter import ( - "fmt" - "errors" "bytes" "encoding/asn1" + "errors" + "fmt" ) -func bitStringEqual (a, b *asn1.BitString) bool { +func bitStringEqual(a, b *asn1.BitString) bool { return a.BitLength == b.BitLength && bytes.Equal(a.Bytes, b.Bytes) } var ( - oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} - oidExtensionSCT = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} - oidExtensionCTPoison = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} + oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} + oidExtensionSCT = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} + oidExtensionCTPoison = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} ) -func ValidatePrecert (precertBytes []byte, tbsBytes []byte) error { + +func ValidatePrecert(precertBytes []byte, tbsBytes []byte) error { precert, err := ParseCertificate(precertBytes) if err != nil { return errors.New("failed to parse pre-certificate: " + err.Error()) @@ -116,18 +117,18 @@ func ValidatePrecert (precertBytes []byte, tbsBytes []byte) error { return nil } -func ReconstructPrecertTBS (tbs *TBSCertificate) (*TBSCertificate, error) { +func ReconstructPrecertTBS(tbs *TBSCertificate) (*TBSCertificate, error) { precertTBS := TBSCertificate{ - Version: tbs.Version, - SerialNumber: tbs.SerialNumber, - SignatureAlgorithm: tbs.SignatureAlgorithm, - Issuer: tbs.Issuer, - Validity: tbs.Validity, - Subject: tbs.Subject, - PublicKey: tbs.PublicKey, - UniqueId: tbs.UniqueId, - SubjectUniqueId: tbs.SubjectUniqueId, - Extensions: make([]Extension, 0, len(tbs.Extensions)), + Version: tbs.Version, + SerialNumber: tbs.SerialNumber, + SignatureAlgorithm: tbs.SignatureAlgorithm, + Issuer: tbs.Issuer, + Validity: tbs.Validity, + Subject: tbs.Subject, + PublicKey: tbs.PublicKey, + UniqueId: tbs.UniqueId, + SubjectUniqueId: tbs.SubjectUniqueId, + Extensions: make([]Extension, 0, len(tbs.Extensions)), } for _, ext := range tbs.Extensions { diff --git a/scanner.go b/scanner.go index 6b5289d..19edfc7 100644 --- a/scanner.go +++ b/scanner.go @@ -13,14 +13,14 @@ package certspotter import ( -// "container/list" + // "container/list" + "crypto" + "errors" "fmt" "log" "sync" "sync/atomic" "time" - "crypto" - "errors" "software.sslmate.com/src/certspotter/ct" "software.sslmate.com/src/certspotter/ct/client" @@ -29,7 +29,7 @@ import ( type ProcessCallback func(*Scanner, *ct.LogEntry) const ( - FETCH_RETRIES = 10 + FETCH_RETRIES = 10 FETCH_RETRY_WAIT = 1 ) @@ -48,28 +48,28 @@ type ScannerOptions struct { // Creates a new ScannerOptions struct with sensible defaults func DefaultScannerOptions() *ScannerOptions { return &ScannerOptions{ - BatchSize: 1000, - NumWorkers: 1, - Quiet: false, + BatchSize: 1000, + NumWorkers: 1, + Quiet: false, } } // Scanner is a tool to scan all the entries in a CT Log. type Scanner struct { // Base URI of CT log - LogUri string + LogUri string // Public key of the log - publicKey crypto.PublicKey + publicKey crypto.PublicKey // Client used to talk to the CT log instance - logClient *client.LogClient + logClient *client.LogClient // Configuration options for this Scanner instance - opts ScannerOptions + opts ScannerOptions // Stats - certsProcessed int64 + certsProcessed int64 } // fetchRange represents a range of certs to fetch from a CT log @@ -233,7 +233,7 @@ func (s *Scanner) CheckConsistency(first *ct.SignedTreeHead, second *ct.SignedTr } func (s *Scanner) Scan(startIndex int64, endIndex int64, processCert ProcessCallback, treeBuilder *MerkleTreeBuilder) error { - s.Log("Starting scan..."); + s.Log("Starting scan...") s.certsProcessed = 0 startTime := time.Now() diff --git a/x509.go b/x509.go index c7a21e0..f0c6ba6 100644 --- a/x509.go +++ b/x509.go @@ -10,93 +10,93 @@ package certspotter import ( - "fmt" "bytes" - "errors" "encoding/asn1" + "errors" + "fmt" "math/big" - "time" "net" + "time" ) var ( - oidExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17} - oidExtensionBasicConstraints = asn1.ObjectIdentifier{2, 5, 29, 19} - oidCountry = asn1.ObjectIdentifier{2, 5, 4, 6} - oidOrganization = asn1.ObjectIdentifier{2, 5, 4, 10} - oidOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11} - oidCommonName = asn1.ObjectIdentifier{2, 5, 4, 3} - oidSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5} - oidLocality = asn1.ObjectIdentifier{2, 5, 4, 7} - oidProvince = asn1.ObjectIdentifier{2, 5, 4, 8} - oidStreetAddress = asn1.ObjectIdentifier{2, 5, 4, 9} - oidPostalCode = asn1.ObjectIdentifier{2, 5, 4, 17} + oidExtensionSubjectAltName = asn1.ObjectIdentifier{2, 5, 29, 17} + oidExtensionBasicConstraints = asn1.ObjectIdentifier{2, 5, 29, 19} + oidCountry = asn1.ObjectIdentifier{2, 5, 4, 6} + oidOrganization = asn1.ObjectIdentifier{2, 5, 4, 10} + oidOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11} + oidCommonName = asn1.ObjectIdentifier{2, 5, 4, 3} + oidSerialNumber = asn1.ObjectIdentifier{2, 5, 4, 5} + oidLocality = asn1.ObjectIdentifier{2, 5, 4, 7} + oidProvince = asn1.ObjectIdentifier{2, 5, 4, 8} + oidStreetAddress = asn1.ObjectIdentifier{2, 5, 4, 9} + oidPostalCode = asn1.ObjectIdentifier{2, 5, 4, 17} ) type CertValidity struct { - NotBefore time.Time - NotAfter time.Time + NotBefore time.Time + NotAfter time.Time } type basicConstraints struct { - IsCA bool `asn1:"optional"` - MaxPathLen int `asn1:"optional,default:-1"` + IsCA bool `asn1:"optional"` + MaxPathLen int `asn1:"optional,default:-1"` } type Extension struct { - Id asn1.ObjectIdentifier - Critical bool `asn1:"optional"` - Value []byte + Id asn1.ObjectIdentifier + Critical bool `asn1:"optional"` + Value []byte } const ( - sanOtherName = 0 - sanRfc822Name = 1 - sanDNSName = 2 - sanX400Address = 3 - sanDirectoryName = 4 - sanEdiPartyName = 5 - sanURI = 6 - sanIPAddress = 7 - sanRegisteredID = 8 + sanOtherName = 0 + sanRfc822Name = 1 + sanDNSName = 2 + sanX400Address = 3 + sanDirectoryName = 4 + sanEdiPartyName = 5 + sanURI = 6 + sanIPAddress = 7 + sanRegisteredID = 8 ) + type SubjectAltName struct { - Type int - Value []byte + Type int + Value []byte } type RDNSequence []RelativeDistinguishedNameSET type RelativeDistinguishedNameSET []AttributeTypeAndValue type AttributeTypeAndValue struct { - Type asn1.ObjectIdentifier - Value asn1.RawValue + Type asn1.ObjectIdentifier + Value asn1.RawValue } type TBSCertificate struct { - Raw asn1.RawContent + Raw asn1.RawContent - Version int `asn1:"optional,explicit,default:1,tag:0"` - SerialNumber asn1.RawValue - SignatureAlgorithm asn1.RawValue - Issuer asn1.RawValue - Validity asn1.RawValue - Subject asn1.RawValue - PublicKey asn1.RawValue - UniqueId asn1.BitString `asn1:"optional,tag:1"` - SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` - Extensions []Extension `asn1:"optional,explicit,tag:3"` + Version int `asn1:"optional,explicit,default:1,tag:0"` + SerialNumber asn1.RawValue + SignatureAlgorithm asn1.RawValue + Issuer asn1.RawValue + Validity asn1.RawValue + Subject asn1.RawValue + PublicKey asn1.RawValue + UniqueId asn1.BitString `asn1:"optional,tag:1"` + SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` + Extensions []Extension `asn1:"optional,explicit,tag:3"` } type Certificate struct { - Raw asn1.RawContent + Raw asn1.RawContent - TBSCertificate asn1.RawValue - SignatureAlgorithm asn1.RawValue - SignatureValue asn1.RawValue + TBSCertificate asn1.RawValue + SignatureAlgorithm asn1.RawValue + SignatureValue asn1.RawValue } - -func (rdns RDNSequence) ParseCNs () ([]string, error) { +func (rdns RDNSequence) ParseCNs() ([]string, error) { var cns []string for _, rdn := range rdns { @@ -116,22 +116,31 @@ func (rdns RDNSequence) ParseCNs () ([]string, error) { return cns, nil } -func rdnLabel (oid asn1.ObjectIdentifier) string { +func rdnLabel(oid asn1.ObjectIdentifier) string { switch { - case oid.Equal(oidCountry): return "C" - case oid.Equal(oidOrganization): return "O" - case oid.Equal(oidOrganizationalUnit): return "OU" - case oid.Equal(oidCommonName): return "CN" - case oid.Equal(oidSerialNumber): return "serialNumber" - case oid.Equal(oidLocality): return "L" - case oid.Equal(oidProvince): return "ST" - case oid.Equal(oidStreetAddress): return "street" - case oid.Equal(oidPostalCode): return "postalCode" + case oid.Equal(oidCountry): + return "C" + case oid.Equal(oidOrganization): + return "O" + case oid.Equal(oidOrganizationalUnit): + return "OU" + case oid.Equal(oidCommonName): + return "CN" + case oid.Equal(oidSerialNumber): + return "serialNumber" + case oid.Equal(oidLocality): + return "L" + case oid.Equal(oidProvince): + return "ST" + case oid.Equal(oidStreetAddress): + return "street" + case oid.Equal(oidPostalCode): + return "postalCode" } return oid.String() } -func (rdns RDNSequence) String () string { +func (rdns RDNSequence) String() string { var buf bytes.Buffer for _, rdn := range rdns { @@ -156,7 +165,7 @@ func (rdns RDNSequence) String () string { return buf.String() } -func (san SubjectAltName) String () string { +func (san SubjectAltName) String() string { switch san.Type { case sanDNSName: return "DNS:" + string(san.Value) // TODO: escape non-printable characters, '\', and ',' @@ -172,7 +181,7 @@ func (san SubjectAltName) String () string { } } -func ParseTBSCertificate (tbsBytes []byte) (*TBSCertificate, error) { +func ParseTBSCertificate(tbsBytes []byte) (*TBSCertificate, error) { var tbs TBSCertificate if rest, err := asn1.Unmarshal(tbsBytes, &tbs); err != nil { return nil, errors.New("failed to parse TBS: " + err.Error()) @@ -182,10 +191,10 @@ func ParseTBSCertificate (tbsBytes []byte) (*TBSCertificate, error) { return &tbs, nil } -func (tbs *TBSCertificate) ParseValidity () (*CertValidity, error) { +func (tbs *TBSCertificate) ParseValidity() (*CertValidity, error) { var rawValidity struct { - NotBefore asn1.RawValue - NotAfter asn1.RawValue + NotBefore asn1.RawValue + NotAfter asn1.RawValue } if rest, err := asn1.Unmarshal(tbs.Validity.FullBytes, &rawValidity); err != nil { return nil, errors.New("failed to parse validity: " + err.Error()) @@ -205,7 +214,7 @@ func (tbs *TBSCertificate) ParseValidity () (*CertValidity, error) { return &validity, nil } -func (tbs *TBSCertificate) ParseBasicConstraints () (*bool, error) { +func (tbs *TBSCertificate) ParseBasicConstraints() (*bool, error) { isCA := false isNotCA := false @@ -240,7 +249,7 @@ func (tbs *TBSCertificate) ParseBasicConstraints () (*bool, error) { } } -func (tbs *TBSCertificate) ParseSerialNumber () (*big.Int, error) { +func (tbs *TBSCertificate) ParseSerialNumber() (*big.Int, error) { serialNumber := big.NewInt(0) if rest, err := asn1.Unmarshal(tbs.SerialNumber.FullBytes, &serialNumber); err != nil { return nil, errors.New("failed to parse serial number: " + err.Error()) @@ -250,19 +259,19 @@ func (tbs *TBSCertificate) ParseSerialNumber () (*big.Int, error) { return serialNumber, nil } -func (tbs *TBSCertificate) GetRawPublicKey () []byte { +func (tbs *TBSCertificate) GetRawPublicKey() []byte { return tbs.PublicKey.FullBytes } -func (tbs *TBSCertificate) GetRawSubject () []byte { +func (tbs *TBSCertificate) GetRawSubject() []byte { return tbs.Subject.FullBytes } -func (tbs *TBSCertificate) GetRawIssuer () []byte { +func (tbs *TBSCertificate) GetRawIssuer() []byte { return tbs.Issuer.FullBytes } -func (tbs *TBSCertificate) ParseSubject () (RDNSequence, error) { +func (tbs *TBSCertificate) ParseSubject() (RDNSequence, error) { var subject RDNSequence if rest, err := asn1.Unmarshal(tbs.GetRawSubject(), &subject); err != nil { return nil, errors.New("failed to parse certificate subject: " + err.Error()) @@ -272,7 +281,7 @@ func (tbs *TBSCertificate) ParseSubject () (RDNSequence, error) { return subject, nil } -func (tbs *TBSCertificate) ParseIssuer () (RDNSequence, error) { +func (tbs *TBSCertificate) ParseIssuer() (RDNSequence, error) { var issuer RDNSequence if rest, err := asn1.Unmarshal(tbs.GetRawIssuer(), &issuer); err != nil { return nil, errors.New("failed to parse certificate issuer: " + err.Error()) @@ -282,7 +291,7 @@ func (tbs *TBSCertificate) ParseIssuer () (RDNSequence, error) { return issuer, nil } -func (tbs *TBSCertificate) ParseSubjectCommonNames () ([]string, error) { +func (tbs *TBSCertificate) ParseSubjectCommonNames() ([]string, error) { subject, err := tbs.ParseSubject() if err != nil { return nil, err @@ -295,7 +304,7 @@ func (tbs *TBSCertificate) ParseSubjectCommonNames () ([]string, error) { return cns, nil } -func (tbs *TBSCertificate) ParseSubjectAltNames () ([]SubjectAltName, error) { +func (tbs *TBSCertificate) ParseSubjectAltNames() ([]SubjectAltName, error) { sans := []SubjectAltName{} for _, sanExt := range tbs.GetExtension(oidExtensionSubjectAltName) { @@ -309,7 +318,7 @@ func (tbs *TBSCertificate) ParseSubjectAltNames () ([]SubjectAltName, error) { return sans, nil } -func (tbs *TBSCertificate) GetExtension (id asn1.ObjectIdentifier) []Extension { +func (tbs *TBSCertificate) GetExtension(id asn1.ObjectIdentifier) []Extension { var exts []Extension for _, ext := range tbs.Extensions { if ext.Id.Equal(id) { @@ -319,8 +328,7 @@ func (tbs *TBSCertificate) GetExtension (id asn1.ObjectIdentifier) []Extension { return exts } - -func ParseCertificate (certBytes []byte) (*Certificate, error) { +func ParseCertificate(certBytes []byte) (*Certificate, error) { var cert Certificate if rest, err := asn1.Unmarshal(certBytes, &cert); err != nil { return nil, errors.New("failed to parse certificate: " + err.Error()) @@ -330,15 +338,15 @@ func ParseCertificate (certBytes []byte) (*Certificate, error) { return &cert, nil } -func (cert *Certificate) GetRawTBSCertificate () []byte { +func (cert *Certificate) GetRawTBSCertificate() []byte { return cert.TBSCertificate.FullBytes } -func (cert *Certificate) ParseTBSCertificate () (*TBSCertificate, error) { +func (cert *Certificate) ParseTBSCertificate() (*TBSCertificate, error) { return ParseTBSCertificate(cert.GetRawTBSCertificate()) } -func parseSANExtension (sans []SubjectAltName, value []byte) ([]SubjectAltName, error) { +func parseSANExtension(sans []SubjectAltName, value []byte) ([]SubjectAltName, error) { var seq asn1.RawValue if rest, err := asn1.Unmarshal(value, &seq); err != nil { return nil, errors.New("failed to parse subjectAltName extension: " + err.Error()) @@ -366,4 +374,3 @@ func parseSANExtension (sans []SubjectAltName, value []byte) ([]SubjectAltName, return sans, nil } -