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  }