github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/crypto/x509/root_unix_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build dragonfly freebsd linux netbsd openbsd solaris 7 8 package x509 9 10 import ( 11 "bytes" 12 "fmt" 13 "os" 14 "path/filepath" 15 "reflect" 16 "strings" 17 "testing" 18 ) 19 20 const ( 21 testDir = "testdata" 22 testDirCN = "test-dir" 23 testFile = "test-file.crt" 24 testFileCN = "test-file" 25 testMissing = "missing" 26 ) 27 28 func TestEnvVars(t *testing.T) { 29 testCases := []struct { 30 name string 31 fileEnv string 32 dirEnv string 33 files []string 34 dirs []string 35 cns []string 36 }{ 37 { 38 // Environment variables override the default locations preventing fall through. 39 name: "override-defaults", 40 fileEnv: testMissing, 41 dirEnv: testMissing, 42 files: []string{testFile}, 43 dirs: []string{testDir}, 44 cns: nil, 45 }, 46 { 47 // File environment overrides default file locations. 48 name: "file", 49 fileEnv: testFile, 50 dirEnv: "", 51 files: nil, 52 dirs: nil, 53 cns: []string{testFileCN}, 54 }, 55 { 56 // Directory environment overrides default directory locations. 57 name: "dir", 58 fileEnv: "", 59 dirEnv: testDir, 60 files: nil, 61 dirs: nil, 62 cns: []string{testDirCN}, 63 }, 64 { 65 // File & directory environment overrides both default locations. 66 name: "file+dir", 67 fileEnv: testFile, 68 dirEnv: testDir, 69 files: nil, 70 dirs: nil, 71 cns: []string{testFileCN, testDirCN}, 72 }, 73 { 74 // Environment variable empty / unset uses default locations. 75 name: "empty-fall-through", 76 fileEnv: "", 77 dirEnv: "", 78 files: []string{testFile}, 79 dirs: []string{testDir}, 80 cns: []string{testFileCN, testDirCN}, 81 }, 82 } 83 84 // Save old settings so we can restore before the test ends. 85 origCertFiles, origCertDirectories := certFiles, certDirectories 86 origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv) 87 defer func() { 88 certFiles = origCertFiles 89 certDirectories = origCertDirectories 90 os.Setenv(certFileEnv, origFile) 91 os.Setenv(certDirEnv, origDir) 92 }() 93 94 for _, tc := range testCases { 95 t.Run(tc.name, func(t *testing.T) { 96 if err := os.Setenv(certFileEnv, tc.fileEnv); err != nil { 97 t.Fatalf("setenv %q failed: %v", certFileEnv, err) 98 } 99 if err := os.Setenv(certDirEnv, tc.dirEnv); err != nil { 100 t.Fatalf("setenv %q failed: %v", certDirEnv, err) 101 } 102 103 certFiles, certDirectories = tc.files, tc.dirs 104 105 r, err := loadSystemRoots() 106 if err != nil { 107 t.Fatal("unexpected failure:", err) 108 } 109 110 if r == nil { 111 t.Fatal("nil roots") 112 } 113 114 // Verify that the returned certs match, otherwise report where the mismatch is. 115 for i, cn := range tc.cns { 116 if i >= r.len() { 117 t.Errorf("missing cert %v @ %v", cn, i) 118 } else if r.mustCert(t, i).Subject.CommonName != cn { 119 fmt.Printf("%#v\n", r.mustCert(t, 0).Subject) 120 t.Errorf("unexpected cert common name %q, want %q", r.mustCert(t, i).Subject.CommonName, cn) 121 } 122 } 123 if r.len() > len(tc.cns) { 124 t.Errorf("got %v certs, which is more than %v wanted", r.len(), len(tc.cns)) 125 } 126 }) 127 } 128 } 129 130 // Ensure that "SSL_CERT_DIR" when used as the environment 131 // variable delimited by colons, allows loadSystemRoots to 132 // load all the roots from the respective directories. 133 // See https://golang.org/issue/35325. 134 func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) { 135 origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv) 136 origCertFiles := certFiles[:] 137 138 // To prevent any other certs from being loaded in 139 // through "SSL_CERT_FILE" or from known "certFiles", 140 // clear them all, and they'll be reverting on defer. 141 certFiles = certFiles[:0] 142 os.Setenv(certFileEnv, "") 143 144 defer func() { 145 certFiles = origCertFiles[:] 146 os.Setenv(certDirEnv, origDir) 147 os.Setenv(certFileEnv, origFile) 148 }() 149 150 tmpDir, err := os.MkdirTemp(os.TempDir(), "x509-issue35325") 151 if err != nil { 152 t.Fatalf("Failed to create temporary directory: %v", err) 153 } 154 defer os.RemoveAll(tmpDir) 155 156 rootPEMs := []string{ 157 geoTrustRoot, 158 googleLeaf, 159 startComRoot, 160 } 161 162 var certDirs []string 163 for i, certPEM := range rootPEMs { 164 certDir := filepath.Join(tmpDir, fmt.Sprintf("cert-%d", i)) 165 if err := os.MkdirAll(certDir, 0755); err != nil { 166 t.Fatalf("Failed to create certificate dir: %v", err) 167 } 168 certOutFile := filepath.Join(certDir, "cert.crt") 169 if err := os.WriteFile(certOutFile, []byte(certPEM), 0655); err != nil { 170 t.Fatalf("Failed to write certificate to file: %v", err) 171 } 172 certDirs = append(certDirs, certDir) 173 } 174 175 // Sanity check: the number of certDirs should be equal to the number of roots. 176 if g, w := len(certDirs), len(rootPEMs); g != w { 177 t.Fatalf("Failed sanity check: len(certsDir)=%d is not equal to len(rootsPEMS)=%d", g, w) 178 } 179 180 // Now finally concatenate them with a colon. 181 colonConcatCertDirs := strings.Join(certDirs, ":") 182 os.Setenv(certDirEnv, colonConcatCertDirs) 183 gotPool, err := loadSystemRoots() 184 if err != nil { 185 t.Fatalf("Failed to load system roots: %v", err) 186 } 187 subjects := gotPool.Subjects() 188 // We expect exactly len(rootPEMs) subjects back. 189 if g, w := len(subjects), len(rootPEMs); g != w { 190 t.Fatalf("Invalid number of subjects: got %d want %d", g, w) 191 } 192 193 wantPool := NewCertPool() 194 for _, certPEM := range rootPEMs { 195 wantPool.AppendCertsFromPEM([]byte(certPEM)) 196 } 197 strCertPool := func(p *CertPool) string { 198 return string(bytes.Join(p.Subjects(), []byte("\n"))) 199 } 200 201 if !certPoolEqual(gotPool, wantPool) { 202 g, w := strCertPool(gotPool), strCertPool(wantPool) 203 t.Fatalf("Mismatched certPools\nGot:\n%s\n\nWant:\n%s", g, w) 204 } 205 } 206 207 func TestReadUniqueDirectoryEntries(t *testing.T) { 208 tmp := t.TempDir() 209 temp := func(base string) string { return filepath.Join(tmp, base) } 210 if f, err := os.Create(temp("file")); err != nil { 211 t.Fatal(err) 212 } else { 213 f.Close() 214 } 215 if err := os.Symlink("target-in", temp("link-in")); err != nil { 216 t.Fatal(err) 217 } 218 if err := os.Symlink("../target-out", temp("link-out")); err != nil { 219 t.Fatal(err) 220 } 221 got, err := readUniqueDirectoryEntries(tmp) 222 if err != nil { 223 t.Fatal(err) 224 } 225 gotNames := []string{} 226 for _, fi := range got { 227 gotNames = append(gotNames, fi.Name()) 228 } 229 wantNames := []string{"file", "link-out"} 230 if !reflect.DeepEqual(gotNames, wantNames) { 231 t.Errorf("got %q; want %q", gotNames, wantNames) 232 } 233 }