1
0
Fork 0
telegraf/plugins/inputs/x509_cert/java_key_store_test.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

201 lines
5.4 KiB
Go

package x509_cert
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/pavlo-v-chernykh/keystore-go/v4"
"github.com/stretchr/testify/require"
"software.sslmate.com/src/go-pkcs12"
"github.com/influxdata/telegraf/config"
"github.com/influxdata/telegraf/testutil"
)
type selfSignedCert struct {
certPEM []byte
keyPEM []byte
certDER []byte
}
// generateTestKeystores creates temporary JKS & PKCS#12 keystores for testing
func generateTestKeystores(t *testing.T) (pkcs12Path, jksPath string) {
t.Helper()
// Generate a test certificate
selfSigned := generateselfSignedCert(t)
pkcs12Path = createTestPKCS12(t, selfSigned.certPEM, selfSigned.keyPEM)
jksPath = createTestJKS(t, selfSigned.certDER)
return pkcs12Path, jksPath
}
// generateselfSignedCert generates a dummy self-signed certificate
func generateselfSignedCert(t *testing.T) selfSignedCert {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "Test Certificate",
Organization: []string{"Test Org"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
require.NoError(t, err)
return selfSignedCert{
certPEM: pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}),
keyPEM: pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privKey)}),
certDER: certDER,
}
}
// createTestPKCS12 creates a temporary PKCS#12 keystore
func createTestPKCS12(t *testing.T, certPEM, keyPEM []byte) string {
t.Helper()
// Decode certificate
block, _ := pem.Decode(certPEM)
require.NotNil(t, block, "failed to parse certificate PEM")
cert, err := x509.ParseCertificate(block.Bytes)
require.NoError(t, err)
// Decode private key
block, _ = pem.Decode(keyPEM)
require.NotNil(t, block, "failed to parse private key PEM")
privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
require.NoError(t, err)
// Encode PKCS#12 keystore
pfxData, err := pkcs12.Modern.Encode(privKey, cert, nil, "test-password")
require.NoError(t, err)
// Use `t.TempDir()` to ensure cleanup
tempDir := t.TempDir()
pkcs12Path := filepath.Join(tempDir, "test-keystore.p12")
err = os.WriteFile(pkcs12Path, pfxData, 0600)
require.NoError(t, err)
pkcs12Path = filepath.ToSlash(pkcs12Path)
if !strings.HasPrefix(pkcs12Path, "/") {
pkcs12Path = "/" + pkcs12Path
}
return "pkcs12://" + pkcs12Path
}
// createTestJKS creates a temporary JKS keystore
func createTestJKS(t *testing.T, certDER []byte) string {
t.Helper()
// Use `t.TempDir()` to ensure cleanup
tempDir := t.TempDir()
jksPath := filepath.Join(tempDir, "test-keystore.jks")
// Create JKS keystore and add a trusted certificate
jks := keystore.New()
err := jks.SetTrustedCertificateEntry("test-alias", keystore.TrustedCertificateEntry{
Certificate: keystore.Certificate{
Type: "X.509",
Content: certDER,
},
})
require.NoError(t, err)
// Write keystore to file
output, err := os.Create(jksPath)
require.NoError(t, err)
defer output.Close()
require.NoError(t, jks.Store(output, []byte("test-password")))
jksPath = filepath.ToSlash(jksPath)
if !strings.HasPrefix(jksPath, "/") {
jksPath = "/" + jksPath
}
return "jks://" + jksPath
}
func TestGatherKeystores(t *testing.T) {
pkcs12Path, jksPath := generateTestKeystores(t)
tests := []struct {
name string
content string
password string
}{
{name: "valid PKCS12 keystore", content: pkcs12Path, password: "test-password"},
{name: "valid JKS keystore", content: jksPath, password: "test-password"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
plugin := X509Cert{
Sources: []string{test.content},
Password: config.NewSecret([]byte(test.password)),
Log: testutil.Logger{},
}
require.NoError(t, plugin.Init())
var acc testutil.Accumulator
require.NoError(t, plugin.Gather(&acc))
})
}
}
func TestGatherKeystoresFail(t *testing.T) {
pkcs12Path, jksPath := generateTestKeystores(t)
tests := []struct {
name string
content string
password string
expected string
}{
{name: "missing password PKCS12", content: pkcs12Path, expected: "decryption password incorrect"},
{name: "missing password JKS", content: jksPath, expected: "got invalid digest"},
{name: "wrong password PKCS12", content: pkcs12Path, password: "wrong-password", expected: "decryption password incorrect"},
{name: "wrong password JKS", content: jksPath, password: "wrong-password", expected: "got invalid digest"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
plugin := X509Cert{
Sources: []string{test.content},
Log: testutil.Logger{},
}
if test.password != "" {
plugin.Password = config.NewSecret([]byte(test.password))
} else {
plugin.Password = config.NewSecret(nil)
}
require.NoError(t, plugin.Init())
var acc testutil.Accumulator
require.NoError(t, plugin.Gather(&acc))
require.NotEmpty(t, acc.Errors)
require.ErrorContains(t, acc.Errors[0], test.expected)
})
}
}