feat: extended support of cert pool (#1565)

- `LEGO_CA_CERTIFICATES` now accepts multiple file paths to be added by using `os.PathListSeparator` (`:` on POSIX, `;` on Windows) as a separator.
- `LEGO_CA_SYSTEM_CERT_POOL` initiates the cert pool with a copy of the system cert pool.
This commit is contained in:
Ludovic Fernandez 2022-01-18 23:22:04 +01:00 committed by GitHub
parent bbec0a6e50
commit 6b58241295
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -7,6 +7,8 @@ import (
"net" "net"
"net/http" "net/http"
"os" "os"
"strconv"
"strings"
"time" "time"
"github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/certcrypto"
@ -16,10 +18,15 @@ import (
const ( const (
// caCertificatesEnvVar is the environment variable name that can be used to // caCertificatesEnvVar is the environment variable name that can be used to
// specify the path to PEM encoded CA Certificates that can be used to // specify the path to PEM encoded CA Certificates that can be used to
// authenticate an ACME server with a HTTPS certificate not issued by a CA in // authenticate an ACME server with an HTTPS certificate not issued by a CA in
// the system-wide trusted root list. // the system-wide trusted root list.
// Multiple file paths can be added by using os.PathListSeparator as a separator.
caCertificatesEnvVar = "LEGO_CA_CERTIFICATES" caCertificatesEnvVar = "LEGO_CA_CERTIFICATES"
// caSystemCertPool is the environment variable name that can be used to define
// if the certificates pool must use a copy of the system cert pool.
caSystemCertPool = "LEGO_CA_SYSTEM_CERT_POOL"
// caServerNameEnvVar is the environment variable name that can be used to // caServerNameEnvVar is the environment variable name that can be used to
// specify the CA server name that can be used to // specify the CA server name that can be used to
// authenticate an ACME server with a HTTPS certificate not issued by a CA in // authenticate an ACME server with a HTTPS certificate not issued by a CA in
@ -81,23 +88,44 @@ func createDefaultHTTPClient() *http.Client {
} }
// initCertPool creates a *x509.CertPool populated with the PEM certificates // initCertPool creates a *x509.CertPool populated with the PEM certificates
// found in the filepath specified in the caCertificatesEnvVar OS environment // found in the filepath specified in the caCertificatesEnvVar OS environment variable.
// variable. If the caCertificatesEnvVar is not set then initCertPool will // If the caCertificatesEnvVar is not set then initCertPool will return nil.
// return nil. If there is an error creating a *x509.CertPool from the provided // If there is an error creating a *x509.CertPool from the provided caCertificatesEnvVar value then initCertPool will panic.
// caCertificatesEnvVar value then initCertPool will panic. // If the caSystemCertPool is set to a "truthy value" (`1`, `t`, `T`, `TRUE`, `true`, `True`) then a copy of system cert pool will be used.
// caSystemCertPool requires caCertificatesEnvVar to be set.
func initCertPool() *x509.CertPool { func initCertPool() *x509.CertPool {
if customCACertsPath := os.Getenv(caCertificatesEnvVar); customCACertsPath != "" { customCACertsPath := os.Getenv(caCertificatesEnvVar)
customCAs, err := os.ReadFile(customCACertsPath) if customCACertsPath == "" {
return nil
}
certPool := getCertPool()
for _, customPath := range strings.Split(customCACertsPath, string(os.PathListSeparator)) {
customCAs, err := os.ReadFile(customPath)
if err != nil { if err != nil {
panic(fmt.Sprintf("error reading %s=%q: %v", panic(fmt.Sprintf("error reading %s=%q: %v",
caCertificatesEnvVar, customCACertsPath, err)) caCertificatesEnvVar, customPath, err))
} }
certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(customCAs); !ok { if ok := certPool.AppendCertsFromPEM(customCAs); !ok {
panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v", panic(fmt.Sprintf("error creating x509 cert pool from %s=%q: %v",
caCertificatesEnvVar, customCACertsPath, err)) caCertificatesEnvVar, customPath, err))
} }
return certPool
} }
return nil
return certPool
}
func getCertPool() *x509.CertPool {
useSystemCertPool, _ := strconv.ParseBool(os.Getenv(caSystemCertPool))
if !useSystemCertPool {
return x509.NewCertPool()
}
pool, err := x509.SystemCertPool()
if err == nil {
return pool
}
return x509.NewCertPool()
} }