diff --git a/pkg/tls/test/test.csr b/pkg/tls/test/test.csr new file mode 100644 index 0000000..159d465 --- /dev/null +++ b/pkg/tls/test/test.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEjTCCAnUCAQAwSDELMAkGA1UEBhMCU1AxEzARBgNVBAgMClNvbWUtU3RhdGUx +FTATBgNVBAoMDFBnc3RyZWFtIEx0ZDENMAsGA1UECwwEWGF0YTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMZG8/obpyvJ+WkGkdO/hbExSN1nWR206/Dh +pSYzcZyI1Jj0R4Af0gD/EFVM+4KTDr20nOofmfBWOYHV+KwiKtWQQ+oT0+xVcTT6 +IC5I5K9+AXERuTu/NbnjkxuC/1u7K511RrUK0lxUra2/B8mGTc9nu2g415GVk2hU +rJjWEX09hVH7xBSmnzYN+IfepsftxgnR5m2YzqOSnsphBBfyyOsL+3Jo5Uv4yY22 +bnJCDxx/TPG37EcGMb4Q/aCWk5mXm4Io5mBfcl7SNxy867JpBO2CCP6fFaWRUGmF +/O+YBD5z0cSb1wZrMBRgezggpa2gacYVtsWrQYzAxMtCf3MwM89z8i+W9ME3cMhg +T7b6T0XCQ5gkqmLxDCsg9ocNV0W0wb5EEPlt4/TeqMmLbpLkIa6rnR2C6gg+wFSQ +Vk8c/aBtm9BjKFLWWUwDUPPzp1RdIVAfuobDK37dVqr+1m6oTDl+BoDuM5PsgTS4 +bFW2ZJVZB+d4IFmGhqTtKKmYa7QbwhzF8i5ShV+419KOt6hRkJ/jREdea7ZS/uyK +wBAvPHZVkUk8tfTpcuKTFVKsgXXV8uwwnI2W6safYbTXaN+7gfA88wntaigjeij/ +LrO+itAiv9GTGkpMlXyuAX/d5+4j0EHcV64NYL61GvMcbJ5G0SeQrXuBlgMTYaNr +O7miEujnAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAgEAGYFGSgMARWuH5VXK0/Fl +nNg+/rzdff1NYkY9QrvFxCQeVJ9rD1ml7VLZXDtXhMNEGJyYbkouc1Ehx0BsihT6 +YztcnQ6TzWAzvr3Ns9X3riADzXxdDHV5xs+8VPV8RvT3XNcrlw2NQmzJ4Juc8PkT +4ZfguZBywAmFTw1oX8JqlQSp5pYtP7popsvGPS6ieUm0Kmv8kK3sRDs+JSc7iXtB +/HymqeSylFNHgFZsdbYmu32v2qbcqimAitB/v5tGNhuiMXx6vEeQnB69V+AV70Rl +9dnvAo7ihTRMzecUVsoDFtc8OWSPdTm6t8vDI2JqmeDN25Xhyf89cKwoY97NhA99 +ds5WHs6TzsHohPZAsaxtZnjwxMEne7Y4FLFmTHVk5o0POTZcOC/sMB1iBDsd/YJe +AYsoiqLYtu6x6Avfe6LXWYWYa/R4/UXh8H6WiChsFXzOIilp3apjaeHM3z7iKx2S +VtGyVTrrcbzRiF0ShKVnbDXnvcoNZxPiXfh6Zz4SkBbV01T3hluBwzp4mjcWpiv3 +AOAWChMnbmkg/T+OME6e1JVHDR5tAC/7vF2QkZYpiH2RVnZmCTDWBcRGpMkhkRgF +eycowzKBkgIOcJ99p0sGEqQ3W0J1M4bzuumncLID08EG/dEp1eIdunahcHHyhnnv +BcGFr2/OxuaVmxcy5/QQjAg= +-----END CERTIFICATE REQUEST----- diff --git a/pkg/tls/test/test.key b/pkg/tls/test/test.key new file mode 100644 index 0000000..df3f707 --- /dev/null +++ b/pkg/tls/test/test.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +/WF38bnN3/Dej6Ns6FRE8gNSRmeT +-----END PRIVATE KEY----- diff --git a/pkg/tls/test/test.pem b/pkg/tls/test/test.pem new file mode 100644 index 0000000..75f10e2 --- /dev/null +++ b/pkg/tls/test/test.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFPzCCAyegAwIBAgIULV6zejFwt/Tri8WKZFBxj15uvaIwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCU1AxEzARBgNVBAgMClNvbWUtU3RhdGUxFTATBgNVBAoM +DFBnc3RyZWFtIEx0ZDENMAsGA1UECwwEWGF0YTAeFw0yNDA4MDUxNTE3NDBaFw0y +NTA4MDUxNTE3NDBaMEgxCzAJBgNVBAYTAlNQMRMwEQYDVQQIDApTb21lLVN0YXRl +MRUwEwYDVQQKDAxQZ3N0cmVhbSBMdGQxDTALBgNVBAsMBFhhdGEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDGRvP6G6cryflpBpHTv4WxMUjdZ1kdtOvw +4aUmM3GciNSY9EeAH9IA/xBVTPuCkw69tJzqH5nwVjmB1fisIirVkEPqE9PsVXE0 ++iAuSOSvfgFxEbk7vzW545Mbgv9buyuddUa1CtJcVK2tvwfJhk3PZ7toONeRlZNo +VKyY1hF9PYVR+8QUpp82DfiH3qbH7cYJ0eZtmM6jkp7KYQQX8sjrC/tyaOVL+MmN +tm5yQg8cf0zxt+xHBjG+EP2glpOZl5uCKOZgX3Je0jccvOuyaQTtggj+nxWlkVBp +hfzvmAQ+c9HEm9cGazAUYHs4IKWtoGnGFbbFq0GMwMTLQn9zMDPPc/IvlvTBN3DI +YE+2+k9FwkOYJKpi8QwrIPaHDVdFtMG+RBD5beP03qjJi26S5CGuq50dguoIPsBU +kFZPHP2gbZvQYyhS1llMA1Dz86dUXSFQH7qGwyt+3Vaq/tZuqEw5fgaA7jOT7IE0 +uGxVtmSVWQfneCBZhoak7SipmGu0G8IcxfIuUoVfuNfSjreoUZCf40RHXmu2Uv7s +isAQLzx2VZFJPLX06XLikxVSrIF11fLsMJyNlurGn2G012jfu4HwPPMJ7WooI3oo +/y6zvorQIr/RkxpKTJV8rgF/3efuI9BB3FeuDWC+tRrzHGyeRtEnkK17gZYDE2Gj +azu5ohLo5wIDAQABoyEwHzAdBgNVHQ4EFgQUcj2UaSuSsgkex5hfS0eDAkPdbJ0w +DQYJKoZIhvcNAQELBQADggIBAJK6fMa4L7iIQSlPzG3pHTSSLQd9Unev2naX9/S1 +Yo55Tj9VCBhViGa7CbDtaW7ZYr/fXydZVcthXYZzZ7QEVyYaguWlzXLjy/qF8kgk +cDwinFa8hiJnP+BJUGnzq3LYQJ2labI4YUscc6p4inh9y8JZ3n33VqX2YjqCdHMA +j8nw5xpThdQ/a8z3Z8ugFCLO09Hts1eKFhs5PwaQvjkoX+dSE2FeX51OMlLOPDsu +C6ScDU7FG0J5JE36nRqp2XwSdGAfc5pHKmsuomxnoE/d/hL7O6zouo/jvQyCNFtn +5/pzhkhhOjUTP2gIW5ueNn8oQF9F32GWRNJGQVTBiK17dWvHxiSvIzgKqUyrD8lI +VefVEQgRbfHD3nSk6G30gAeWzt8T10lI8MtQWTtoFJGFBaSVr/lSyHo4QS4SyTmK +uvnFGJVivRtaAP4d+u/6/1Mvy5sNsSiWRRKfKTB/FEerbe7blhnqJhrBp98nKBv/ +IJtmewD7lVGGDY8sWnxnpNyqLVhvRilO9d+4oQWqKgN8m1PXAI2jDYA0RZ+Qs/ko +5FB88mRi8hNOhmADXguKlnCid/X0StK6wpphvFIaNnGLFzjeZXc65BoV1c2+Boxe +cNwpkrW5tKaf/Ox1ntHnnQBpUhM4AxGoczfIj0dEnYio54gagsAMK/Pjq2KiX7Bi +RUm4 +-----END CERTIFICATE----- diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go index 8351681..8735e0d 100644 --- a/pkg/tls/tls.go +++ b/pkg/tls/tls.go @@ -6,21 +6,23 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io" "os" ) type Config struct { // Enabled determines if TLS should be used. Defaults to false. Enabled bool - // File path to the CA PEM certificate to be used for TLS connection. If TLS is - // enabled and no CA cert file is provided, the system certificate pool is - // used as default. + // File path to the CA PEM certificate or PEM certificate to be used for TLS + // connection. If TLS is enabled and no CA cert file is provided, the system + // certificate pool is used as default. CaCertFile string - // File path to the client PEM certificate + CaCertPEM string + // File path to the client PEM certificate or client PEM certificate ClientCertFile string - // File path to the client PEM key + ClientCertPEM string + // File path to the client PEM key or client PEM key content ClientKeyFile string + ClientKeyPEM string } func NewConfig(cfg *Config) (*tls.Config, error) { @@ -28,12 +30,12 @@ func NewConfig(cfg *Config) (*tls.Config, error) { return nil, nil } - certPool, err := getCertPool(cfg.CaCertFile) + certPool, err := getCertPool(cfg) if err != nil { return nil, err } - certificates, err := getCertificates(cfg.ClientCertFile, cfg.ClientKeyFile) + certificates, err := getCertificates(cfg) if err != nil { return nil, err } @@ -46,23 +48,32 @@ func NewConfig(cfg *Config) (*tls.Config, error) { }, nil } -func getCertPool(caCertFile string) (*x509.CertPool, error) { - if caCertFile != "" { - pemCertBytes, err := readFile(caCertFile) - if err != nil { - return nil, fmt.Errorf("reading CA certificate file: %w", err) - } - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(pemCertBytes) - return certPool, nil +func getCertPool(cfg *Config) (*x509.CertPool, error) { + pemCertBytes, err := readPEMBytes(cfg.CaCertFile, cfg.CaCertPEM) + if err != nil { + return nil, fmt.Errorf("reading CA certificate file: %w", err) + } + + if len(pemCertBytes) == 0 { + return x509.SystemCertPool() } - return x509.SystemCertPool() + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM(pemCertBytes) + return certPool, nil } -func getCertificates(clientCertFile, clientKeyFile string) ([]tls.Certificate, error) { - if clientCertFile != "" && clientKeyFile != "" { - cert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile) +func getCertificates(cfg *Config) ([]tls.Certificate, error) { + if cfg.IsClientCertProvided() { + pemCertBytes, err := readPEMBytes(cfg.ClientCertFile, cfg.ClientCertPEM) + if err != nil { + return nil, err + } + pemKeyBytes, err := readPEMBytes(cfg.ClientKeyFile, cfg.ClientKeyPEM) + if err != nil { + return nil, err + } + cert, err := tls.X509KeyPair(pemCertBytes, pemKeyBytes) if err != nil { return nil, err } @@ -72,12 +83,16 @@ func getCertificates(clientCertFile, clientKeyFile string) ([]tls.Certificate, e return []tls.Certificate{}, nil } -func readFile(path string) ([]byte, error) { - file, err := os.Open(path) - if err != nil { - return nil, err +// readPEMBytes will parse the certificate on input and return the pem byte +// content. It accepts a pem certificate or the file path to a pem certificate. +func readPEMBytes(certFile, certPEM string) ([]byte, error) { + if certFile != "" { + return os.ReadFile(certFile) } - defer file.Close() - return io.ReadAll(file) + return []byte(certPEM), nil +} + +func (c *Config) IsClientCertProvided() bool { + return (c.ClientCertFile != "" || c.ClientCertPEM != "") && (c.ClientKeyFile != "" || c.ClientKeyPEM != "") } diff --git a/pkg/tls/tls_test.go b/pkg/tls/tls_test.go new file mode 100644 index 0000000..53e79aa --- /dev/null +++ b/pkg/tls/tls_test.go @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: Apache-2.0 + +package tls + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/stretchr/testify/require" +) + +func Test_NewConfig(t *testing.T) { + t.Parallel() + + systemCAs, err := x509.SystemCertPool() + require.NoError(t, err) + + testPEMBytes, err := os.ReadFile("test/test.pem") + require.NoError(t, err) + testCertPool := x509.NewCertPool() + testCertPool.AppendCertsFromPEM(testPEMBytes) + + testClientKeyPair, err := tls.LoadX509KeyPair("test/test.pem", "test/test.key") + require.NoError(t, err) + + tests := []struct { + name string + cfg *Config + + wantConfig *tls.Config + wantErr error + }{ + { + name: "ok - tls not enabled", + cfg: &Config{ + Enabled: false, + }, + + wantConfig: nil, + wantErr: nil, + }, + { + name: "ok - tls enabled no certificates", + cfg: &Config{ + Enabled: true, + }, + + wantConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: 0, + Certificates: []tls.Certificate{}, + RootCAs: systemCAs, + }, + wantErr: nil, + }, + { + name: "ok - tls enabled with CA certificate", + cfg: &Config{ + Enabled: true, + CaCertFile: "test/test.pem", + }, + + wantConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: 0, + Certificates: []tls.Certificate{}, + RootCAs: testCertPool, + }, + wantErr: nil, + }, + { + name: "ok - tls enabled with client certificate", + cfg: &Config{ + Enabled: true, + ClientCertFile: "test/test.pem", + ClientKeyFile: "test/test.key", + }, + + wantConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: 0, + Certificates: []tls.Certificate{testClientKeyPair}, + RootCAs: systemCAs, + }, + wantErr: nil, + }, + { + name: "ok - tls enabled with CA and client certificate", + cfg: &Config{ + Enabled: true, + CaCertFile: "test/test.pem", + ClientCertFile: "test/test.pem", + ClientKeyFile: "test/test.key", + }, + + wantConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + MaxVersion: 0, + Certificates: []tls.Certificate{testClientKeyPair}, + RootCAs: testCertPool, + }, + wantErr: nil, + }, + { + name: "error - invalid CA certificate file", + cfg: &Config{ + Enabled: true, + CaCertFile: "test/doesnotexist.pem", + }, + + wantConfig: nil, + wantErr: os.ErrNotExist, + }, + { + name: "error - invalid client certificate file", + cfg: &Config{ + Enabled: true, + ClientCertFile: "test/doesnotexist.pem", + ClientKeyFile: "test/test.pem", + }, + + wantConfig: nil, + wantErr: os.ErrNotExist, + }, + { + name: "error - invalid client key file", + cfg: &Config{ + Enabled: true, + ClientCertFile: "test/test.pem", + ClientKeyFile: "test/doesnotexist.pem", + }, + + wantConfig: nil, + wantErr: os.ErrNotExist, + }, + { + name: "error - invalid client key pair", + cfg: &Config{ + Enabled: true, + ClientCertFile: "test/test.pem", + ClientKeyFile: "test/test.pem", + }, + + wantConfig: nil, + wantErr: errors.New("tls: found a certificate rather than a key in the PEM for the private key"), + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + tlsCfg, err := NewConfig(tc.cfg) + if !errors.Is(err, tc.wantErr) { + require.EqualError(t, err, tc.wantErr.Error()) + } + require.Equal(t, "", cmp.Diff(tlsCfg, tc.wantConfig, cmpopts.IgnoreUnexported(tls.Config{}))) //nolint:gosec + }) + } +} + +func Test_readPEMBytes(t *testing.T) { + t.Parallel() + + testPEMBytes, err := os.ReadFile("test/test.pem") + require.NoError(t, err) + + tests := []struct { + name string + file string + pem string + + wantBytes []byte + wantErr error + }{ + { + name: "with file", + file: "test/test.pem", + + wantBytes: testPEMBytes, + wantErr: nil, + }, + { + name: "with pem", + pem: string(testPEMBytes), + + wantBytes: testPEMBytes, + wantErr: nil, + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + pemBytes, err := readPEMBytes(tc.file, tc.pem) + require.ErrorIs(t, err, tc.wantErr) + require.Equal(t, tc.wantBytes, pemBytes) + }) + } +}