github.com/google/osv-scalibr@v0.4.1/detector/weakcredentials/winlocal/systemreg/systemreg_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package systemreg 16 17 import ( 18 "slices" 19 "strings" 20 "testing" 21 22 "github.com/google/osv-scalibr/common/windows/registry" 23 "github.com/google/osv-scalibr/testing/mockregistry" 24 ) 25 26 func TestNewFromFile(t *testing.T) { 27 tests := []struct { 28 name string 29 path string 30 wantErr bool 31 }{ 32 { 33 name: "File is missing registry magic", 34 path: "/dev/null", 35 wantErr: true, 36 }, 37 { 38 name: "Fails when file does not exist", 39 path: "/some/non/existing/file", 40 wantErr: true, 41 }, 42 } 43 44 for _, tc := range tests { 45 t.Run(tc.name, func(t *testing.T) { 46 _, err := NewFromFile(tc.path) 47 if (err != nil) != tc.wantErr { 48 t.Fatalf("NewFromFile(%q) error: got: %v, want: %v", tc.path, err, tc.wantErr) 49 } 50 }) 51 } 52 } 53 54 func TestSyskey(t *testing.T) { 55 tests := []struct { 56 name string 57 registry *mockregistry.MockRegistry 58 want []byte 59 wantErr bool 60 wantErrText string 61 }{ 62 { 63 name: "Parses_syskey_correctly", 64 registry: &mockregistry.MockRegistry{ 65 Keys: map[string]registry.Key{ 66 `Select`: &mockregistry.MockKey{ 67 KValues: []registry.Value{ 68 &mockregistry.MockValue{ 69 VName: "Current", 70 VData: []byte{0x01}, 71 }, 72 }, 73 }, 74 `ControlSet001\Control\Lsa\JD`: &mockregistry.MockKey{ 75 KClassName: "\x32\x00\x35\x00\x33\x00\x35\x00\x39\x00\x33\x00\x64\x00\x64\x00", 76 }, 77 `ControlSet001\Control\Lsa\Skew1`: &mockregistry.MockKey{ 78 KClassName: "\x61\x00\x65\x00\x39\x00\x33\x00\x34\x00\x37\x00\x30\x00\x30\x00", 79 }, 80 `ControlSet001\Control\Lsa\GBG`: &mockregistry.MockKey{ 81 KClassName: "\x38\x00\x38\x00\x31\x00\x33\x00\x39\x00\x64\x00\x34\x00\x35\x00", 82 }, 83 `ControlSet001\Control\Lsa\Data`: &mockregistry.MockKey{ 84 KClassName: "\x31\x00\x36\x00\x62\x00\x64\x00\x33\x00\x65\x00\x33\x00\x33\x00", 85 }, 86 }, 87 }, 88 want: []byte("\x88\x93\xae\x93\x45\x13\xbd\xdd\x25\x47\x35\x16\x3e\x9d\x33\x00"), 89 }, 90 { 91 name: "Parses_syskey_correctly_with_different_control_set", 92 registry: &mockregistry.MockRegistry{ 93 Keys: map[string]registry.Key{ 94 `Select`: &mockregistry.MockKey{ 95 KValues: []registry.Value{ 96 &mockregistry.MockValue{ 97 VName: "Current", 98 VData: []byte{0x02}, 99 }, 100 }, 101 }, 102 `ControlSet002\Control\Lsa\JD`: &mockregistry.MockKey{ 103 KClassName: "\x32\x00\x35\x00\x33\x00\x35\x00\x39\x00\x33\x00\x64\x00\x64\x00", 104 }, 105 `ControlSet002\Control\Lsa\Skew1`: &mockregistry.MockKey{ 106 KClassName: "\x61\x00\x65\x00\x39\x00\x33\x00\x34\x00\x37\x00\x30\x00\x30\x00", 107 }, 108 `ControlSet002\Control\Lsa\GBG`: &mockregistry.MockKey{ 109 KClassName: "\x38\x00\x38\x00\x31\x00\x33\x00\x39\x00\x64\x00\x34\x00\x35\x00", 110 }, 111 `ControlSet002\Control\Lsa\Data`: &mockregistry.MockKey{ 112 KClassName: "\x31\x00\x36\x00\x62\x00\x64\x00\x33\x00\x65\x00\x33\x00\x33\x00", 113 }, 114 }, 115 }, 116 want: []byte("\x88\x93\xae\x93\x45\x13\xbd\xdd\x25\x47\x35\x16\x3e\x9d\x33\x00"), 117 }, 118 { 119 name: "Parts_of_the_syskey_are_missing", 120 registry: &mockregistry.MockRegistry{ 121 Keys: map[string]registry.Key{ 122 `Select`: &mockregistry.MockKey{ 123 KValues: []registry.Value{ 124 &mockregistry.MockValue{ 125 VName: "Current", 126 VData: []byte{0x01}, 127 }, 128 }, 129 }, 130 `ControlSet001\Control\Lsa\JD`: &mockregistry.MockKey{ 131 KClassName: "\x32\x00\x35\x00\x33\x00\x35\x00\x39\x00\x33\x00\x64\x00\x64\x00", 132 }, 133 }, 134 }, 135 wantErr: true, 136 wantErrText: `failed to open key`, 137 }, 138 { 139 name: "The_key_does_not_decode_as_hexadecimal", 140 registry: &mockregistry.MockRegistry{ 141 Keys: map[string]registry.Key{ 142 `Select`: &mockregistry.MockKey{ 143 KValues: []registry.Value{ 144 &mockregistry.MockValue{ 145 VName: "Current", 146 VData: []byte{0x01}, 147 }, 148 }, 149 }, 150 `ControlSet001\Control\Lsa\JD`: &mockregistry.MockKey{ 151 KClassName: "\x32\xFF\x35\xFF\x33\xFF\x35\xFF\x39\xFF\x33\xFF\x64\xFF\x64\xFF", 152 }, 153 `ControlSet001\Control\Lsa\Skew1`: &mockregistry.MockKey{ 154 KClassName: "\x61\x00\x65\x00\x39\x00\x33\x00\x34\x00\x37\x00\x30\x00\x30\x00", 155 }, 156 `ControlSet001\Control\Lsa\GBG`: &mockregistry.MockKey{ 157 KClassName: "\x38\x00\x38\x00\x31\x00\x33\x00\x39\x00\x64\x00\x34\x00\x35\x00", 158 }, 159 `ControlSet001\Control\Lsa\Data`: &mockregistry.MockKey{ 160 KClassName: "\x31\x00\x36\x00\x62\x00\x64\x00\x33\x00\x65\x00\x33\x00\x33\x00", 161 }, 162 }, 163 }, 164 wantErr: true, 165 wantErrText: `encoding/hex: invalid byte: U+00EF 'ï'`, 166 }, 167 { 168 name: "Select_registry_key_not_found", 169 registry: &mockregistry.MockRegistry{ 170 Keys: map[string]registry.Key{}, 171 }, 172 wantErr: true, 173 wantErrText: `failed to open key`, 174 }, 175 { 176 name: "Current_control_set_not_found", 177 registry: &mockregistry.MockRegistry{ 178 Keys: map[string]registry.Key{ 179 `Select`: &mockregistry.MockKey{}, 180 }, 181 }, 182 wantErr: true, 183 wantErrText: errNoCurrentControlSet.Error(), 184 }, 185 } 186 187 for _, tc := range tests { 188 t.Run(tc.name, func(t *testing.T) { 189 sysreg := &SystemRegistry{tc.registry} 190 got, err := sysreg.Syskey() 191 192 if (err != nil) != tc.wantErr { 193 t.Errorf("Syskey() unexpected error: %v", err) 194 } 195 196 if tc.wantErr { 197 if !strings.Contains(err.Error(), tc.wantErrText) { 198 t.Errorf("Syskey() unexpected error: got: %v, want: %v", err.Error(), tc.wantErrText) 199 } 200 201 return 202 } 203 204 if !slices.Equal(got, tc.want) { 205 t.Errorf("Syskey() unexpected result: got: %v, want: %v", got, tc.want) 206 } 207 }) 208 } 209 }