From e82d5b4cfdb7e6f0ac16c045c9984a63cad02ddc Mon Sep 17 00:00:00 2001 From: Justin Bastress Date: Mon, 2 Apr 2018 16:09:41 -0400 Subject: [PATCH] add process tests --- lib/output/test/process_test.go | 1061 +++++++++++++++++++++++++++++++ 1 file changed, 1061 insertions(+) create mode 100644 lib/output/test/process_test.go diff --git a/lib/output/test/process_test.go b/lib/output/test/process_test.go new file mode 100644 index 0000000..3e43f41 --- /dev/null +++ b/lib/output/test/process_test.go @@ -0,0 +1,1061 @@ +package test + +import ( + "encoding/json" + "fmt" + "testing" + + "crypto/rsa" + "encoding/asn1" + "encoding/base64" + "encoding/hex" + "math/big" + "sync" + "time" + + "strings" + + "github.com/sirupsen/logrus" + jsonKeys "github.com/zmap/zcrypto/json" + "github.com/zmap/zcrypto/tls" + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zcrypto/x509/pkix" + "github.com/zmap/zgrab2/lib/output" + "github.com/zmap/zgrab2/lib/output/types" +) + +// The tests operate by manually constructing the stripped versions of the output. +type Strippable interface { + Stripped() string +} + +func toMap(v interface{}) map[string]interface{} { + ret, err := json.MarshalIndent(v, "", " ") + if err != nil { + logrus.Fatalf("Error marshaling: %v", err) + } + theMap := new(map[string]interface{}) + err = json.Unmarshal(ret, theMap) + if err != nil { + logrus.Fatalf("Error unmarshaling: %v", err) + } + return *theMap +} + +func mapPath(v interface{}, keys ...string) (interface{}, error) { + for i, key := range keys { + cast, ok := v.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("%s in map is not a map", strings.Join(keys[0:i], ".")) + } + v = cast + next, ok := cast[key] + if !ok { + return nil, fmt.Errorf("map does not contain %s", strings.Join(keys[0:i+1], ".")) + } + v = next + } + return v, nil +} + +func nilOut(v map[string]interface{}, keys ...string) error { + lastIndex := len(keys) - 1 + out, err := mapPath(v, keys[0:lastIndex]...) + if err != nil { + return err + } + cast, ok := out.(map[string]interface{}) + if !ok { + return fmt.Errorf("%s in map is not a map", strings.Join(keys[0:lastIndex], ".")) + } + cast[keys[lastIndex]] = nil + return nil +} + +// Get a marshalled version of the struct suitable for comparison. +// structs' keys are sorted by order in the definition, which can vary between +// the original and "stripped" versions, the marshalled text is unmarshaled into +// a map (whose keys are sorted alphabetically) and then re-marshaled. +func marshal(v interface{}) string { + theMap := toMap(v) + realRet, err := json.MarshalIndent(theMap, "", " ") + if err != nil { + logrus.Fatalf("Error re-marshaling: %v", err) + } + return string(realRet) +} + +// Helper to process then marshal the input using the given processor. +func process(verbose bool, v interface{}) string { + proc := output.NewOutputProcessor() + proc.Verbose = verbose + theCopy, err := proc.Process(v) + if err != nil { + logrus.Fatalf("Error processing: %v", err) + } + return marshal(theCopy) +} + +// Flat value with a wide variety of types, both debug and non-debug. +type Flat struct { + StringValue string `json:"string_value"` + TrueValue bool `json:"true_value"` + FalseValue bool `json:"false_value"` + IntValue int `json:"int_value"` + BytesValue []byte `json:"bytes_value"` + ArrayValue [5]string `json:"array_value"` + InterfaceValue interface{} `json:"interface_value"` + + PtrStringValue *string `json:"ptr_string_value"` + PtrTrueValue *bool `json:"ptr_true_value"` + PtrFalseValue *bool `json:"ptr_false_value"` + PtrIntValue *int `json:"ptr_int_value"` + PtrBytesValue *[]byte `json:"ptr_bytes_value"` + PtrArrayValue *[5]string `json:"ptr_array_value"` + + DebugStringValue string `json:"debug_string_value,omitempty" zgrab:"debug"` + DebugTrueValue bool `json:"debug_true_value,omitempty" zgrab:"debug"` + DebugFalseValue bool `json:"debug_false_value,omitempty" zgrab:"debug"` + DebugIntValue int `json:"debug_int_value,omitempty" zgrab:"debug"` + DebugBytesValue []byte `json:"debug_bytes_value,omitempty" zgrab:"debug"` + DebugArrayValue [5]string `json:"debug_array_value,omitempty" zgrab:"debug"` + DebugInterfaceValue interface{} `json:"debug_interface_value,omitempty" zgrab:"debug"` + + DebugPtrStringValue *string `json:"debug_ptr_string_value,omitempty" zgrab:"debug"` + DebugPtrTrueValue *bool `json:"debug_ptr_true_value,omitempty" zgrab:"debug"` + DebugPtrFalseValue *bool `json:"debug_ptr_false_value,omitempty" zgrab:"debug"` + DebugPtrIntValue *int `json:"debug_ptr_int_value,omitempty" zgrab:"debug"` + DebugPtrBytesValue *[]byte `json:"debug_ptr_bytes_value,omitempty" zgrab:"debug"` + DebugPtrArrayValue *[5]string `json:"debug_ptr_array_value,omitempty" zgrab:"debug"` +} + +type StrippedFlat struct { + *Flat + OmitDebugStringValue string `json:"debug_string_value,omitempty" zgrab:"debug"` + OmitDebugTrueValue bool `json:"debug_true_value,omitempty" zgrab:"debug"` + OmitDebugFalseValue bool `json:"debug_false_value,omitempty" zgrab:"debug"` + OmitDebugIntValue int `json:"debug_int_value,omitempty" zgrab:"debug"` + OmitDebugBytesValue []byte `json:"debug_bytes_value,omitempty" zgrab:"debug"` + OmitDebugArrayValue [5]string `json:"debug_array_value,omitempty" zgrab:"debug"` + OmitDebugInterfaceValue interface{} `json:"debug_interface_value,omitempty" zgrab:"debug"` + + OmitDebugPtrStringValue *string `json:"debug_ptr_string_value,omitempty" zgrab:"debug"` + OmitDebugPtrTrueValue *bool `json:"debug_ptr_true_value,omitempty" zgrab:"debug"` + OmitDebugPtrFalseValue *bool `json:"debug_ptr_false_value,omitempty" zgrab:"debug"` + OmitDebugPtrIntValue *int `json:"debug_ptr_int_value,omitempty" zgrab:"debug"` + OmitDebugPtrBytesValue *[]byte `json:"debug_ptr_bytes_value,omitempty" zgrab:"debug"` + OmitDebugPtrArrayValue *[5]string `json:"debug_ptr_array_value,omitempty" zgrab:"debug"` +} + +func (flat *Flat) GetStripped() *StrippedFlat { + return &StrippedFlat{Flat: flat} +} + +func (flat *Flat) Stripped() string { + return marshal(flat.GetStripped()) +} + +func getStringArray(id string) *[5]string { + ret := [5]string{} + for i := 0; i < 5; i++ { + ret[i] = fmt.Sprintf("%s[%d]", id, i) + } + return &ret +} + +func pString(s string) *string { + return &s +} + +func pInt(i int) *int { + return &i +} + +func pBool(v bool) *bool { + return &v +} + +func getFlat(id string) *Flat { + return &Flat{ + StringValue: id, + TrueValue: true, + FalseValue: false, + IntValue: len(id), + BytesValue: []byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + ArrayValue: *getStringArray(id), + InterfaceValue: &[]byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + + PtrStringValue: pString(id), + PtrTrueValue: pBool(true), + PtrFalseValue: pBool(false), + PtrIntValue: pInt(len(id)), + PtrBytesValue: &[]byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + PtrArrayValue: getStringArray(id), + + DebugStringValue: "debug_" + id, + DebugTrueValue: true, + DebugFalseValue: false, + DebugIntValue: -len(id), + DebugBytesValue: []byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + DebugArrayValue: *getStringArray("debug_" + id), + DebugInterfaceValue: &[]byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + + DebugPtrStringValue: pString("debug_" + id), + DebugPtrTrueValue: pBool(true), + DebugPtrFalseValue: pBool(false), + DebugPtrIntValue: pInt(-len(id)), + DebugPtrBytesValue: &[]byte{0x64, 0x64, 0x40, 0x05, 0x35, 0x8e}, + DebugPtrArrayValue: getStringArray("debug_" + id), + } +} + +// An arbitrarily deep struct with debug and non-debug fields +type Deep struct { + ID string `json:"id,omitempty"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + Child *Deep `json:"child"` + DebugChild *Deep `json:"debug_child,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeep struct { + *Deep + + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + OverrideChild *StrippedDeep `json:"child"` + OmitDebugChild *StrippedDeep `json:"debug_child,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat" zgrab:"debug"` + OmitDebugPtrFlat *StrippedFlat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *Deep) GetStripped() *StrippedDeep { + temp := StrippedDeep{Deep: deep} + if deep.Child != nil { + temp.OverrideChild = deep.Child.GetStripped() + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + // deep.DebugFlat should be "nilled" automatically; if not, tmep.OverrideDebugFlat = StrippedFlat{} + return &temp +} + +func (deep *Deep) Stripped() string { + return marshal(deep.GetStripped()) +} + +// getDeep (and all similar functions) takes an identifier string, which is used +// as a prefix for all children, and a depth, which determines how many levels +// of children the return value will have. +func getDeep(id string, depth int) *Deep { + ret := &Deep{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Child = getDeep(ret.ID+".child", depth-1) + ret.DebugChild = getDeep(ret.ID+".debug_child", depth-1) + } + return ret +} + +// An arbitrarily deep struct, with its children stored as interface{} fields. +type DeepIface struct { + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + Child interface{} `json:"child"` + DebugChild interface{} `json:"debug_child,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepIface struct { + *DeepIface + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + OverrideChild interface{} `json:"child"` + OmitDebugChild interface{} `json:"debug_child,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *StrippedFlat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepIface) GetStripped() *StrippedDeepIface { + temp := StrippedDeepIface{DeepIface: deep} + // child and debugChild are both pointers to DeepIface + if deep.Child != nil { + temp.OverrideChild = deep.Child.(*DeepIface).GetStripped() + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + return &temp +} + +func (deep *DeepIface) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepIface(id string, depth int) *DeepIface { + ret := &DeepIface{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Child = getDeepIface(ret.ID+".child", depth-1) + ret.DebugChild = getDeepIface(ret.ID+".debug_child", depth-1) + } + return ret +} + +// An arbitrarily deep struct, with its children stored in a slice. +type DeepSlice struct { + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + Children []DeepSlice `json:"children"` + DebugChildren []DeepSlice `json:"debug_children,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepSlice struct { + *DeepSlice + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + OverrideChildren []StrippedDeepSlice `json:"children"` + OmitDebugChildren []StrippedDeepSlice `json:"debug_children,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepSlice) GetStripped() *StrippedDeepSlice { + temp := StrippedDeepSlice{DeepSlice: deep} + // child and debugChild are both pointers to DeepIface + if len(deep.Children) > 0 { + temp.OverrideChildren = make([]StrippedDeepSlice, len(deep.Children)) + for i, v := range deep.Children { + temp.OverrideChildren[i] = *v.GetStripped() + } + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + return &temp +} + +func (deep *DeepSlice) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepSlice(id string, depth int) *DeepSlice { + ret := &DeepSlice{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Children = []DeepSlice{*getDeepSlice(ret.ID+".child", depth-1)} + ret.DebugChildren = []DeepSlice{*getDeepSlice(ret.ID+".debug_child", depth-1)} + } + return ret +} + +// An arbitrarily deep struct, with its children stored in an array of pointers. +type DeepArray struct { + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + Children [1]*DeepArray `json:"children"` + DebugChildren [1]*DeepArray `json:"debug_children,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepArray struct { + *DeepArray + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + OverrideChildren [1]*StrippedDeepArray `json:"children"` + OmitDebugChildren [1]*StrippedDeepArray `json:"debug_children,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *StrippedFlat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepArray) GetStripped() *StrippedDeepArray { + temp := StrippedDeepArray{DeepArray: deep} + // child and debugChild are both pointers to DeepIface + if deep.Children[0] != nil { + temp.OverrideChildren[0] = deep.Children[0].GetStripped() + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + return &temp +} + +func (deep *DeepArray) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepArray(id string, depth int) *DeepArray { + ret := &DeepArray{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Children[0] = getDeepArray(ret.ID+".child", depth-1) + ret.DebugChildren[0] = getDeepArray(ret.ID+".child", depth-1) + } + return ret +} + +// An arbitrarily deep struct, with its children stored in a slice of interface{}s. +type DeepIfaceSlice struct { + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + Children []interface{} `json:"children"` + DebugChildren []interface{} `json:"debug_children,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepIfaceSlice struct { + *DeepIfaceSlice + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + OverrideChildren []interface{} `json:"children"` + OmitDebugChildren []interface{} `json:"debug_children,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *StrippedFlat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepIfaceSlice) GetStripped() *StrippedDeepIfaceSlice { + temp := StrippedDeepIfaceSlice{DeepIfaceSlice: deep} + // child and debugChild are both pointers to DeepIface + if len(deep.Children) > 0 { + child0 := deep.Children[0].(DeepIfaceSlice) + child1 := deep.Children[1].(Flat) + temp.OverrideChildren = []interface{}{ + *(&child0).GetStripped(), + *(&child1).GetStripped(), + } + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + return &temp +} + +func (deep *DeepIfaceSlice) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepIfaceSlice(id string, depth int) *DeepIfaceSlice { + ret := &DeepIfaceSlice{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Children = []interface{}{ + *getDeepIfaceSlice(ret.ID+".children[0]", depth-1), + *getFlat(id + ".children[1]"), + } + ret.DebugChildren = []interface{}{ + *getDeepIfaceSlice(ret.ID+".debug_children[0]", depth-1), + *getFlat(ret.ID + ".debug_children[1]"), + } + } + return ret +} + +// An arbitrarily deep struct, with its children stored in an array of interface{}s +type DeepIfaceArray struct { + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + Children [2]interface{} `json:"children"` + DebugChildren [2]interface{} `json:"debug_children,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepIfaceArray struct { + *DeepIfaceArray + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + + OverrideChildren [2]interface{} `json:"children"` + OmitDebugChildren [2]interface{} `json:"debug_children,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *StrippedFlat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepIfaceArray) GetStripped() *StrippedDeepIfaceArray { + temp := StrippedDeepIfaceArray{DeepIfaceArray: deep} + // child and debugChild are both pointers to DeepIface + if deep.Children[0] != nil { + temp.OverrideChildren[0] = deep.Children[0].(*DeepIfaceArray).GetStripped() + } + if deep.Children[1] != nil { + temp.OverrideChildren[1] = deep.Children[1].(*Flat).GetStripped() + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + return &temp +} + +func (deep *DeepIfaceArray) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepIfaceArray(id string, depth int) *DeepIfaceArray { + ret := &DeepIfaceArray{ + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + PtrFlat: getFlat(id + ".ptr_flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + DebugPtrFlat: getFlat(id + ".debug_ptr_flat"), + } + if depth > 0 { + ret.Children[0] = getDeepIfaceArray(ret.ID+".children[0]", depth-1) + ret.Children[1] = getFlat(ret.ID + ".children[1]") + ret.DebugChildren[0] = getDeepIfaceArray(ret.ID+".debug_children[0]", depth-1) + ret.DebugChildren[1] = getFlat(ret.ID + ".debug_children[1]") + } + return ret +} + +// A wrapper around a Deep, with field names prefixed with anon0 so that it can +// be used as an anonymous member struct. +type DeepAnon0 struct { + Anon0ID string `json:"anon0_id,omitempty"` + DebugAnon0ID string `json:"debug_anon0_id,omitempty" zgrab:"debug"` + + Anon0 Deep `json:"anon0,omitempty"` + DebugAnon0 Deep `json:"debug_anon0,omitempty" zgrab:"debug"` + + Anon0Flat Flat `json:"anon0_flat,omitempty"` + PtrAnon0Flat *Flat `json:"ptr_anon0_flat,omitempty"` + + DebugAnon0Flat Flat `json:"debug_anon0_flat,omitempty" zgrab:"debug"` + DebugPtrAnon0Flat *Flat `json:"debug_ptr_anon0_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepAnon0 struct { + *DeepAnon0 + OmitDebugAnon0ID string `json:"debug_anon0_id,omitempty" zgrab:"debug"` + + OverrideAnon0 StrippedDeep `json:"anon0,omitempty"` + OverrideDebugAnon0 Deep `json:"debug_anon0,omitempty" zgrab:"debug"` + + OverrideAnon0Flat StrippedFlat `json:"anon0_flat,omitempty"` + OverridePtrAnon0Flat *StrippedFlat `json:"ptr_anon0_flat,omitempty"` + + OverrideDebugAnon0Flat Flat `json:"debug_anon0_flat" zgrab:"debug"` + OmitDebugPtrAnon0Flat *Flat `json:"debug_ptr_anon0_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepAnon0) GetStripped() *StrippedDeepAnon0 { + temp := StrippedDeepAnon0{DeepAnon0: deep} + // child and debugChild are both pointers to DeepIface + temp.OverrideAnon0 = *deep.Anon0.GetStripped() + temp.OverrideDebugAnon0 = Deep{} + temp.OverrideAnon0Flat = *deep.Anon0Flat.GetStripped() + temp.OverridePtrAnon0Flat = deep.PtrAnon0Flat.GetStripped() + + temp.OverrideDebugAnon0Flat = Flat{} + return &temp +} + +func (deep *DeepAnon0) Stripped() string { + return marshal(deep.GetStripped()) +} + +// A wrapper around a Deep, with field names prefixed with anon1 so that it can +// be used as an anonymous member struct. +type DeepAnon1 struct { + Anon1ID string `json:"anon1_id"` + DebugAnon1ID string `json:"debug_anon1_id,omitempty" zgrab:"debug"` + + Anon1 Deep `json:"anon1"` + DebugAnon1 Deep `json:"debug_anon1,omitempty" zgrab:"debug"` + + Anon1Flat Flat `json:"anon1_flat,omitempty"` + PtrAnon1Flat *Flat `json:"ptr_anon1_flat,omitempty"` + + DebugAnon1Flat Flat `json:"debug_anon1_flat,omitempty" zgrab:"debug"` + DebugPtrAnon1Flat *Flat `json:"debug_ptr_anon1_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepAnon1 struct { + *DeepAnon1 + OmitDebugAnon1ID string `json:"debug_anon1_id,omitempty" zgrab:"debug"` + + OverrideAnon1 StrippedDeep `json:"anon1,omitempty"` + OverrideDebugAnon1 Deep `json:"debug_anon1,omitempty" zgrab:"debug"` + + OverrideAnon1Flat StrippedFlat `json:"anon1_flat,omitempty"` + OverridePtrAnon1Flat *StrippedFlat `json:"ptr_anon1_flat,omitempty"` + + OverrideDebugAnon1Flat Flat `json:"debug_anon1_flat" zgrab:"debug"` + OmitDebugPtrAnon1Flat *Flat `json:"debug_ptr_anon1_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepAnon1) GetStripped() *StrippedDeepAnon1 { + temp := StrippedDeepAnon1{DeepAnon1: deep} + // child and debugChild are both pointers to DeepIface + temp.OverrideAnon1 = *deep.Anon1.GetStripped() + temp.OverrideDebugAnon1 = Deep{} + temp.OverrideAnon1Flat = *deep.Anon1Flat.GetStripped() + temp.OverridePtrAnon1Flat = deep.PtrAnon1Flat.GetStripped() + + temp.OverrideDebugAnon1Flat = Flat{} + return &temp +} + +func (deep *DeepAnon1) Stripped() string { + return marshal(deep.GetStripped()) +} + +// An arbitrarily deep struct, with a pair of anonymous member structs (one a pointer). +type DeepAnon struct { + DeepAnon0 + *DeepAnon1 + + ID string `json:"id"` + DebugID string `json:"debug_id,omitempty" zgrab:"debug"` + Child *DeepAnon `json:"child,omitempty"` + DebugChild *DeepAnon `json:"debug_child,omitempty" zgrab:"debug"` + + Flat Flat `json:"flat,omitempty"` + PtrFlat *Flat `json:"ptr_flat,omitempty"` + + DebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + DebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +type StrippedDeepAnon struct { + *DeepAnon + *StrippedDeepAnon0 + *StrippedDeepAnon1 + + OverrideAnon0ID string `json:"anon0_id,omitempty"` + OverrideAnon1ID string `json:"anon1_id,omitempty"` + + OmitDebugID string `json:"debug_id,omitempty" zgrab:"debug"` + OverrideChild *StrippedDeepAnon `json:"child,omitempty"` + OmitDebugChild *StrippedDeepAnon `json:"debug_child,omitempty" zgrab:"debug"` + + OverrideFlat StrippedFlat `json:"flat,omitempty"` + OverridePtrFlat *StrippedFlat `json:"ptr_flat,omitempty"` + + OverrideDebugFlat Flat `json:"debug_flat,omitempty" zgrab:"debug"` + OmitDebugPtrFlat *Flat `json:"debug_ptr_flat,omitempty" zgrab:"debug"` +} + +func (deep *DeepAnon) GetStripped() *StrippedDeepAnon { + temp := StrippedDeepAnon{ + DeepAnon: deep, + StrippedDeepAnon0: deep.DeepAnon0.GetStripped(), + StrippedDeepAnon1: deep.DeepAnon1.GetStripped(), + OverrideAnon0ID: deep.DeepAnon0.Anon0ID, + OverrideAnon1ID: deep.DeepAnon1.Anon1ID, + } + if deep.Child != nil { + temp.OverrideChild = deep.Child.GetStripped() + } + temp.OverrideFlat = *deep.Flat.GetStripped() + if deep.PtrFlat != nil { + temp.OverridePtrFlat = deep.PtrFlat.GetStripped() + } + temp.OverrideDebugFlat = Flat{} + + return &temp +} + +func (deep *DeepAnon) Stripped() string { + return marshal(deep.GetStripped()) +} + +func getDeepAnon(id string, depth int) *DeepAnon { + ret := &DeepAnon{ + DeepAnon0: DeepAnon0{ + Anon0ID: id + ".anon0", + DebugAnon0ID: id + ".debug_anon0", + Anon0: *getDeep(id+".anon0", depth-1), + DebugAnon0: *getDeep(id+".anon0", depth-1), + Anon0Flat: *getFlat(id + ".anon0_flat"), + PtrAnon0Flat: getFlat(id + ".ptr_anon0_flat"), + DebugAnon0Flat: *getFlat(id + ".debug_anon0_flat"), + DebugPtrAnon0Flat: getFlat(id + ".debug_ptr_anon0_flat"), + }, + DeepAnon1: &DeepAnon1{ + Anon1ID: id + ".anon1", + DebugAnon1ID: id + ".debug_anon1", + Anon1: *getDeep(id+".anon1", depth-1), + DebugAnon1: *getDeep(id+".anon1", depth-1), + Anon1Flat: *getFlat(id + ".anon1_flat"), + PtrAnon1Flat: getFlat(id + ".ptr_anon1_flat"), + DebugAnon1Flat: *getFlat(id + ".debug_anon1_flat"), + DebugPtrAnon1Flat: getFlat(id + ".debug_ptr_anon1_flat"), + }, + ID: id, + DebugID: "debug_" + id, + Flat: *getFlat(id + ".flat"), + DebugFlat: *getFlat(id + ".debug_flat"), + } + if depth > 0 { + ret.Child = getDeepAnon(id+".child", depth-1) + ret.DebugChild = getDeepAnon(id+".debug_child", depth-1) + } + return ret +} +func fail(t *testing.T, id string, expected string, actual string) { + t.Logf("%s: mismatch: expected %s, got %s", id, expected, actual) + t.Errorf("%s mismatch", id) +} + +// Test processing all of the different types, in verbose and default mode, in parallel. +func TestProcess(t *testing.T) { + tests := map[string]Strippable{ + "flat": getFlat("flat"), + "deep": getDeep("deep", 1), + "deepAnon": getDeepAnon("deepAnon", 1), + "deepArray": getDeepArray("deepArray", 1), + "deepIface": getDeepIface("deepIface", 1), + "deepIfaceArray": getDeepIfaceArray("deepIfaceArray", 1), + "deepIfaceSlice": getDeepIfaceSlice("deepIfaceSlice", 1), + "deepSlice": getDeepSlice("deepSlice", 1), + } + + doTest := func(verbose bool, id string, input Strippable) { + var testID string + if verbose { + testID = id + "-verbose" + } else { + testID = id + "-default" + } + var expected string + if verbose { + expected = marshal(input) + } else { + expected = input.Stripped() + } + actual := process(verbose, input) + if expected != actual { + fail(t, testID, expected, actual) + } + } + doTests := func(verbose bool) { + var done sync.WaitGroup + done.Add(len(tests)) + for k, v := range tests { + go func(id string, input Strippable) { + defer done.Done() + doTest(verbose, id, input) + }(k, v) + } + done.Wait() + } + doTests(true) + doTests(false) +} + +func _b64(s string) []byte { + raw, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return raw +} + +func _hex(s string) []byte { + if len(s)%2 != 0 { + s = "0" + s + } + raw, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return raw +} + +type fakeMySQLScanResults struct { + // ProtocolVersion is the 8-bit unsigned integer representing the + // server's protocol version sent in the initial HandshakePacket from + // the server. + // This has been 10 for all MySQL versionssince 3.2.2 (from 1998). + ProtocolVersion byte `json:"protocol_version"` + + // ServerVersion is a null-terminated string giving the specific + // server version in the initial HandshakePacket. Often of the format + // x.y.z, but not always. + ServerVersion string `json:"server_version"` + + // ConnectionID is the server's internal identifier for this client's + // connection, sent in the initial HandshakePacket. + ConnectionID uint32 `json:"connection_id" zgrab:"debug"` + + // AuthPluginData is optional plugin-specific data, whose meaning + // depends on the value of AuthPluginName. Returned in the initial + // HandshakePacket. + AuthPluginData []byte `json:"auth_plugin_data" zgrab:"debug"` + + // CharacterSet is the identifier for the character set the server is + // using. Returned in the initial HandshakePacket. + CharacterSet byte `json:"character_set" zgrab:"debug"` + + // StatusFlags is the set of status flags the server returned in the + // initial HandshakePacket. Each true entry in the map corresponds to + // a bit set to 1 in the flags, where the keys correspond to the + // #defines in the MySQL docs. + StatusFlags map[string]bool `json:"status_flags"` + + // CapabilityFlags is the set of capability flags the server returned + // initial HandshakePacket. Each true entry in the map corresponds to + // a bit set to 1 in the flags, where the keys correspond to the + // #defines in the MySQL docs. + CapabilityFlags map[string]bool `json:"capability_flags"` + + // AuthPluginName is the name of the authentication plugin, returned + // in the initial HandshakePacket. + AuthPluginName string `json:"auth_plugin_name,omitempty" zgrab:"debug"` + + // ErrorCode is only set if there is an error returned by the server, + // for example if the scanner is not on the allowed hosts list. + ErrorCode *int `json:"error_code,omitempty"` + + // ErrorMessage is an optional string describing the error. Only set + // if there is an error. + ErrorMessage string `json:"error_message,omitempty"` + + // RawPackets contains the base64 encoding of all packets sent and + // received during the scan. + RawPackets []string `json:"raw_packets,omitempty"` + + // TLSLog contains the usual shared TLS logs. + TLSLog *types.TLSLog `json:"tls,omitempty"` +} + +// TestMySQL builds a bogus MySQL result, and then manually checks that the +// debug fields (and only the debug fields) are omitted. +func TestMySQL(t *testing.T) { + results := fakeMySQLScanResults{} + results.AuthPluginData = []byte("auth plugin data") + results.CapabilityFlags = map[string]bool{ + "CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS": true, + "CLIENT_COMPRESS": true, + "CLIENT_SSL": true, + "CLIENT_SECURE_CONNECTION": true, + "CLIENT_INTERACTIVE": true, + "CLIENT_PLUGIN_AUTH": true, + "CLIENT_PLUGIN_AUTH_LEN_ENC_CLIENT_DATA": true, + "CLIENT_PROTOCOL_41": true, + } + results.ProtocolVersion = 10 + results.RawPackets = []string{ + "dGhpcyBpcyBub3QgYSByZWFsIHBhY2tldA==", + "bm9yIGlzIHRoaXM=", + } + results.ConnectionID = 1234 + results.ServerVersion = "8.0.3-rc-log" + results.StatusFlags = map[string]bool{ + "SERVER_STATUS_AUTOCOMMIT": true, + } + results.TLSLog = new(types.TLSLog) + results.TLSLog.HandshakeLog = &tls.ServerHandshake{ + ClientFinished: &tls.Finished{ + VerifyData: []byte("not real data"), + }, + ClientHello: &tls.ClientHello{ + CipherSuites: []tls.CipherSuite{ + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + }, + CompressionMethods: []tls.CompressionMethod{0x00}, + OcspStapling: true, + Random: []byte("some random data"), + SecureRenegotiation: true, + // leaving out SignatureAndHashes, since these aren't exported (yet?) + SupportedCurves: []tls.CurveID{ + tls.CurveP256, + tls.CurveP384, + tls.CurveP521, + }, + SupportedPoints: []tls.PointFormat{0}, + Version: 0x303, + }, + ClientKeyExchange: &tls.ClientKeyExchange{ + RSAParams: &jsonKeys.RSAClientParams{ + EncryptedPMS: []byte("fake"), + Length: 4, + }, + }, + KeyMaterial: &tls.KeyMaterial{ + MasterSecret: &tls.MasterSecret{ + Value: []byte("fake"), + Length: 4, + }, + PreMasterSecret: &tls.PreMasterSecret{ + Value: []byte("fake"), + Length: 4, + }, + }, + ServerCertificates: &tls.Certificates{ + Certificate: tls.SimpleCertificate{ + Raw: _b64("MIIC9DCCAdwCAQIwDQYJKoZIhvcNAQELBQAwPjE8MDoGA1UEAwwzTXlTUUxfU2VydmVyXzguMC4zLXJjX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4XDTE4MDMyMzE5MDMyOFoXDTI4MDMyMDE5MDMyOFowQjFAMD4GA1UEAww3TXlTUUxfU2VydmVyXzguMC4zLXJjX0F1dG9fR2VuZXJhdGVkX1NlcnZlcl9DZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALspPX60RdH8fgSsBjvXRhJ3egQBQWRoga8iGqAjdYrapvNwsdNqzsIe1v+q0FzIKwTkrrGQ3At1ikBjxOhobJOeNeB84jJp+72lPQM2ngYUx3ua/zwZKQw+vZIIqeGPnLzAc180anZl9AL5olyMR+sWm23+YCqEWK0+o9UW5tj27HOX5dL/xZSX+Y8Hsp/1cMK0AmReUsejNobfJ9jBomfKJRiyrEm4Zp3nCA8SuHByboQcKONHMWHeuvvSH5k/ndNf53yw7B/fYua8DHfZ9JUOIZfiGTPJFy1a7zLpIE0fjKRIVaGgggZA9lJzlnNVKna5KT92q+Vi4qgg5pPVqVUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAiOYzSZapOpbSqJHAwpjQRhF02xu8f2sqeckpvROzDMRaq7lP/b5No51Sc7mqe2FrDB2O80G8qwZiM06INRd4HaoKDvolXD+xpyBZ5daNY09/ucpg8f1gDr83sS++AT+LHeoQ9ZmbpRn/x2ZfwA3L8fAoOJg/9m1Z07JOX/9h2uKgZVZBvIQNdm7QSjM7hqgHAcBQVVgk6p2BVd17RYuM9SXJIaCrCKJlg2EcBDyqSD4bdXm941o3+if7eeaTXkBlPzj7MzmrQnaI1Q11LfUrrrNrYDqv1DgIAwMIQ3BzqsJ4GQipq1z5DqU3I8jz0LtsI6J8hFqQf5zQDTuxP3b+tw=="), + Parsed: &x509.Certificate{ + Raw: _b64("MIIC9DCCAdwCAQIwDQYJKoZIhvcNAQELBQAwPjE8MDoGA1UEAwwzTXlTUUxfU2VydmVyXzguMC4zLXJjX0F1dG9fR2VuZXJhdGVkX0NBX0NlcnRpZmljYXRlMB4XDTE4MDMyMzE5MDMyOFoXDTI4MDMyMDE5MDMyOFowQjFAMD4GA1UEAww3TXlTUUxfU2VydmVyXzguMC4zLXJjX0F1dG9fR2VuZXJhdGVkX1NlcnZlcl9DZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALspPX60RdH8fgSsBjvXRhJ3egQBQWRoga8iGqAjdYrapvNwsdNqzsIe1v+q0FzIKwTkrrGQ3At1ikBjxOhobJOeNeB84jJp+72lPQM2ngYUx3ua/zwZKQw+vZIIqeGPnLzAc180anZl9AL5olyMR+sWm23+YCqEWK0+o9UW5tj27HOX5dL/xZSX+Y8Hsp/1cMK0AmReUsejNobfJ9jBomfKJRiyrEm4Zp3nCA8SuHByboQcKONHMWHeuvvSH5k/ndNf53yw7B/fYua8DHfZ9JUOIZfiGTPJFy1a7zLpIE0fjKRIVaGgggZA9lJzlnNVKna5KT92q+Vi4qgg5pPVqVUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAiOYzSZapOpbSqJHAwpjQRhF02xu8f2sqeckpvROzDMRaq7lP/b5No51Sc7mqe2FrDB2O80G8qwZiM06INRd4HaoKDvolXD+xpyBZ5daNY09/ucpg8f1gDr83sS++AT+LHeoQ9ZmbpRn/x2ZfwA3L8fAoOJg/9m1Z07JOX/9h2uKgZVZBvIQNdm7QSjM7hqgHAcBQVVgk6p2BVd17RYuM9SXJIaCrCKJlg2EcBDyqSD4bdXm941o3+if7eeaTXkBlPzj7MzmrQnaI1Q11LfUrrrNrYDqv1DgIAwMIQ3BzqsJ4GQipq1z5DqU3I8jz0LtsI6J8hFqQf5zQDTuxP3b+tw=="), + RawTBSCertificate: _b64("MIIB3AIBAjANBgkqhkiG9w0BAQsFADA+MTwwOgYDVQQDDDNNeVNRTF9TZXJ2ZXJfOC4wLjMtcmNfQXV0b19HZW5lcmF0ZWRfQ0FfQ2VydGlmaWNhdGUwHhcNMTgwMzIzMTkwMzI4WhcNMjgwMzIwMTkwMzI4WjBCMUAwPgYDVQQDDDdNeVNRTF9TZXJ2ZXJfOC4wLjMtcmNfQXV0b19HZW5lcmF0ZWRfU2VydmVyX0NlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuyk9frRF0fx+BKwGO9dGEnd6BAFBZGiBryIaoCN1itqm83Cx02rOwh7W/6rQXMgrBOSusZDcC3WKQGPE6Ghsk5414HziMmn7vaU9AzaeBhTHe5r/PBkpDD69kgip4Y+cvMBzXzRqdmX0AvmiXIxH6xabbf5gKoRYrT6j1Rbm2Pbsc5fl0v/FlJf5jweyn/VwwrQCZF5Sx6M2ht8n2MGiZ8olGLKsSbhmnecIDxK4cHJuhBwo40cxYd66+9IfmT+d01/nfLDsH99i5rwMd9n0lQ4hl+IZM8kXLVrvMukgTR+MpEhVoaCCBkD2UnOWc1UqdrkpP3ar5WLiqCDmk9WpVQIDAQAB"), + RawSubjectPublicKeyInfo: _b64("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuyk9frRF0fx+BKwGO9dGEnd6BAFBZGiBryIaoCN1itqm83Cx02rOwh7W/6rQXMgrBOSusZDcC3WKQGPE6Ghsk5414HziMmn7vaU9AzaeBhTHe5r/PBkpDD69kgip4Y+cvMBzXzRqdmX0AvmiXIxH6xabbf5gKoRYrT6j1Rbm2Pbsc5fl0v/FlJf5jweyn/VwwrQCZF5Sx6M2ht8n2MGiZ8olGLKsSbhmnecIDxK4cHJuhBwo40cxYd66+9IfmT+d01/nfLDsH99i5rwMd9n0lQ4hl+IZM8kXLVrvMukgTR+MpEhVoaCCBkD2UnOWc1UqdrkpP3ar5WLiqCDmk9WpVQIDAQAB"), + RawSubject: _b64("MEIxQDA+BgNVBAMMN015U1FMX1NlcnZlcl84LjAuMy1yY19BdXRvX0dlbmVyYXRlZF9TZXJ2ZXJfQ2VydGlmaWNhdGU="), + RawIssuer: _b64("MD4xPDA6BgNVBAMMM015U1FMX1NlcnZlcl84LjAuMy1yY19BdXRvX0dlbmVyYXRlZF9DQV9DZXJ0aWZpY2F0ZQ=="), + Signature: _b64("iOYzSZapOpbSqJHAwpjQRhF02xu8f2sqeckpvROzDMRaq7lP/b5No51Sc7mqe2FrDB2O80G8qwZiM06INRd4HaoKDvolXD+xpyBZ5daNY09/ucpg8f1gDr83sS++AT+LHeoQ9ZmbpRn/x2ZfwA3L8fAoOJg/9m1Z07JOX/9h2uKgZVZBvIQNdm7QSjM7hqgHAcBQVVgk6p2BVd17RYuM9SXJIaCrCKJlg2EcBDyqSD4bdXm941o3+if7eeaTXkBlPzj7MzmrQnaI1Q11LfUrrrNrYDqv1DgIAwMIQ3BzqsJ4GQipq1z5DqU3I8jz0LtsI6J8hFqQf5zQDTuxP3b+tw=="), + SignatureAlgorithm: 4, + SignatureAlgorithmOID: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}, + PublicKeyAlgorithm: x509.PublicKeyAlgorithm(1), + PublicKey: &rsa.PublicKey{ + N: (&big.Int{}).SetBytes(_hex("23626899336418032268426511006251456008957710946561236060077488477243930404389062857052756514213142729464147136250009726616710651748049570319952455766122793111751860932493085339042549427591735641622561350827399950711160330519889423606741185340361830307539991923398265174995648216248341512414059342081655136496339884654761519474219238937533274055680590823298754387287727134545334674412201273293183886639463834612608672984702302550038373374767049834134869307465746789634588312053503628028754854224411402349197656713279667931626157560702246437041136455602220365024967237813532823227555845248339489268414093584421359036757")), + E: 65537, + }, + PublicKeyAlgorithmOID: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}, + Version: 2, + SerialNumber: big.NewInt(2), + Issuer: pkix.Name{ + CommonName: "MySQL_Server_8.0.3-rc_Auto_Generated_CA_Certificate", + Names: []pkix.AttributeTypeAndValue{pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, + Value: "MySQL_Server_8.0.3-rc_Auto_Generated_CA_Certificate"}}, + ExtraNames: []pkix.AttributeTypeAndValue(nil), + OriginalRDNS: pkix.RDNSequence{pkix.RelativeDistinguishedNameSET{pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, + Value: "MySQL_Server_8.0.3-rc_Auto_Generated_CA_Certificate"}}}}, + Subject: pkix.Name{ + CommonName: "MySQL_Server_8.0.3-rc_Auto_Generated_Server_Certificate", + Names: []pkix.AttributeTypeAndValue{pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, + Value: "MySQL_Server_8.0.3-rc_Auto_Generated_Server_Certificate"}}, + ExtraNames: []pkix.AttributeTypeAndValue(nil), + OriginalRDNS: pkix.RDNSequence{pkix.RelativeDistinguishedNameSET{pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{2, 5, 4, 3}, + Value: "MySQL_Server_8.0.3-rc_Auto_Generated_Server_Certificate"}}}}, + NotBefore: time.Unix(63657428608/1000, 0), + NotAfter: time.Unix(63972788608/1000, 0), + ValidityPeriod: 315360000, + KeyUsage: 0, + SPKISubjectFingerprint: x509.CertificateFingerprint(_hex("14ffb1395597876cf13957c7de6994f7361efa951ceb49e222897ec964566c98")), + SPKIFingerprint: x509.CertificateFingerprint(_hex("66bedbc8b8f7df04f2dea4eb7d351f4f7f2b88b51eb52b988f8579201f9e5f3c")), + TBSCertificateFingerprint: x509.CertificateFingerprint(_hex("2cfc9ad82b7871734febcc892f61c81c4d8cf051ac071d357c8b9d08a13a2707")), + FingerprintNoCT: x509.CertificateFingerprint(_hex("a678d89928d1b7d398c1bc194bf393aac70239876b3f17da15c0fe5d1cde34f7")), + FingerprintSHA256: x509.CertificateFingerprint(_hex("202dc36b950a33f12237dd6197a60c06ddaba945b8c281d811c7b1a6d45b0640")), + FingerprintSHA1: x509.CertificateFingerprint(_hex("48e5d105675ea12ef95f7ef31eb8af3639ee57b2")), + FingerprintMD5: x509.CertificateFingerprint(_hex("da94c3e3592de3da093c5da51f46d4ce")), + }, + }, + }, + ServerFinished: &tls.Finished{ + VerifyData: []byte("fake"), + }, + ServerHello: &tls.ServerHello{ + CipherSuite: tls.TLS_RSA_WITH_AES_256_CBC_SHA, + CompressionMethod: 0, + Random: []byte("some other random data"), + SessionID: []byte("some session ID"), + Version: 0x302, + }, + } + results.TLSLog.HeartbleedLog = &tls.Heartbleed{} + mapVal := toMap(results) + mapVal["auth_plugin_data"] = nil + mapVal["connection_id"] = 0 + expected := marshal(mapVal) + p := output.NewOutputProcessor() + p.Verbose = false + output, err := p.Process(results) + if err != nil { + panic(err) + } + actual := marshal(output) + if actual != expected { + fail(t, "fake-mysql", expected, actual) + } +}