2018-09-06 21:42:41 +00:00
|
|
|
package lfshttp
|
2016-12-20 18:22:20 +00:00
|
|
|
|
|
|
|
import (
|
2017-01-16 14:58:06 +00:00
|
|
|
"crypto/tls"
|
2016-12-20 18:22:20 +00:00
|
|
|
"crypto/x509"
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
"encoding/pem"
|
2016-12-20 18:22:20 +00:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
"net/url"
|
2016-12-20 18:22:20 +00:00
|
|
|
"path/filepath"
|
|
|
|
|
2021-08-10 06:18:38 +00:00
|
|
|
"github.com/git-lfs/git-lfs/v2/config"
|
|
|
|
"github.com/git-lfs/git-lfs/v2/tools"
|
2016-12-20 18:22:20 +00:00
|
|
|
"github.com/rubyist/tracerx"
|
|
|
|
)
|
|
|
|
|
|
|
|
// isCertVerificationDisabledForHost returns whether SSL certificate verification
|
|
|
|
// has been disabled for the given host, or globally
|
|
|
|
func isCertVerificationDisabledForHost(c *Client, host string) bool {
|
2017-04-17 20:36:21 +00:00
|
|
|
hostSslVerify, _ := c.uc.Get("http", fmt.Sprintf("https://%v", host), "sslverify")
|
2016-12-20 18:22:20 +00:00
|
|
|
if hostSslVerify == "false" {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.SkipSSLVerify
|
|
|
|
}
|
|
|
|
|
2017-01-16 14:58:06 +00:00
|
|
|
// isClientCertEnabledForHost returns whether client certificate
|
|
|
|
// are configured for the given host
|
|
|
|
func isClientCertEnabledForHost(c *Client, host string) bool {
|
2017-04-17 20:36:21 +00:00
|
|
|
_, hostSslKeyOk := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslKey")
|
|
|
|
_, hostSslCertOk := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslCert")
|
2017-01-16 14:58:06 +00:00
|
|
|
|
2017-01-24 22:07:13 +00:00
|
|
|
return hostSslKeyOk && hostSslCertOk
|
2017-01-16 14:58:06 +00:00
|
|
|
}
|
|
|
|
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
// decryptPEMBlock decrypts an encrypted PEM block representing a private key,
|
|
|
|
// prompting for credentials using the credential helper, and returns a
|
|
|
|
// decrypted PEM block representing that same private key.
|
|
|
|
func decryptPEMBlock(c *Client, block *pem.Block, path string, key []byte) ([]byte, error) {
|
|
|
|
fileurl := fmt.Sprintf("cert:///%s", filepath.ToSlash(path))
|
|
|
|
url, err := url.Parse(fileurl)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-04-18 14:41:55 +00:00
|
|
|
credWrapper := c.credHelperContext.GetCredentialHelper(nil, url)
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
|
2019-04-18 14:41:55 +00:00
|
|
|
credWrapper.Input["username"] = ""
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
|
2019-04-18 14:41:55 +00:00
|
|
|
creds, err := credWrapper.CredentialHelper.Fill(credWrapper.Input)
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error filling credentials for %q: %v", fileurl, err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
pass := creds["password"]
|
|
|
|
decrypted, err := x509.DecryptPEMBlock(block, []byte(pass))
|
|
|
|
if err != nil {
|
2019-04-18 14:41:55 +00:00
|
|
|
credWrapper.CredentialHelper.Reject(creds)
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2019-04-18 14:41:55 +00:00
|
|
|
credWrapper.CredentialHelper.Approve(creds)
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
|
|
|
|
// decrypted is a DER blob, but we need a PEM-encoded block.
|
|
|
|
toEncode := &pem.Block{Type: block.Type, Headers: nil, Bytes: decrypted}
|
|
|
|
buf := pem.EncodeToMemory(toEncode)
|
|
|
|
return buf, nil
|
|
|
|
}
|
|
|
|
|
2017-01-16 14:58:06 +00:00
|
|
|
// getClientCertForHost returns a client certificate for a specific host (which may
|
|
|
|
// be "host:port" loaded from the gitconfig
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
func getClientCertForHost(c *Client, host string) *tls.Certificate {
|
2017-04-17 20:36:21 +00:00
|
|
|
hostSslKey, _ := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslKey")
|
|
|
|
hostSslCert, _ := c.uc.Get("http", fmt.Sprintf("https://%v/", host), "sslCert")
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
|
|
|
|
cert, err := ioutil.ReadFile(hostSslCert)
|
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error reading client cert file %q: %v", hostSslCert, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
key, err := ioutil.ReadFile(hostSslKey)
|
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error reading client key file %q: %v", hostSslKey, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
block, _ := pem.Decode(key)
|
|
|
|
if x509.IsEncryptedPEMBlock(block) {
|
|
|
|
key, err = decryptPEMBlock(c, block, hostSslKey, key)
|
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Unable to decrypt client key file %q: %v", hostSslKey, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
certobj, err := tls.X509KeyPair(cert, key)
|
2017-01-16 14:58:06 +00:00
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error reading client cert/key %v", err)
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
return nil
|
2017-01-16 14:58:06 +00:00
|
|
|
}
|
lfsapi: add support for encrypted client TLS private keys
When using client certificates for TLS, it's possible to specify a
private key file with an encrypted private key. Previously, we silently
returned a nil Certificate object in this case which promptly resulted
in a panic in crypto/tls when attempting to push.
Instead, let's detect that the key is encrypted and prompt for a
passphrase. Git usually handles this with a prompt from OpenSSL, which
we aren't using, although it can be configured to use the credential
helper as well.
Since there isn't a portable way to turn off the echo in order to prompt
for a passphrase, even among Unix systems, let's use the credential
helper route for this purpose by prompting for credentials using a cert:
URL for the file holding the private key; this is the type of URL that
Git uses with the credential helper for this purpose.
In order to make things as intuitive as possible, tell the credential
code to always include the path for cert: URLs (so we don't just prompt
for "cert:///") and provide the user's current username in the username
field so they don't get a useless username prompt. Provide as much
helpful trace output as possible for debugging; note that credential
filling success and failure already have trace logging enabled
elsewhere.
Note that we create our own credential helper for the client object to
avoid having to pass it into the HTTP client context from the LFS API
context; this should be fine, since we're going to prompt and use this
value only within this context and for this purpose.
Finally, since we're in a context where we can't really return an error
up the chain, if for whatever reason an error occurs, ensure that we
don't pass nil to crypto/tls and instead skip passing a certificate
altogether. This will at least make the failure case obvious later on
and provide a better user experience than a panic.
2018-09-19 18:56:48 +00:00
|
|
|
return &certobj
|
2017-01-16 14:58:06 +00:00
|
|
|
}
|
|
|
|
|
2016-12-20 18:22:20 +00:00
|
|
|
// getRootCAsForHost returns a certificate pool for that specific host (which may
|
|
|
|
// be "host:port" loaded from either the gitconfig or from a platform-specific
|
|
|
|
// source which is not included by default in the golang certificate search)
|
|
|
|
// May return nil if it doesn't have anything to add, in which case the default
|
|
|
|
// RootCAs will be used if passed to TLSClientConfig.RootCAs
|
|
|
|
func getRootCAsForHost(c *Client, host string) *x509.CertPool {
|
|
|
|
// don't init pool, want to return nil not empty if none found; init only on successful add cert
|
|
|
|
var pool *x509.CertPool
|
|
|
|
|
|
|
|
// gitconfig first
|
|
|
|
pool = appendRootCAsForHostFromGitconfig(c.osEnv, c.gitEnv, pool, host)
|
|
|
|
// Platform specific
|
|
|
|
return appendRootCAsForHostFromPlatform(pool, host)
|
|
|
|
}
|
|
|
|
|
2017-10-25 21:33:20 +00:00
|
|
|
func appendRootCAsForHostFromGitconfig(osEnv, gitEnv config.Environment, pool *x509.CertPool, host string) *x509.CertPool {
|
2019-10-18 18:19:35 +00:00
|
|
|
url := fmt.Sprintf("https://%v/", host)
|
|
|
|
uc := config.NewURLConfig(gitEnv)
|
|
|
|
|
|
|
|
backend, _ := uc.Get("http", url, "sslbackend")
|
|
|
|
schannelUseSslCaInfoStrValue, _ := uc.Get("http", url, "schannelusesslcainfo")
|
|
|
|
schannelUseSslCaInfo := config.Bool(schannelUseSslCaInfoStrValue, false)
|
|
|
|
|
|
|
|
if backend == "schannel" && !schannelUseSslCaInfo {
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
2016-12-20 18:22:20 +00:00
|
|
|
// Accumulate certs from all these locations:
|
|
|
|
|
|
|
|
// GIT_SSL_CAINFO first
|
|
|
|
if cafile, _ := osEnv.Get("GIT_SSL_CAINFO"); len(cafile) > 0 {
|
|
|
|
return appendCertsFromFile(pool, cafile)
|
|
|
|
}
|
|
|
|
// http.<url>/.sslcainfo or http.<url>.sslcainfo
|
2019-10-18 18:19:35 +00:00
|
|
|
if cafile, ok := uc.Get("http", url, "sslcainfo"); ok {
|
2016-12-20 18:22:20 +00:00
|
|
|
return appendCertsFromFile(pool, cafile)
|
|
|
|
}
|
|
|
|
// GIT_SSL_CAPATH
|
|
|
|
if cadir, _ := osEnv.Get("GIT_SSL_CAPATH"); len(cadir) > 0 {
|
|
|
|
return appendCertsFromFilesInDir(pool, cadir)
|
|
|
|
}
|
|
|
|
// http.sslcapath
|
|
|
|
if cadir, ok := gitEnv.Get("http.sslcapath"); ok {
|
|
|
|
return appendCertsFromFilesInDir(pool, cadir)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
|
|
|
func appendCertsFromFilesInDir(pool *x509.CertPool, dir string) *x509.CertPool {
|
2021-04-09 08:56:27 +00:00
|
|
|
dirpath, errpath := tools.TranslateCygwinPath(dir)
|
|
|
|
if errpath != nil {
|
|
|
|
tracerx.Printf("Error reading cert dir %q: %v", dirpath, errpath)
|
|
|
|
}
|
|
|
|
files, err := ioutil.ReadDir(dirpath)
|
2016-12-20 18:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error reading cert dir %q: %v", dir, err)
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
for _, f := range files {
|
|
|
|
pool = appendCertsFromFile(pool, filepath.Join(dir, f.Name()))
|
|
|
|
}
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
|
|
|
func appendCertsFromFile(pool *x509.CertPool, filename string) *x509.CertPool {
|
2021-04-09 08:56:27 +00:00
|
|
|
filenamepath, errfile := tools.TranslateCygwinPath(filename)
|
|
|
|
if errfile != nil {
|
|
|
|
tracerx.Printf("Error reading cert dir %q: %v", filenamepath, errfile)
|
|
|
|
}
|
|
|
|
data, err := ioutil.ReadFile(filenamepath)
|
2016-12-20 18:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
tracerx.Printf("Error reading cert file %q: %v", filename, err)
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
// Firstly, try parsing as binary certificate
|
|
|
|
if certs, err := x509.ParseCertificates(data); err == nil {
|
|
|
|
return appendCerts(pool, certs)
|
|
|
|
}
|
|
|
|
// If not binary certs, try PEM data
|
|
|
|
return appendCertsFromPEMData(pool, data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func appendCerts(pool *x509.CertPool, certs []*x509.Certificate) *x509.CertPool {
|
|
|
|
if len(certs) == 0 {
|
|
|
|
// important to return unmodified (may be nil)
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
|
|
|
if pool == nil {
|
|
|
|
pool = x509.NewCertPool()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, cert := range certs {
|
|
|
|
pool.AddCert(cert)
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
|
|
|
func appendCertsFromPEMData(pool *x509.CertPool, data []byte) *x509.CertPool {
|
|
|
|
if len(data) == 0 {
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit of a dance, need to ensure if AppendCertsFromPEM fails we still return
|
|
|
|
// nil and not an empty pool, so system roots still get used
|
|
|
|
var ret *x509.CertPool
|
|
|
|
if pool == nil {
|
|
|
|
ret = x509.NewCertPool()
|
|
|
|
} else {
|
|
|
|
ret = pool
|
|
|
|
}
|
|
|
|
if !ret.AppendCertsFromPEM(data) {
|
|
|
|
// Return unmodified input pool (may be nil, do not replace with empty)
|
|
|
|
return pool
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|