683 lines
19 KiB
Go
683 lines
19 KiB
Go
|
package x509_cert
|
||
|
|
||
|
import (
|
||
|
"crypto/rand"
|
||
|
"crypto/rsa"
|
||
|
"crypto/tls"
|
||
|
"crypto/x509"
|
||
|
"crypto/x509/pkix"
|
||
|
"encoding/base64"
|
||
|
"encoding/pem"
|
||
|
"fmt"
|
||
|
"math/big"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"net/http/httptest"
|
||
|
"net/url"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/google/go-cmp/cmp"
|
||
|
"github.com/pion/dtls/v2"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/influxdata/telegraf"
|
||
|
"github.com/influxdata/telegraf/config"
|
||
|
"github.com/influxdata/telegraf/metric"
|
||
|
common_tls "github.com/influxdata/telegraf/plugins/common/tls"
|
||
|
"github.com/influxdata/telegraf/testutil"
|
||
|
)
|
||
|
|
||
|
var pki = testutil.NewPKI("../../../testutil/pki")
|
||
|
|
||
|
// Make sure X509Cert implements telegraf.Input
|
||
|
var _ telegraf.Input = &X509Cert{}
|
||
|
|
||
|
func TestGatherRemoteIntegration(t *testing.T) {
|
||
|
t.Skip("Skipping network-dependent test due to race condition when test-all")
|
||
|
|
||
|
tmpfile, err := os.CreateTemp(t.TempDir(), "example")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = tmpfile.WriteString(pki.ReadServerCert())
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
server string
|
||
|
timeout time.Duration
|
||
|
close bool
|
||
|
unset bool
|
||
|
noshake bool
|
||
|
error bool
|
||
|
}{
|
||
|
{name: "wrong port", server: ":99999", error: true},
|
||
|
{name: "no server", timeout: 5},
|
||
|
{name: "successful https", server: "https://example.org:443", timeout: 5},
|
||
|
{name: "successful file", server: "file://" + filepath.ToSlash(tmpfile.Name()), timeout: 5},
|
||
|
{name: "unsupported scheme", server: "foo://", timeout: 5, error: true},
|
||
|
{name: "no certificate", timeout: 5, unset: true, error: true},
|
||
|
{name: "closed connection", close: true, error: true},
|
||
|
{name: "no handshake", timeout: 5, noshake: true, error: true},
|
||
|
}
|
||
|
|
||
|
pair, err := tls.X509KeyPair([]byte(pki.ReadServerCert()), []byte(pki.ReadServerKey()))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
cfg := &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
Certificates: []tls.Certificate{pair},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
t.Run(test.name, func(t *testing.T) {
|
||
|
if test.unset {
|
||
|
cfg.Certificates = nil
|
||
|
cfg.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||
|
return nil, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ln, err := tls.Listen("tcp", "127.0.0.1:0", cfg)
|
||
|
require.NoError(t, err)
|
||
|
defer ln.Close()
|
||
|
|
||
|
go func() {
|
||
|
sconn, err := ln.Accept()
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if test.close {
|
||
|
sconn.Close()
|
||
|
}
|
||
|
|
||
|
serverConfig := cfg.Clone()
|
||
|
srv := tls.Server(sconn, serverConfig)
|
||
|
if test.noshake {
|
||
|
srv.Close()
|
||
|
}
|
||
|
|
||
|
if err = srv.Handshake(); err != nil {
|
||
|
t.Error(err)
|
||
|
return
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
if test.server == "" {
|
||
|
test.server = "tcp://" + ln.Addr().String()
|
||
|
}
|
||
|
|
||
|
sc := X509Cert{
|
||
|
Sources: []string{test.server},
|
||
|
Timeout: config.Duration(test.timeout),
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, sc.Init())
|
||
|
|
||
|
sc.InsecureSkipVerify = true
|
||
|
testErr := false
|
||
|
|
||
|
acc := testutil.Accumulator{}
|
||
|
err = sc.Gather(&acc)
|
||
|
if len(acc.Errors) > 0 {
|
||
|
testErr = true
|
||
|
}
|
||
|
|
||
|
if testErr != test.error {
|
||
|
t.Errorf("%s", err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGatherLocal(t *testing.T) {
|
||
|
wrongCert := fmt.Sprintf("-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----\n", base64.StdEncoding.EncodeToString([]byte("test")))
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
mode os.FileMode
|
||
|
content string
|
||
|
error bool
|
||
|
}{
|
||
|
{name: "permission denied", mode: 0001, error: true},
|
||
|
{name: "not a certificate", mode: 0640, content: "test", error: true},
|
||
|
{name: "wrong certificate", mode: 0640, content: wrongCert, error: true},
|
||
|
{name: "correct certificate", mode: 0640, content: pki.ReadServerCert()},
|
||
|
{name: "correct client certificate", mode: 0640, content: pki.ReadClientCert()},
|
||
|
{name: "correct certificate and extra trailing space", mode: 0640, content: pki.ReadServerCert() + " "},
|
||
|
{name: "correct certificate and extra leading space", mode: 0640, content: " " + pki.ReadServerCert()},
|
||
|
{name: "correct multiple certificates", mode: 0640, content: pki.ReadServerCert() + pki.ReadCACert()},
|
||
|
{name: "correct multiple certificates and key", mode: 0640, content: pki.ReadServerCert() + pki.ReadCACert() + pki.ReadServerKey()},
|
||
|
{name: "correct certificate and wrong certificate", mode: 0640, content: pki.ReadServerCert() + "\n" + wrongCert, error: true},
|
||
|
{name: "correct certificate and not a certificate", mode: 0640, content: pki.ReadServerCert() + "\ntest", error: true},
|
||
|
{name: "correct multiple certificates and extra trailing space", mode: 0640, content: pki.ReadServerCert() + pki.ReadServerCert() + " "},
|
||
|
{name: "correct multiple certificates and extra leading space", mode: 0640, content: " " + pki.ReadServerCert() + pki.ReadServerCert()},
|
||
|
{name: "correct multiple certificates and extra middle space", mode: 0640, content: pki.ReadServerCert() + " " + pki.ReadServerCert()},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
t.Run(test.name, func(t *testing.T) {
|
||
|
f, err := os.CreateTemp(t.TempDir(), "x509_cert")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = f.WriteString(test.content)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
if runtime.GOOS != "windows" {
|
||
|
require.NoError(t, f.Chmod(test.mode))
|
||
|
}
|
||
|
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
sc := X509Cert{
|
||
|
Sources: []string{f.Name()},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, sc.Init())
|
||
|
|
||
|
acc := testutil.Accumulator{}
|
||
|
err = sc.Gather(&acc)
|
||
|
|
||
|
if (len(acc.Errors) > 0) != test.error {
|
||
|
t.Errorf("%s", err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTags(t *testing.T) {
|
||
|
cert := fmt.Sprintf("%s\n%s", pki.ReadServerCert(), pki.ReadCACert())
|
||
|
|
||
|
f, err := os.CreateTemp(t.TempDir(), "x509_cert")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = f.WriteString(cert)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
defer os.Remove(f.Name())
|
||
|
|
||
|
sc := X509Cert{
|
||
|
Sources: []string{f.Name()},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, sc.Init())
|
||
|
|
||
|
acc := testutil.Accumulator{}
|
||
|
require.NoError(t, sc.Gather(&acc))
|
||
|
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "common_name"))
|
||
|
require.Equal(t, "localhost", acc.TagValue("x509_cert", "common_name"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "signature_algorithm"))
|
||
|
require.Equal(t, "SHA256-RSA", acc.TagValue("x509_cert", "signature_algorithm"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "public_key_algorithm"))
|
||
|
require.Equal(t, "RSA", acc.TagValue("x509_cert", "public_key_algorithm"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "issuer_common_name"))
|
||
|
require.Equal(t, "Telegraf Test CA", acc.TagValue("x509_cert", "issuer_common_name"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "san"))
|
||
|
require.Equal(t, "localhost,127.0.0.1", acc.TagValue("x509_cert", "san"))
|
||
|
|
||
|
require.True(t, acc.HasTag("x509_cert", "serial_number"))
|
||
|
serialNumber := new(big.Int)
|
||
|
_, validSerialNumber := serialNumber.SetString(acc.TagValue("x509_cert", "serial_number"), 16)
|
||
|
require.Truef(t, validSerialNumber, "Expected a valid Hex serial number but got %s", acc.TagValue("x509_cert", "serial_number"))
|
||
|
require.Equal(t, big.NewInt(1), serialNumber)
|
||
|
|
||
|
// expect root/intermediate certs (more than one cert)
|
||
|
require.Greater(t, acc.NMetrics(), uint64(1))
|
||
|
}
|
||
|
|
||
|
func TestGatherExcludeRootCerts(t *testing.T) {
|
||
|
cert := fmt.Sprintf("%s\n%s", pki.ReadServerCert(), pki.ReadCACert())
|
||
|
|
||
|
f, err := os.CreateTemp(t.TempDir(), "x509_cert")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = f.WriteString(cert)
|
||
|
require.NoError(t, err)
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
sc := X509Cert{
|
||
|
Sources: []string{f.Name()},
|
||
|
ExcludeRootCerts: true,
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, sc.Init())
|
||
|
|
||
|
acc := testutil.Accumulator{}
|
||
|
require.NoError(t, sc.Gather(&acc))
|
||
|
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
require.Equal(t, uint64(1), acc.NMetrics())
|
||
|
}
|
||
|
|
||
|
func TestGatherChain(t *testing.T) {
|
||
|
cert := fmt.Sprintf("%s\n%s", pki.ReadServerCert(), pki.ReadCACert())
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
content string
|
||
|
error bool
|
||
|
}{
|
||
|
{name: "chain certificate", content: cert},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
t.Run(test.name, func(t *testing.T) {
|
||
|
f, err := os.CreateTemp(t.TempDir(), "x509_cert")
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = f.WriteString(test.content)
|
||
|
require.NoError(t, err)
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
sc := X509Cert{
|
||
|
Sources: []string{f.Name()},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, sc.Init())
|
||
|
|
||
|
acc := testutil.Accumulator{}
|
||
|
err = sc.Gather(&acc)
|
||
|
if (err != nil) != test.error {
|
||
|
t.Errorf("%s", err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGatherUDPCertIntegration(t *testing.T) {
|
||
|
if testing.Short() {
|
||
|
t.Skip("Skipping integration test in short mode")
|
||
|
}
|
||
|
pair, err := tls.X509KeyPair([]byte(pki.ReadServerCert()), []byte(pki.ReadServerKey()))
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
cfg := &dtls.Config{
|
||
|
Certificates: []tls.Certificate{pair},
|
||
|
}
|
||
|
|
||
|
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0}
|
||
|
listener, err := dtls.Listen("udp", addr, cfg)
|
||
|
require.NoError(t, err)
|
||
|
defer listener.Close()
|
||
|
|
||
|
go func() {
|
||
|
if _, err := listener.Accept(); err != nil {
|
||
|
t.Error(err)
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
m := &X509Cert{
|
||
|
Sources: []string{"udp://" + listener.Addr().String()},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, m.Init())
|
||
|
|
||
|
var acc testutil.Accumulator
|
||
|
require.NoError(t, m.Gather(&acc))
|
||
|
|
||
|
require.Empty(t, acc.Errors)
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
require.True(t, acc.HasTag("x509_cert", "ocsp_stapled"))
|
||
|
}
|
||
|
|
||
|
func TestGatherTCPCert(t *testing.T) {
|
||
|
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||
|
w.WriteHeader(http.StatusOK)
|
||
|
}))
|
||
|
defer ts.Close()
|
||
|
|
||
|
m := &X509Cert{
|
||
|
Sources: []string{ts.URL},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, m.Init())
|
||
|
|
||
|
var acc testutil.Accumulator
|
||
|
require.NoError(t, m.Gather(&acc))
|
||
|
|
||
|
require.Empty(t, acc.Errors)
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
}
|
||
|
|
||
|
func TestGatherCertIntegration(t *testing.T) {
|
||
|
if testing.Short() {
|
||
|
t.Skip("Skipping integration test in short mode")
|
||
|
}
|
||
|
|
||
|
m := &X509Cert{
|
||
|
Sources: []string{"https://www.influxdata.com:443"},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, m.Init())
|
||
|
|
||
|
var acc testutil.Accumulator
|
||
|
require.NoError(t, m.Gather(&acc))
|
||
|
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
require.True(t, acc.HasTag("x509_cert", "ocsp_stapled"))
|
||
|
}
|
||
|
|
||
|
func TestGatherCertMustNotTimeoutIntegration(t *testing.T) {
|
||
|
if testing.Short() {
|
||
|
t.Skip("Skipping integration test in short mode")
|
||
|
}
|
||
|
duration := time.Duration(15) * time.Second
|
||
|
m := &X509Cert{
|
||
|
Sources: []string{"https://www.influxdata.com:443"},
|
||
|
Timeout: config.Duration(duration),
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, m.Init())
|
||
|
|
||
|
var acc testutil.Accumulator
|
||
|
require.NoError(t, m.Gather(&acc))
|
||
|
require.Empty(t, acc.Errors)
|
||
|
require.True(t, acc.HasMeasurement("x509_cert"))
|
||
|
require.True(t, acc.HasTag("x509_cert", "ocsp_stapled"))
|
||
|
}
|
||
|
|
||
|
func TestSourcesToURLs(t *testing.T) {
|
||
|
m := &X509Cert{
|
||
|
Sources: []string{
|
||
|
"https://www.influxdata.com:443",
|
||
|
"tcp://influxdata.com:443",
|
||
|
"smtp://influxdata.com:25",
|
||
|
"file:///dummy_test_path_file.pem",
|
||
|
"file:///windows/temp/test.pem",
|
||
|
`file://C:\windows\temp\test.pem`,
|
||
|
`file:///C:/windows/temp/test.pem`,
|
||
|
"/tmp/dummy_test_path_glob*.pem",
|
||
|
},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, m.Init())
|
||
|
|
||
|
expected := []string{
|
||
|
"https://www.influxdata.com:443",
|
||
|
"tcp://influxdata.com:443",
|
||
|
"smtp://influxdata.com:25",
|
||
|
}
|
||
|
|
||
|
expectedPaths := []string{
|
||
|
"/dummy_test_path_file.pem",
|
||
|
"/windows/temp/test.pem",
|
||
|
"C:\\windows\\temp\\test.pem",
|
||
|
"C:/windows/temp/test.pem",
|
||
|
}
|
||
|
|
||
|
for _, p := range expectedPaths {
|
||
|
expected = append(expected, filepath.FromSlash(p))
|
||
|
}
|
||
|
|
||
|
actual := make([]string, 0, len(m.globpaths)+len(m.locations))
|
||
|
for _, p := range m.globpaths {
|
||
|
actual = append(actual, p.GetRoots()...)
|
||
|
}
|
||
|
for _, p := range m.locations {
|
||
|
actual = append(actual, p.String())
|
||
|
}
|
||
|
require.Len(t, m.globpaths, 5)
|
||
|
require.Len(t, m.locations, 3)
|
||
|
require.ElementsMatch(t, expected, actual)
|
||
|
}
|
||
|
|
||
|
func TestServerName(t *testing.T) {
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
fromTLS string
|
||
|
fromCfg string
|
||
|
url string
|
||
|
expected string
|
||
|
err bool
|
||
|
}{
|
||
|
{name: "in cfg", fromCfg: "example.com", url: "https://other.example.com", expected: "example.com"},
|
||
|
{name: "in tls", fromTLS: "example.com", url: "https://other.example.com", expected: "example.com"},
|
||
|
{name: "from URL", url: "https://other.example.com", expected: "other.example.com"},
|
||
|
{name: "errors", fromCfg: "otherex.com", fromTLS: "example.com", url: "https://other.example.com", err: true},
|
||
|
}
|
||
|
|
||
|
for _, test := range tests {
|
||
|
t.Run(test.name, func(t *testing.T) {
|
||
|
sc := &X509Cert{
|
||
|
Sources: []string{test.url},
|
||
|
ServerName: test.fromCfg,
|
||
|
ClientConfig: common_tls.ClientConfig{ServerName: test.fromTLS},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
err := sc.Init()
|
||
|
if test.err {
|
||
|
require.Error(t, err)
|
||
|
return
|
||
|
}
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
u, err := url.Parse(test.url)
|
||
|
require.NoError(t, err)
|
||
|
require.Equal(t, test.expected, sc.serverName(u))
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestCertificateSerialNumberRetainsLeadingZeroes(t *testing.T) {
|
||
|
bi := &big.Int{}
|
||
|
bi.SetString("123456789abcdef", 16)
|
||
|
|
||
|
plugin := &X509Cert{}
|
||
|
certificate := &x509.Certificate{
|
||
|
SerialNumber: bi,
|
||
|
}
|
||
|
|
||
|
require.Equal(t, "123456789abcdef", plugin.getSerialNumberString(certificate))
|
||
|
plugin.PadSerial = true
|
||
|
require.Equal(t, "0123456789abcdef", plugin.getSerialNumberString(certificate))
|
||
|
}
|
||
|
|
||
|
// Bases on code from
|
||
|
// https://medium.com/@shaneutt/create-sign-x509-certificates-in-golang-8ac4ae49f903
|
||
|
func TestClassification(t *testing.T) {
|
||
|
start := time.Now()
|
||
|
end := time.Now().AddDate(0, 0, 1)
|
||
|
tmpDir := t.TempDir()
|
||
|
|
||
|
// Create the CA certificate
|
||
|
caPriv, err := rsa.GenerateKey(rand.Reader, 4096)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
ca := &x509.Certificate{
|
||
|
SerialNumber: big.NewInt(342350),
|
||
|
Subject: pkix.Name{
|
||
|
Organization: []string{"Testing Inc."},
|
||
|
Country: []string{"US"},
|
||
|
CommonName: "Root CA",
|
||
|
},
|
||
|
NotBefore: start,
|
||
|
NotAfter: end,
|
||
|
IsCA: true,
|
||
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||
|
BasicConstraintsValid: true,
|
||
|
}
|
||
|
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPriv.PublicKey, caPriv)
|
||
|
require.NoError(t, err)
|
||
|
caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caBytes})
|
||
|
|
||
|
// Write CA cert
|
||
|
f, err := os.Create(filepath.Join(tmpDir, "ca.pem"))
|
||
|
require.NoError(t, err)
|
||
|
_, err = f.Write(caPEM)
|
||
|
require.NoError(t, err)
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
// Create an intermediate certificate
|
||
|
intermediatePriv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
intermediate := &x509.Certificate{
|
||
|
SerialNumber: big.NewInt(342351),
|
||
|
Subject: pkix.Name{
|
||
|
Organization: []string{"Testing Inc."},
|
||
|
Country: []string{"US"},
|
||
|
CommonName: "Intermediate CA",
|
||
|
},
|
||
|
NotBefore: start,
|
||
|
NotAfter: end,
|
||
|
IsCA: true,
|
||
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||
|
BasicConstraintsValid: true,
|
||
|
}
|
||
|
intermediateBytes, err := x509.CreateCertificate(rand.Reader, intermediate, ca, &intermediatePriv.PublicKey, caPriv)
|
||
|
require.NoError(t, err)
|
||
|
intermediatePEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: intermediateBytes})
|
||
|
|
||
|
// Create a leaf certificate
|
||
|
leafPriv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
leaf := &x509.Certificate{
|
||
|
SerialNumber: big.NewInt(342352),
|
||
|
Subject: pkix.Name{
|
||
|
Organization: []string{"Testing Inc."},
|
||
|
Country: []string{"US"},
|
||
|
CommonName: "My server",
|
||
|
},
|
||
|
NotBefore: start,
|
||
|
NotAfter: end,
|
||
|
IsCA: false,
|
||
|
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||
|
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
||
|
}
|
||
|
leafBytes, err := x509.CreateCertificate(rand.Reader, leaf, intermediate, &leafPriv.PublicKey, intermediatePriv)
|
||
|
require.NoError(t, err)
|
||
|
leafPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafBytes})
|
||
|
|
||
|
// Write the chain
|
||
|
out := append(leafPEM, intermediatePEM...)
|
||
|
out = append(out, caPEM...)
|
||
|
f, err = os.Create(filepath.Join(tmpDir, "cert.pem"))
|
||
|
require.NoError(t, err)
|
||
|
_, err = f.Write(out)
|
||
|
require.NoError(t, err)
|
||
|
require.NoError(t, f.Close())
|
||
|
|
||
|
// Create the actual test
|
||
|
certURI := "file://" + filepath.Join(tmpDir, "cert.pem")
|
||
|
plugin := &X509Cert{
|
||
|
Sources: []string{certURI},
|
||
|
ClientConfig: common_tls.ClientConfig{
|
||
|
TLSCA: filepath.Join(tmpDir, "ca.pem"),
|
||
|
},
|
||
|
Log: testutil.Logger{},
|
||
|
}
|
||
|
require.NoError(t, plugin.Init())
|
||
|
|
||
|
var acc testutil.Accumulator
|
||
|
require.NoError(t, plugin.Gather(&acc))
|
||
|
require.Empty(t, acc.Errors)
|
||
|
|
||
|
expected := []telegraf.Metric{
|
||
|
metric.New(
|
||
|
"x509_cert",
|
||
|
map[string]string{
|
||
|
"common_name": "My server",
|
||
|
"country": "US",
|
||
|
"issuer_common_name": "Intermediate CA",
|
||
|
"issuer_serial_number": "",
|
||
|
"ocsp_stapled": "no",
|
||
|
"organization": "Testing Inc.",
|
||
|
"public_key_algorithm": "RSA",
|
||
|
"san": "127.0.0.1",
|
||
|
"serial_number": "53950",
|
||
|
"signature_algorithm": "SHA256-RSA",
|
||
|
"source": filepath.ToSlash(certURI),
|
||
|
"type": "leaf",
|
||
|
"verification": "valid",
|
||
|
},
|
||
|
map[string]interface{}{
|
||
|
"age": int64(0),
|
||
|
"expiry": int64(86399),
|
||
|
"startdate": start.Unix(),
|
||
|
"enddate": end.Unix(),
|
||
|
"verification_code": int64(0),
|
||
|
},
|
||
|
time.Unix(0, 0),
|
||
|
),
|
||
|
metric.New(
|
||
|
"x509_cert",
|
||
|
map[string]string{
|
||
|
"common_name": "Intermediate CA",
|
||
|
"country": "US",
|
||
|
"issuer_common_name": "Root CA",
|
||
|
"issuer_serial_number": "",
|
||
|
"ocsp_stapled": "no",
|
||
|
"organization": "Testing Inc.",
|
||
|
"public_key_algorithm": "RSA",
|
||
|
"san": "",
|
||
|
"serial_number": "5394f",
|
||
|
"signature_algorithm": "SHA256-RSA",
|
||
|
"source": filepath.ToSlash(certURI),
|
||
|
"type": "intermediate",
|
||
|
"verification": "valid",
|
||
|
},
|
||
|
map[string]interface{}{
|
||
|
"age": int64(0),
|
||
|
"expiry": int64(86399),
|
||
|
"startdate": start.Unix(),
|
||
|
"enddate": end.Unix(),
|
||
|
"verification_code": int64(0),
|
||
|
},
|
||
|
time.Unix(0, 0),
|
||
|
),
|
||
|
metric.New(
|
||
|
"x509_cert",
|
||
|
map[string]string{
|
||
|
"common_name": "Root CA",
|
||
|
"country": "US",
|
||
|
"issuer_common_name": "Root CA",
|
||
|
"issuer_serial_number": "",
|
||
|
"ocsp_stapled": "no",
|
||
|
"organization": "Testing Inc.",
|
||
|
"public_key_algorithm": "RSA",
|
||
|
"san": "",
|
||
|
"serial_number": "5394e",
|
||
|
"signature_algorithm": "SHA256-RSA",
|
||
|
"source": filepath.ToSlash(certURI),
|
||
|
"type": "root",
|
||
|
"verification": "valid",
|
||
|
},
|
||
|
map[string]interface{}{
|
||
|
"age": int64(0),
|
||
|
"expiry": int64(86399),
|
||
|
"startdate": start.Unix(),
|
||
|
"enddate": end.Unix(),
|
||
|
"verification_code": int64(0),
|
||
|
},
|
||
|
time.Unix(0, 0),
|
||
|
),
|
||
|
}
|
||
|
|
||
|
opts := []cmp.Option{
|
||
|
testutil.SortMetrics(),
|
||
|
testutil.IgnoreTime(),
|
||
|
// We need to ignore those fields as they are timing sensitive.
|
||
|
testutil.IgnoreFields("age", "expiry"),
|
||
|
}
|
||
|
actual := acc.GetTelegrafMetrics()
|
||
|
testutil.RequireMetricsEqual(t, expected, actual, opts...)
|
||
|
}
|