forked from SUSE/connect-ng
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Workaround system cert reloading after import (bsc#1195220)
This is a workaround for Golang's missing feature of reloading system certs. The built in system certs pool is initialized only once on startup and there is no option for reloading it when new certs are installed. The problem is known upstream and tracked at golang/go#41888. The cert_pool.go is almost 1:1 copy of original library code but exposes needed functionality. It can be removed when upstream fixes the problem.
- Loading branch information
Showing
3 changed files
with
144 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// TODO: remove when https://github.com/golang/go/issues/41888 is fixed | ||
// code copied from standard library crypto/x509/root.go to enable system certs reloading | ||
|
||
package connect | ||
|
||
import ( | ||
"crypto/x509" | ||
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
func systemRootsPool() *x509.CertPool { | ||
systemRoots, systemRootsErr := _loadSystemRoots() | ||
if systemRootsErr != nil { | ||
return nil | ||
} | ||
return systemRoots | ||
} | ||
|
||
const ( | ||
// certFileEnv is the environment variable which identifies where to locate | ||
// the SSL certificate file. If set this overrides the system default. | ||
_certFileEnv = "SSL_CERT_FILE" | ||
|
||
// certDirEnv is the environment variable which identifies which directory | ||
// to check for SSL certificate files. If set this overrides the system default. | ||
// It is a colon separated list of directories. | ||
// See https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html. | ||
_certDirEnv = "SSL_CERT_DIR" | ||
) | ||
|
||
// Possible certificate files; stop after finding one. | ||
var _certFiles = []string{ | ||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. | ||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6 | ||
"/etc/ssl/ca-bundle.pem", // OpenSUSE | ||
"/etc/pki/tls/cacert.pem", // OpenELEC | ||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7 | ||
"/etc/ssl/cert.pem", // Alpine Linux | ||
} | ||
|
||
// Possible directories with certificate files; stop after successfully | ||
// reading at least one file from a directory. | ||
var _certDirectories = []string{ | ||
"/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 | ||
"/etc/pki/tls/certs", // Fedora/RHEL | ||
"/system/etc/security/cacerts", // Android | ||
} | ||
|
||
func _loadSystemRoots() (*x509.CertPool, error) { | ||
roots := x509.NewCertPool() | ||
rootsLen := 0 | ||
|
||
files := _certFiles | ||
if f := os.Getenv(_certFileEnv); f != "" { | ||
files = []string{f} | ||
} | ||
|
||
var firstErr error | ||
for _, file := range files { | ||
data, err := os.ReadFile(file) | ||
if err == nil { | ||
roots.AppendCertsFromPEM(data) | ||
rootsLen++ | ||
break | ||
} | ||
if firstErr == nil && !os.IsNotExist(err) { | ||
firstErr = err | ||
} | ||
} | ||
|
||
dirs := _certDirectories | ||
if d := os.Getenv(_certDirEnv); d != "" { | ||
// OpenSSL and BoringSSL both use ":" as the SSL_CERT_DIR separator. | ||
// See: | ||
// * https://golang.org/issue/35325 | ||
// * https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html | ||
dirs = strings.Split(d, ":") | ||
} | ||
|
||
for _, directory := range dirs { | ||
fis, err := _readUniqueDirectoryEntries(directory) | ||
if err != nil { | ||
if firstErr == nil && !os.IsNotExist(err) { | ||
firstErr = err | ||
} | ||
continue | ||
} | ||
for _, fi := range fis { | ||
data, err := os.ReadFile(directory + "/" + fi.Name()) | ||
if err == nil { | ||
roots.AppendCertsFromPEM(data) | ||
rootsLen++ | ||
} | ||
} | ||
} | ||
|
||
if rootsLen > 0 || firstErr == nil { | ||
return roots, nil | ||
} | ||
|
||
return nil, firstErr | ||
} | ||
|
||
// readUniqueDirectoryEntries is like os.ReadDir but omits | ||
// symlinks that point within the directory. | ||
func _readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) { | ||
files, err := os.ReadDir(dir) | ||
if err != nil { | ||
return nil, err | ||
} | ||
uniq := files[:0] | ||
for _, f := range files { | ||
if !_isSameDirSymlink(f, dir) { | ||
uniq = append(uniq, f) | ||
} | ||
} | ||
return uniq, nil | ||
} | ||
|
||
// isSameDirSymlink reports whether fi in dir is a symlink with a | ||
// target not containing a slash. | ||
func _isSameDirSymlink(f fs.DirEntry, dir string) bool { | ||
if f.Type()&fs.ModeSymlink == 0 { | ||
return false | ||
} | ||
target, err := os.Readlink(filepath.Join(dir, f.Name())) | ||
return err == nil && !strings.Contains(target, "/") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters