Skip to content

Commit

Permalink
CA trusted fingerprint tests (#29347) (#29451)
Browse files Browse the repository at this point in the history
This commit adds tests to `trustRootCA` and `makeVerifyConnection`,
the tests aim to cover the usage of `ssl.ca_tursted_fingerprint`.

Some existing tests were refactored, `openTestCerts` receives a `testing.TB`
and fail tests in case of an error

(cherry picked from commit 6c268f8)

Co-authored-by: Tiago Queiroz <tiago.queiroz@elastic.co>
  • Loading branch information
mergify[bot] and belimawr committed Dec 16, 2021
1 parent f15e493 commit 3e564f6
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 12 deletions.
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)
}
})
}
}

0 comments on commit 3e564f6

Please sign in to comment.