github.com/stffabi/git-lfs@v2.3.5-0.20180214015214-8eeaa8d88902+incompatible/lfsapi/certs.go (about) 1 package lfsapi 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "fmt" 7 "io/ioutil" 8 "path/filepath" 9 10 "github.com/git-lfs/git-lfs/config" 11 "github.com/rubyist/tracerx" 12 ) 13 14 // isCertVerificationDisabledForHost returns whether SSL certificate verification 15 // has been disabled for the given host, or globally 16 func isCertVerificationDisabledForHost(c *Client, host string) bool { 17 hostSslVerify, _ := c.uc.Get("http", fmt.Sprintf("https://%v", host), "sslverify") 18 if hostSslVerify == "false" { 19 return true 20 } 21 22 return c.SkipSSLVerify 23 } 24 25 // isClientCertEnabledForHost returns whether client certificate 26 // are configured for the given host 27 func isClientCertEnabledForHost(c *Client, host string) bool { 28 _, hostSslKeyOk := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslKey") 29 _, hostSslCertOk := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslCert") 30 31 return hostSslKeyOk && hostSslCertOk 32 } 33 34 // getClientCertForHost returns a client certificate for a specific host (which may 35 // be "host:port" loaded from the gitconfig 36 func getClientCertForHost(c *Client, host string) tls.Certificate { 37 hostSslKey, _ := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslKey") 38 hostSslCert, _ := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslCert") 39 cert, err := tls.LoadX509KeyPair(hostSslCert, hostSslKey) 40 if err != nil { 41 tracerx.Printf("Error reading client cert/key %v", err) 42 } 43 return cert 44 } 45 46 // getRootCAsForHost returns a certificate pool for that specific host (which may 47 // be "host:port" loaded from either the gitconfig or from a platform-specific 48 // source which is not included by default in the golang certificate search) 49 // May return nil if it doesn't have anything to add, in which case the default 50 // RootCAs will be used if passed to TLSClientConfig.RootCAs 51 func getRootCAsForHost(c *Client, host string) *x509.CertPool { 52 // don't init pool, want to return nil not empty if none found; init only on successful add cert 53 var pool *x509.CertPool 54 55 // gitconfig first 56 pool = appendRootCAsForHostFromGitconfig(c.osEnv, c.gitEnv, pool, host) 57 // Platform specific 58 return appendRootCAsForHostFromPlatform(pool, host) 59 } 60 61 func appendRootCAsForHostFromGitconfig(osEnv, gitEnv config.Environment, pool *x509.CertPool, host string) *x509.CertPool { 62 // Accumulate certs from all these locations: 63 64 // GIT_SSL_CAINFO first 65 if cafile, _ := osEnv.Get("GIT_SSL_CAINFO"); len(cafile) > 0 { 66 return appendCertsFromFile(pool, cafile) 67 } 68 // http.<url>/.sslcainfo or http.<url>.sslcainfo 69 uc := config.NewURLConfig(gitEnv) 70 if cafile, ok := uc.Get("http", fmt.Sprintf("https://%v/", host), "sslcainfo"); ok { 71 return appendCertsFromFile(pool, cafile) 72 } 73 // GIT_SSL_CAPATH 74 if cadir, _ := osEnv.Get("GIT_SSL_CAPATH"); len(cadir) > 0 { 75 return appendCertsFromFilesInDir(pool, cadir) 76 } 77 // http.sslcapath 78 if cadir, ok := gitEnv.Get("http.sslcapath"); ok { 79 return appendCertsFromFilesInDir(pool, cadir) 80 } 81 82 return pool 83 } 84 85 func appendCertsFromFilesInDir(pool *x509.CertPool, dir string) *x509.CertPool { 86 files, err := ioutil.ReadDir(dir) 87 if err != nil { 88 tracerx.Printf("Error reading cert dir %q: %v", dir, err) 89 return pool 90 } 91 for _, f := range files { 92 pool = appendCertsFromFile(pool, filepath.Join(dir, f.Name())) 93 } 94 return pool 95 } 96 97 func appendCertsFromFile(pool *x509.CertPool, filename string) *x509.CertPool { 98 data, err := ioutil.ReadFile(filename) 99 if err != nil { 100 tracerx.Printf("Error reading cert file %q: %v", filename, err) 101 return pool 102 } 103 // Firstly, try parsing as binary certificate 104 if certs, err := x509.ParseCertificates(data); err == nil { 105 return appendCerts(pool, certs) 106 } 107 // If not binary certs, try PEM data 108 return appendCertsFromPEMData(pool, data) 109 } 110 111 func appendCerts(pool *x509.CertPool, certs []*x509.Certificate) *x509.CertPool { 112 if len(certs) == 0 { 113 // important to return unmodified (may be nil) 114 return pool 115 } 116 117 if pool == nil { 118 pool = x509.NewCertPool() 119 } 120 121 for _, cert := range certs { 122 pool.AddCert(cert) 123 } 124 125 return pool 126 } 127 128 func appendCertsFromPEMData(pool *x509.CertPool, data []byte) *x509.CertPool { 129 if len(data) == 0 { 130 return pool 131 } 132 133 // Bit of a dance, need to ensure if AppendCertsFromPEM fails we still return 134 // nil and not an empty pool, so system roots still get used 135 var ret *x509.CertPool 136 if pool == nil { 137 ret = x509.NewCertPool() 138 } else { 139 ret = pool 140 } 141 if !ret.AppendCertsFromPEM(data) { 142 // Return unmodified input pool (may be nil, do not replace with empty) 143 return pool 144 } 145 return ret 146 }