Run gofmt

Signed-off-by: Jonathan Rudenberg <jonathan@titanous.com>
This commit is contained in:
Jonathan Rudenberg 2016-07-28 14:55:46 -04:00
parent 38b9c920eb
commit acc6781f29
16 changed files with 451 additions and 410 deletions

17
asn1.go
View File

@ -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")
}

View File

@ -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)

View File

@ -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) {

View File

@ -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")
}

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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 {

View File

@ -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
}

View File

@ -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) {

View File

@ -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)
}

View File

@ -11,10 +11,10 @@ package certspotter
import (
"bytes"
"strings"
"net"
"unicode/utf8"
"golang.org/x/net/idna"
"net"
"strings"
"unicode/utf8"
)
const UnparsableDNSLabelPlaceholder = "<unparsable>"
@ -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 {

24
logs.go
View File

@ -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())

View File

@ -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 {

View File

@ -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()

173
x509.go
View File

@ -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
}