cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2018.10.5

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tlsconfig/tlsconfig_test.go

214lines · modecode

1// +build ignore
2// TODO: Remove the above build tag and include this test when we start compiling with Golang 1.10.0+
3
4package tlsconfig
5
6import (
7 "crypto/x509"
8 "crypto/x509/pkix"
9 "encoding/asn1"
10 "os"
11 "testing"
12
13 "github.com/stretchr/testify/assert"
14)
15
16// Generated using `openssl req -newkey rsa:512 -nodes -x509 -days 3650`
17var samplePEM = []byte(`
18-----BEGIN CERTIFICATE-----
19MIIB4DCCAYoCCQCb/H0EUrdXEjANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV
20UzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkF1c3RpbjEZMBcGA1UECgwQQ2xv
21dWRmbGFyZSwgSW5jLjEZMBcGA1UECwwQUHJvZHVjdCBTdHJhdGVneTERMA8GA1UE
22AwwIVGVzdCBPbmUwHhcNMTgwNDI2MTYxMDUxWhcNMjgwNDIzMTYxMDUxWjB3MQsw
23CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkF1c3RpbjEZMBcG
24A1UECgwQQ2xvdWRmbGFyZSwgSW5jLjEZMBcGA1UECwwQUHJvZHVjdCBTdHJhdGVn
25eTERMA8GA1UEAwwIVGVzdCBPbmUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAwVQD
26K0SJ25UFLznm2pU3zhzMEvpDEofHVNnCjk4mlDrtVop7PkKZ8pDEmuQANltUrxC8
27yHBE2wXMv+GlH+bDtwIDAQABMA0GCSqGSIb3DQEBCwUAA0EAjVYQzozIFPkt/HRY
28uUoZ8zEHIDICb0syFf5VAjm9AgTwIPzUmD+c5vl6LWDnxq7L45nLCzhhQ6YmiwDz
29X7Wcyg==
30-----END CERTIFICATE-----
31-----BEGIN CERTIFICATE-----
32MIIB4DCCAYoCCQDZfCdAJ+mwzDANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV
33UzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkF1c3RpbjEZMBcGA1UECgwQQ2xv
34dWRmbGFyZSwgSW5jLjEZMBcGA1UECwwQUHJvZHVjdCBTdHJhdGVneTERMA8GA1UE
35AwwIVGVzdCBUd28wHhcNMTgwNDI2MTYxMTIwWhcNMjgwNDIzMTYxMTIwWjB3MQsw
36CQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxDzANBgNVBAcMBkF1c3RpbjEZMBcG
37A1UECgwQQ2xvdWRmbGFyZSwgSW5jLjEZMBcGA1UECwwQUHJvZHVjdCBTdHJhdGVn
38eTERMA8GA1UEAwwIVGVzdCBUd28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAoHKp
39ROVK3zCSsH7ocYeyRAML4V7SFAbZcb4WIwDnE08oMBVRkQVcW5tqEkvG3RiClfzV
40wZIJ3CfqKIeSNSDU9wIDAQABMA0GCSqGSIb3DQEBCwUAA0EAJw2gUbnPiq4C2p5b
41iWzlA9Q7aKo+VQ4H7IZS7tTccr59nVjvH/TG3eWujpnocr4TOqW9M3CK1DF9mUGP
423pQ3Jg==
43-----END CERTIFICATE-----
44`)
45
46var systemCertPoolSubjects []*pkix.Name
47
48type certificateFixture struct {
49 ou string
50 cn string
51}
52
53func TestMain(m *testing.M) {
54 systemCertPool, err := x509.SystemCertPool()
55 if isUnrecoverableError(err) {
56 os.Exit(1)
57 }
58
59 if systemCertPool == nil {
60 // On Windows, let's just assume the system cert pool was empty
61 systemCertPool = x509.NewCertPool()
62 }
63
64 systemCertPoolSubjects, err = getCertPoolSubjects(systemCertPool)
65 if err != nil {
66 os.Exit(1)
67 }
68
69 os.Exit(m.Run())
70}
71
72func TestLoadOriginCertPoolJustSystemPool(t *testing.T) {
73 certPoolSubjects := loadCertPoolSubjects(t, nil)
74 extraSubjects := subjectSubtract(systemCertPoolSubjects, certPoolSubjects)
75
76 // Remove extra subjects from the cert pool
77 var filteredSystemCertPoolSubjects []*pkix.Name
78
79 t.Log(extraSubjects)
80
81OUTER:
82 for _, subject := range certPoolSubjects {
83 for _, extraSubject := range extraSubjects {
84 if subject == extraSubject {
85 t.Log(extraSubject)
86 continue OUTER
87 }
88 }
89
90 filteredSystemCertPoolSubjects = append(filteredSystemCertPoolSubjects, subject)
91 }
92
93 assert.Equal(t, len(filteredSystemCertPoolSubjects), len(systemCertPoolSubjects))
94
95 difference := subjectSubtract(systemCertPoolSubjects, filteredSystemCertPoolSubjects)
96 assert.Equal(t, 0, len(difference))
97}
98
99func TestLoadOriginCertPoolCFCertificates(t *testing.T) {
100 certPoolSubjects := loadCertPoolSubjects(t, nil)
101
102 extraSubjects := subjectSubtract(systemCertPoolSubjects, certPoolSubjects)
103
104 expected := []*certificateFixture{
105 {ou: "CloudFlare Origin SSL ECC Certificate Authority"},
106 {ou: "CloudFlare Origin SSL Certificate Authority"},
107 {cn: "origin-pull.cloudflare.net"},
108 {cn: "Argo Tunnel Sample Hello Server Certificate"},
109 }
110
111 assertFixturesMatchSubjects(t, expected, extraSubjects)
112}
113
114func TestLoadOriginCertPoolWithExtraPEMs(t *testing.T) {
115 certPoolWithoutPEMSubjects := loadCertPoolSubjects(t, nil)
116 certPoolWithPEMSubjects := loadCertPoolSubjects(t, samplePEM)
117
118 difference := subjectSubtract(certPoolWithoutPEMSubjects, certPoolWithPEMSubjects)
119
120 assert.Equal(t, 2, len(difference))
121
122 expected := []*certificateFixture{
123 {cn: "Test One"},
124 {cn: "Test Two"},
125 }
126
127 assertFixturesMatchSubjects(t, expected, difference)
128}
129
130func loadCertPoolSubjects(t *testing.T, originCAPoolPEM []byte) []*pkix.Name {
131 certPool, err := LoadOriginCertPool(originCAPoolPEM)
132 if isUnrecoverableError(err) {
133 t.Fatal(err)
134 }
135 assert.NotEmpty(t, certPool.Subjects())
136 certPoolSubjects, err := getCertPoolSubjects(certPool)
137 if err != nil {
138 t.Fatal(err)
139 }
140
141 return certPoolSubjects
142}
143
144func assertFixturesMatchSubjects(t *testing.T, fixtures []*certificateFixture, subjects []*pkix.Name) {
145 assert.Equal(t, len(fixtures), len(subjects))
146
147 for _, fixture := range fixtures {
148 found := false
149 for _, subject := range subjects {
150 found = found || fixtureMatchesSubjectPredicate(fixture, subject)
151 }
152
153 if !found {
154 t.Fail()
155 }
156 }
157}
158
159func fixtureMatchesSubjectPredicate(fixture *certificateFixture, subject *pkix.Name) bool {
160 cnMatch := true
161 if fixture.cn != "" {
162 cnMatch = fixture.cn == subject.CommonName
163 }
164
165 ouMatch := true
166 if fixture.ou != "" {
167 ouMatch = len(subject.OrganizationalUnit) > 0 && fixture.ou == subject.OrganizationalUnit[0]
168 }
169
170 return cnMatch && ouMatch
171}
172
173func subjectSubtract(left []*pkix.Name, right []*pkix.Name) []*pkix.Name {
174 var difference []*pkix.Name
175
176 var found bool
177 for _, r := range right {
178 found = false
179 for _, l := range left {
180 if (*l).String() == (*r).String() {
181 found = true
182 }
183 }
184
185 if !found {
186 difference = append(difference, r)
187 }
188 }
189
190 return difference
191}
192
193func getCertPoolSubjects(certPool *x509.CertPool) ([]*pkix.Name, error) {
194 var subjects []*pkix.Name
195
196 for _, subject := range certPool.Subjects() {
197 var sequence pkix.RDNSequence
198 _, err := asn1.Unmarshal(subject, &sequence)
199 if err != nil {
200 return nil, err
201 }
202
203 name := pkix.Name{}
204 name.FillFromRDNSequence(&sequence)
205
206 subjects = append(subjects, &name)
207 }
208
209 return subjects, nil
210}
211
212func isUnrecoverableError(err error) bool {
213 return err != nil && err.Error() != "crypto/x509: system root pool is not available on Windows"
214}
215