Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Shushlin <vshushlin@gitlab.com>2020-07-20 11:32:43 +0300
committerVladimir Shushlin <vshushlin@gitlab.com>2020-07-20 11:32:43 +0300
commit7e2600ea4ad6a8ef2d19c07eadb8c7aa7b8c65e2 (patch)
tree7d18810a56ee6e0fd3a68c3748b5adb2a11830f5
parentdc7bf0c3a847320b9370decc8792aff3712dd3e2 (diff)
parent8d65281f548d6a25e764e1ca47a9821a3d8152a7 (diff)
Merge branch '415-424-load-ssl-cert-dir' into 'master'
Load certs from SSL_CERT_DIR Closes #415 See merge request gitlab-org/gitlab-pages!302
-rw-r--r--internal/httptransport/LICENSE27
-rw-r--r--internal/httptransport/transport.go30
-rw-r--r--internal/httptransport/transport_darwin.go118
3 files changed, 154 insertions, 21 deletions
diff --git a/internal/httptransport/LICENSE b/internal/httptransport/LICENSE
new file mode 100644
index 00000000..6a66aea5
--- /dev/null
+++ b/internal/httptransport/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/internal/httptransport/transport.go b/internal/httptransport/transport.go
index d6ca6de2..e6094ed7 100644
--- a/internal/httptransport/transport.go
+++ b/internal/httptransport/transport.go
@@ -3,10 +3,8 @@ package httptransport
import (
"crypto/tls"
"crypto/x509"
- "io/ioutil"
"net"
"net/http"
- "os"
"strconv"
"sync"
"time"
@@ -19,6 +17,8 @@ var (
sysPoolOnce = &sync.Once{}
sysPool *x509.CertPool
+ // only overridden by transport_darwin.go
+ loadExtraCerts = func() {}
// InternalTransport can be used with http.Client with TLS and certificates
InternalTransport = newInternalTransport()
)
@@ -52,10 +52,10 @@ func NewTransportWithMetrics(gaugeVec *prometheus.GaugeVec, counterVec *promethe
}
}
-// This is here because macOS does not support the SSL_CERT_FILE
-// environment variable. We have arrange things to read SSL_CERT_FILE as
-// late as possible to avoid conflicts with file descriptor passing at
-// startup.
+// This is here because macOS does not support the SSL_CERT_FILE and
+// SSL_CERT_DIR environment variables. We have arranged things to read
+// SSL_CERT_FILE and SSL_CERT_DIR as late as possible to avoid conflicts
+// with file descriptor passing at startup.
func pool() *x509.CertPool {
sysPoolOnce.Do(loadPool)
return sysPool
@@ -71,21 +71,9 @@ func loadPool() {
return
}
- // Try to load from SSL_CERT_FILE
- // TODO: Handle SSL_CERT_DIR?
- // See https://gitlab.com/gitlab-org/gitlab-pages/-/issues/415
- sslCertFile := os.Getenv("SSL_CERT_FILE")
- if sslCertFile == "" {
- return
- }
-
- certPem, err := ioutil.ReadFile(sslCertFile)
- if err != nil {
- log.WithError(err).Error("failed to read SSL_CERT_FILE")
- return
- }
-
- sysPool.AppendCertsFromPEM(certPem)
+ // Go does not load SSL_CERT_FILE and SSL_CERT_DIR on darwin systems so we need to
+ // load them manually in OSX. See https://golang.org/src/crypto/x509/root_unix.go
+ loadExtraCerts()
}
// withRoundTripper takes an original RoundTripper, reports metrics based on the
diff --git a/internal/httptransport/transport_darwin.go b/internal/httptransport/transport_darwin.go
new file mode 100644
index 00000000..b73009da
--- /dev/null
+++ b/internal/httptransport/transport_darwin.go
@@ -0,0 +1,118 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+// Modified copy of https://golang.org/src/crypto/x509/root_unix.go
+
+package httptransport
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ log "github.com/sirupsen/logrus"
+)
+
+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"
+)
+
+func init() {
+ // override and load SSL_CERT_FILE and SSL_CERT_DIR in OSX.
+ loadExtraCerts = func() {
+ if err := loadCertFile(); err != nil {
+ log.WithError(err).Error("failed to read SSL_CERT_FILE")
+ }
+
+ if err := loadCertDir(); err != nil {
+ log.WithError(err).Error("failed to load SSL_CERT_DIR")
+ }
+ }
+}
+
+func loadCertFile() error {
+ sslCertFile := os.Getenv(certFileEnv)
+ if sslCertFile == "" {
+ return nil
+ }
+
+ data, err := ioutil.ReadFile(sslCertFile)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ sysPool.AppendCertsFromPEM(data)
+
+ return nil
+}
+
+func loadCertDir() error {
+ var firstErr error
+ var dirs []string
+ 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
+ }
+
+ rootsAdded := false
+ for _, fi := range fis {
+ data, err := ioutil.ReadFile(directory + "/" + fi.Name())
+ if err == nil && sysPool.AppendCertsFromPEM(data) {
+ rootsAdded = true
+ }
+ }
+
+ if rootsAdded {
+ return nil
+ }
+ }
+
+ return firstErr
+}
+
+// readUniqueDirectoryEntries is like ioutil.ReadDir but omits
+// symlinks that point within the directory.
+func readUniqueDirectoryEntries(dir string) ([]os.FileInfo, error) {
+ fis, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return nil, err
+ }
+ uniq := fis[:0]
+ for _, fi := range fis {
+ if !isSameDirSymlink(fi, dir) {
+ uniq = append(uniq, fi)
+ }
+ }
+ return uniq, nil
+}
+
+// isSameDirSymlink reports whether fi in dir is a symlink with a
+// target not containing a slash.
+func isSameDirSymlink(fi os.FileInfo, dir string) bool {
+ if fi.Mode()&os.ModeSymlink == 0 {
+ return false
+ }
+ target, err := os.Readlink(filepath.Join(dir, fi.Name()))
+ return err == nil && !strings.Contains(target, "/")
+}