Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CA trusted fingerprint tests #29347

Merged
merged 3 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions libbeat/common/transport/tlscommon/testdata/es-leaf.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFeDCCA2CgAwIBAgIUV7+XlHjcV++/ezqTkJrXSFc1dpAwDQYJKoZIhvcNAQEL
BQAwPDE6MDgGA1UEAxMxRWxhc3RpY3NlYXJjaCBzZWN1cml0eSBhdXRvLWNvbmZp
Z3VyYXRpb24gSFRUUCBDQTAeFw0yMTExMzAxMDMzNTdaFw0yMzExMzAxMDMzNTda
MBExDzANBgNVBAMTBngtd2luZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBALL045X6ywAHg9tWuViNyXu30rHhJa/AI45ZwLWzQMEwnCWnMvV0Cy3FgUd6
VKw4Rg55/SfBKShhTRjC4PmDIHDIBgpm4NWpREIW2+cZfeEU8B34ucK/ZHycTFQ1
Guh8HfvFy5J3OYT+8Wfz94ZxvVLMOGROTSiWdL2foVk98tbHgL1K3qyv1v0rgIjt
smZ7G4tbl3sBCuYceUL7X/+0kavJGls2T/rtxxEIfj5dNz4h65KmABrrAJfrEx35
y2jCdY2XQsBxxMvbHEXXJKhrjQ8pajMcWAlDBKweiNIDdgBDYWpodpr4f3A6ZJkM
Nplw7KyLna4s3BO/g7fd5/FyQGFuLPraFtFnTXGqH+LjX0td74bdSP22/uhU3cKY
3y64I3/HEaEY5JITgUArExcMVpXuKJKqXEb+LtjGmUbAiO8Z7QKL+PqmU+3tJJ0p
kXnS07m3F/MgrDir/VCnYGQcXeteBwEgmcOwPmxz98eOSBhtb0PrimycF2tQuT8b
mCU+evTPC+KQ+8XY5vBwdPGpf6YAaHuVhNtKqBQnYOpsadS7zw5DJ0Y1Kp9z0ZPL
ch4DxE40xqAFmxWnAfpy2scD8LGJ1zDII90tAtYdu+3Wlzj6uMqUdqPuJED7XD41
mlF2OjB5ipTs/1Jjl3pEnGG94sw5bQmnS1xFQp/DO3mjlgFBAgMBAAGjgZwwgZkw
HQYDVR0OBBYEFJKNxskBHE5xQ9S24puXSKm6/bLKMB8GA1UdIwQYMBaAFHEdsBBS
VCiK0fDIVe2vNN8JvHmcMEwGA1UdEQRFMEOHEP6AAAAAAAAAtw+3JU5DX8mCCWxv
Y2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAAYcEwKgqtoIGeC13aW5nMAkG
A1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAF5JAIQ9cu2xroh2F85fBr/F0s8D
aRV6AJpkjSVKInMm7omn+GLB80TwQZ6NsGuXrbaq0rcM85khsBs4rWn5MqescYG/
8A7gZ4EtYE3LIyeqiqBByrtIqszZeXm7ITDSF/lwn7X2swe7orkhVD4tVEvKH6L6
Ql0oNe5UBN1Rm9NskDltMDzE2A25slkm99CAdPERDEjBpvd3eDcfbQdHeuAOPfUV
T8P2DAdW4SC955bxnc0GPTla5TKXWWLde3egow5a4LeJv6KVWPTC9chEXZyQKp4p
jvWZW1fTO/kC3oj97tfqoH/r35/+qyXmg38HNAFbEoVM3bsO0vqrI5CbkWTkB1Xb
7CY6jJxemyEprl2gmkgfA/MXBHFc3RoIL7JcX7Sk8ZWpnEVK3KyoyK1RJ5kY1Cz4
SRw4KLJA4Cu6DE7vXy9pTlIeeQARgQOUxnrlRGYHpKRIwgjrhwEjVqc0CPwj7rWr
0VY4MW80FPFIePpqy3DjoJmORQU632iu/5zeUS4dZ11Ms7NTakqqnFHi7XczqeZn
4HqPW8ebQTXrqRXMF/X30x6gkK1R1tXHSbve7cTQWJEwJd+MS2aA5Npt7hGznjPn
Y1p4k9jEz5BnbLtZ2RbAj2FuL4Ee6iJoyZpFbi/SW+h+1ZaPCeUTnxUkDLEiXpdk
tN8H6/6dudhy6btm
-----END CERTIFICATE-----
31 changes: 31 additions & 0 deletions libbeat/common/transport/tlscommon/testdata/es-root-ca-cert.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIUAoPlJ3hVr921EyJfiT+9lVft3fcwDQYJKoZIhvcNAQEL
BQAwPDE6MDgGA1UEAxMxRWxhc3RpY3NlYXJjaCBzZWN1cml0eSBhdXRvLWNvbmZp
Z3VyYXRpb24gSFRUUCBDQTAeFw0yMTExMzAxMDMzNTdaFw0yNDExMjkxMDMzNTda
MDwxOjA4BgNVBAMTMUVsYXN0aWNzZWFyY2ggc2VjdXJpdHkgYXV0by1jb25maWd1
cmF0aW9uIEhUVFAgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2
soq+heCJNHsMuyyyLndREhYmxYFav06XOLB5oC1bAt+0WMo3n7rxVB8dAhfvigof
DsTIytnCcK+Th8ll2k4Bs2weF16ZhvvC2FKbSkdUxNXnXfx7gdKDXZLbfref5FiL
ucwxa7CtVL28Lfws9J5dZTTAuxR2XxaX+TJbH6MbQgKUYR+DnK8T3jSfiDTQtiHs
+pd+C8hSdMgzKCynYP36VZbtz1ynWjvQ/0wxARO6q2OLZGBNh2ncoFEmosXgc0ir
Vh9NrVmozSI0H2f6W07imqL3oe1pe3bwW/OdfeahCBY3IvDLDn8q8wDl91gRta3n
EsMsiuBRSRRpT0grgoCFNy+wiIrETVLaI2HJ0UpVIpcoS7K5l2zN/wA+w+hAOdh0
PoBt8AoC1aCCGM4osCTKqbgbOg957io2twuvWJ6ae3J2k5FFDMvIfMfL+5HhPSRp
nYiRDPOhapDhaXhHa4pEFONpdiJJgmqymLqjW4liZOGft28dSkISK3iiBL74p/gu
X/sBI7PZANycpyVjnLHK+FwPlRZPkrqCw2Gke4Oqm9uydwM08uRVZcNylVS7H0ip
9BEcxKlXJSaULnTqQXkiPGKGkCrrIIsNQTFjoaBIBP2o69NSZ0SozDf4aCnYy10v
U1dwI9yisOmMfDkakNcAPXfRfmuuJlstl1W1RraQswIDAQABo1MwUTAdBgNVHQ4E
FgQUcR2wEFJUKIrR8MhV7a803wm8eZwwHwYDVR0jBBgwFoAUcR2wEFJUKIrR8MhV
7a803wm8eZwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAiHrC
NxCNsyUYLFVivL9AsJ5Y3IrhAHUzYwofLBJiMYNFsaEi3P1VU3TNlo98kzi2QkdY
NPFtRYoOg6sEI0KPEBw54kLP/Q/FJK7jeJSyhJ9V/Z+NS081YHqrMP4YPK6mM4qa
XuM7hpx37vkLDdfrDPionbcLk7Zz+2t6bIThrwta0idMY6LKeFfW1EWeggK6inNc
Ub3n1qcTyOp1RfcLlHCdb17JhgY5hROmqVfhgLlbT0bx1NZS4pRWhw5CDKsflMUe
SyHbLE1BTH6yE0nNXbR6FgDKjQNUSSZBOBck0hdSaRArALavujjBojHmJYWt1jWO
bcBErzwKKwH/peUh7Wgnq1L/lqym9K9AniWUyhvKn8AbxGLnILDMYOSrvlPF2uU+
uvp2EzhPUyOgYycC28H4fFUdDeoN5FVP+4sFFK+FIgfqLfVMTgDPmGAbkqA6WKlH
fgQ2fP4oB2ZkN0EPxivXkvZkhDVlIXeoisUkNCgAfVuwCjvOLnqz8u0tTnp/wXxq
XAXUPLcG71YFzABlkwuPdA5GhFAL1Rv8GQJEznhZ8mYz/yTtcg/z3pYEhDcM92Cb
161BormFYVRI1B80rSpzeQwJVfvgCwnWOTat+1joFHCzpl99nHu8tMxi6lkO1G9E
8vdk/J0zMMnhO52V2EMNdH2fTJUMZYixBm4BeEM=
-----END CERTIFICATE-----
196 changes: 184 additions & 12 deletions libbeat/common/transport/tlscommon/tls_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMakeVerifyServerConnection(t *testing.T) {
testCerts, err := openTestCerts()
if err != nil {
t.Fatalf("failed to open test certs: %+v", err)
}
testCerts := openTestCerts(t)

testCA, errs := LoadCertificateAuthorities([]string{
filepath.Join("testdata", "ca.crt"),
Expand Down Expand Up @@ -159,7 +157,6 @@ func TestMakeVerifyServerConnection(t *testing.T) {

for name, test := range testcases {
t.Run(name, func(t *testing.T) {
test := test
cfg := &TLSConfig{
Verification: test.verificationMode,
ClientAuth: test.clientAuth,
Expand All @@ -177,36 +174,211 @@ func TestMakeVerifyServerConnection(t *testing.T) {
ServerName: test.serverName,
})
if test.expectedError == nil {
assert.Nil(t, err)
assert.NoError(t, err)
} else {
assert.Error(t, test.expectedError, err)
require.Error(t, err)
// We want to ensure the error type/message are the expected ones
// so we compare the types and the message
assert.IsType(t, test.expectedError, err)
assert.Contains(t, err.Error(), test.expectedError.Error())
}
})
}

}

func openTestCerts() (map[string]*x509.Certificate, error) {
func openTestCerts(t testing.TB) map[string]*x509.Certificate {
t.Helper()
certs := make(map[string]*x509.Certificate, 0)

for testcase, certname := range map[string]string{
"expired": "tls.crt",
"unknown authority": "unsigned_tls.crt",
"correct": "client1.crt",
"wildcard": "server.crt",
"es-leaf": "es-leaf.crt",
"es-root-ca": "es-root-ca-cert.crt",
} {

certBytes, err := ioutil.ReadFile(filepath.Join("testdata", certname))
if err != nil {
return nil, err
t.Fatalf("reading file %q: %+v", certname, err)
}
block, _ := pem.Decode(certBytes)
testCert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
t.Fatalf("parsing certificate %q: %+v", certname, err)
}
certs[testcase] = testCert
}

return certs, nil
return certs
}

func TestTrustRootCA(t *testing.T) {
certs := openTestCerts(t)

nonEmptyCertPool := x509.NewCertPool()
nonEmptyCertPool.AddCert(certs["wildcard"])
nonEmptyCertPool.AddCert(certs["unknown authority"])

testCases := []struct {
name string
rootCAs *x509.CertPool
caTrustedFingerprint string
peerCerts []*x509.Certificate
expectingError bool
expectedRootCAsLen int
}{
{
name: "RootCA cert matches the fingerprint and is added to cfg.RootCAs",
caTrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
peerCerts: []*x509.Certificate{certs["es-leaf"], certs["es-root-ca"]},
expectedRootCAsLen: 1,
},
{
name: "RootCA cert doesn not matche the fingerprint and is not added to cfg.RootCAs",
caTrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
peerCerts: []*x509.Certificate{certs["es-leaf"], certs["es-root-ca"]},
expectedRootCAsLen: 0,
},
{
name: "non empty CertPool has the RootCA added",
rootCAs: nonEmptyCertPool,
caTrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
peerCerts: []*x509.Certificate{certs["es-leaf"], certs["es-root-ca"]},
expectedRootCAsLen: 3,
},
{
name: "invalis HEX encoding",
caTrustedFingerprint: "INVALID ENCODING",
expectedRootCAsLen: 0,
expectingError: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cfg := TLSConfig{
RootCAs: tc.rootCAs,
CATrustedFingerprint: tc.caTrustedFingerprint,
}
err := trustRootCA(&cfg, tc.peerCerts)
if tc.expectingError && err == nil {
t.Fatal("expecting an error when calling trustRootCA")
}

if !tc.expectingError && err != nil {
t.Fatalf("did not expect an error calling trustRootCA: %v", err)
}

if tc.expectedRootCAsLen != 0 {
if cfg.RootCAs == nil {
t.Fatal("cfg.RootCAs cannot be nil")
}

// we want to know the number of certificates in the CertPool (RootCAs), as it is not
// directly available, we use this workaround of reading the number of subjects in the pool.
if got, expected := len(cfg.RootCAs.Subjects()), tc.expectedRootCAsLen; got != expected {
t.Fatalf("expecting cfg.RootCAs to have %d element, got %d instead", expected, got)
}
}
})
}
}

func TestMakeVerifyConnectionUsesCATrustedFingerprint(t *testing.T) {
testCerts := openTestCerts(t)

testcases := map[string]struct {
verificationMode TLSVerificationMode
peerCerts []*x509.Certificate
serverName string
expectedCallback bool
expectingError bool
CATrustedFingerprint string
CASHA256 []string
}{
"CATrustedFingerprint and verification mode:VerifyFull": {
verificationMode: VerifyFull,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
},
"CATrustedFingerprint and verification mode:VerifyCertificate": {
verificationMode: VerifyCertificate,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
},
"CATrustedFingerprint and verification mode:VerifyStrict": {
verificationMode: VerifyStrict,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "e83171aa133b2b507e057fe091e296a7e58e9653c2b88d203b64a47eef6ec62b",
CASHA256: []string{Fingerprint(testCerts["es-leaf"])},
},
"CATrustedFingerprint and verification mode:VerifyNone": {
verificationMode: VerifyNone,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: false,
},
"invalid CATrustedFingerprint and verification mode:VerifyFull returns error": {
verificationMode: VerifyFull,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "INVALID HEX ENCODING",
expectingError: true,
},
"invalid CATrustedFingerprint and verification mode:VerifyCertificate returns error": {
verificationMode: VerifyCertificate,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "INVALID HEX ENCODING",
expectingError: true,
},
"invalid CATrustedFingerprint and verification mode:VerifyStrict returns error": {
verificationMode: VerifyStrict,
peerCerts: []*x509.Certificate{testCerts["es-leaf"], testCerts["es-root-ca"]},
serverName: "localhost",
expectedCallback: true,
CATrustedFingerprint: "INVALID HEX ENCODING",
expectingError: true,
CASHA256: []string{Fingerprint(testCerts["es-leaf"])},
},
}

for name, test := range testcases {
t.Run(name, func(t *testing.T) {
cfg := &TLSConfig{
Verification: test.verificationMode,
CATrustedFingerprint: test.CATrustedFingerprint,
CASha256: test.CASHA256,
}

verifier := makeVerifyConnection(cfg)
if test.expectedCallback {
require.NotNil(t, verifier, "makeVerifyConnection returned a nil verifier")
} else {
require.Nil(t, verifier)
return
}

err := verifier(tls.ConnectionState{
PeerCertificates: test.peerCerts,
ServerName: test.serverName,
VerifiedChains: [][]*x509.Certificate{test.peerCerts},
})
if test.expectingError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}