Browse code

Merge pull request #11716 from ramr/fix-extval-bug

Merged by openshift-bot

OpenShift Bot authored on 2016/11/09 06:43:04
Showing 2 changed files
... ...
@@ -3,7 +3,6 @@ package validation
3 3
 import (
4 4
 	"crypto/tls"
5 5
 	"crypto/x509"
6
-	"encoding/pem"
7 6
 	"fmt"
8 7
 	"strings"
9 8
 
... ...
@@ -15,6 +14,7 @@ import (
15 15
 	"k8s.io/kubernetes/pkg/util/validation/field"
16 16
 
17 17
 	oapi "github.com/openshift/origin/pkg/api"
18
+	cmdutil "github.com/openshift/origin/pkg/cmd/util"
18 19
 	routeapi "github.com/openshift/origin/pkg/route/api"
19 20
 )
20 21
 
... ...
@@ -131,23 +131,29 @@ func ExtendedValidateRoute(route *routeapi.Route) field.ErrorList {
131 131
 	//       break, so disable the hostname validation for now.
132 132
 	// hostname := route.Spec.Host
133 133
 	hostname := ""
134
-	var certPool *x509.CertPool
134
+	var verifyOptions *x509.VerifyOptions
135 135
 
136 136
 	if len(tlsConfig.CACertificate) > 0 {
137
-		certPool = x509.NewCertPool()
138
-		if ok := certPool.AppendCertsFromPEM([]byte(tlsConfig.CACertificate)); !ok {
139
-			result = append(result, field.Invalid(tlsFieldPath.Child("caCertificate"), tlsConfig.CACertificate, "failed to parse CA certificate"))
137
+		certPool := x509.NewCertPool()
138
+		if certs, err := cmdutil.CertificatesFromPEM([]byte(tlsConfig.CACertificate)); err != nil {
139
+			errmsg := fmt.Sprintf("failed to parse CA certificate: %v", err)
140
+			result = append(result, field.Invalid(tlsFieldPath.Child("caCertificate"), "<ca certificate data>", errmsg))
141
+		} else {
142
+			for _, cert := range certs {
143
+				certPool.AddCert(cert)
144
+			}
140 145
 		}
141
-	}
142 146
 
143
-	verifyOptions := &x509.VerifyOptions{
144
-		DNSName: hostname,
145
-		Roots:   certPool,
147
+		verifyOptions = &x509.VerifyOptions{
148
+			DNSName:       hostname,
149
+			Intermediates: certPool,
150
+			Roots:         certPool,
151
+		}
146 152
 	}
147 153
 
148 154
 	if len(tlsConfig.Certificate) > 0 {
149 155
 		if _, err := validateCertificatePEM(tlsConfig.Certificate, verifyOptions); err != nil {
150
-			result = append(result, field.Invalid(tlsFieldPath.Child("certificate"), tlsConfig.Certificate, err.Error()))
156
+			result = append(result, field.Invalid(tlsFieldPath.Child("certificate"), "<certificate data>", err.Error()))
151 157
 		}
152 158
 
153 159
 		certKeyBytes := []byte{}
... ...
@@ -158,14 +164,14 @@ func ExtendedValidateRoute(route *routeapi.Route) field.ErrorList {
158 158
 		}
159 159
 
160 160
 		if _, err := tls.X509KeyPair(certKeyBytes, certKeyBytes); err != nil {
161
-			result = append(result, field.Invalid(tlsFieldPath.Child("key"), tlsConfig.Key, err.Error()))
161
+			result = append(result, field.Invalid(tlsFieldPath.Child("key"), "<key data>", err.Error()))
162 162
 		}
163 163
 	}
164 164
 
165 165
 	if len(tlsConfig.DestinationCACertificate) > 0 {
166
-		roots := x509.NewCertPool()
167
-		if ok := roots.AppendCertsFromPEM([]byte(tlsConfig.DestinationCACertificate)); !ok {
168
-			result = append(result, field.Invalid(tlsFieldPath.Child("destinationCACertificate"), tlsConfig.DestinationCACertificate, "failed to parse destination CA certificate"))
166
+		if _, err := cmdutil.CertificatesFromPEM([]byte(tlsConfig.DestinationCACertificate)); err != nil {
167
+			errmsg := fmt.Sprintf("failed to parse destination CA certificate: %v", err)
168
+			result = append(result, field.Invalid(tlsFieldPath.Child("destinationCACertificate"), "<destination ca certificate data>", errmsg))
169 169
 		}
170 170
 	}
171 171
 
... ...
@@ -218,25 +224,25 @@ func validateTLS(route *routeapi.Route, fldPath *field.Path) field.ErrorList {
218 218
 	//passthrough term should not specify any cert
219 219
 	case routeapi.TLSTerminationPassthrough:
220 220
 		if len(tls.Certificate) > 0 {
221
-			result = append(result, field.Invalid(fldPath.Child("certificate"), tls.Certificate, "passthrough termination does not support certificates"))
221
+			result = append(result, field.Invalid(fldPath.Child("certificate"), "<certificate data>", "passthrough termination does not support certificates"))
222 222
 		}
223 223
 
224 224
 		if len(tls.Key) > 0 {
225
-			result = append(result, field.Invalid(fldPath.Child("key"), tls.Key, "passthrough termination does not support certificates"))
225
+			result = append(result, field.Invalid(fldPath.Child("key"), "<key data>", "passthrough termination does not support certificates"))
226 226
 		}
227 227
 
228 228
 		if len(tls.CACertificate) > 0 {
229
-			result = append(result, field.Invalid(fldPath.Child("caCertificate"), tls.CACertificate, "passthrough termination does not support certificates"))
229
+			result = append(result, field.Invalid(fldPath.Child("caCertificate"), "<ca certificate data>", "passthrough termination does not support certificates"))
230 230
 		}
231 231
 
232 232
 		if len(tls.DestinationCACertificate) > 0 {
233
-			result = append(result, field.Invalid(fldPath.Child("destinationCACertificate"), tls.DestinationCACertificate, "passthrough termination does not support certificates"))
233
+			result = append(result, field.Invalid(fldPath.Child("destinationCACertificate"), "<destination ca certificate data>", "passthrough termination does not support certificates"))
234 234
 		}
235 235
 	// edge cert should only specify cert, key, and cacert but those certs
236 236
 	// may not be specified if the route is a wildcard route
237 237
 	case routeapi.TLSTerminationEdge:
238 238
 		if len(tls.DestinationCACertificate) > 0 {
239
-			result = append(result, field.Invalid(fldPath.Child("destinationCACertificate"), tls.DestinationCACertificate, "edge termination does not support destination certificates"))
239
+			result = append(result, field.Invalid(fldPath.Child("destinationCACertificate"), "<destination ca certificate data>", "edge termination does not support destination certificates"))
240 240
 		}
241 241
 	default:
242 242
 		validValues := []string{string(routeapi.TLSTerminationEdge), string(routeapi.TLSTerminationPassthrough), string(routeapi.TLSTerminationReencrypt)}
... ...
@@ -282,37 +288,33 @@ func validateInsecureEdgeTerminationPolicy(tls *routeapi.TLSConfig, fldPath *fie
282 282
 
283 283
 // validateCertificatePEM checks if a certificate PEM is valid and
284 284
 // optionally verifies the certificate using the options.
285
-func validateCertificatePEM(certPEM string, options *x509.VerifyOptions) (*x509.Certificate, error) {
286
-	var data *pem.Block
287
-	for remaining := []byte(certPEM); len(remaining) > 0; {
288
-		block, rest := pem.Decode(remaining)
289
-		if block == nil {
290
-			return nil, fmt.Errorf("error decoding certificate data")
291
-		}
292
-		if block.Type == "CERTIFICATE" {
293
-			data = block
294
-			break
295
-		}
296
-		remaining = rest
285
+func validateCertificatePEM(certPEM string, options *x509.VerifyOptions) ([]*x509.Certificate, error) {
286
+	certs, err := cmdutil.CertificatesFromPEM([]byte(certPEM))
287
+	if err != nil {
288
+		return nil, err
297 289
 	}
298 290
 
299
-	if data == nil || len(data.Bytes) < 1 {
291
+	if len(certs) < 1 {
300 292
 		return nil, fmt.Errorf("invalid/empty certificate data")
301 293
 	}
302 294
 
303
-	cert, err := x509.ParseCertificate(data.Bytes)
304
-	if err != nil {
305
-		return nil, fmt.Errorf("error parsing certificate: %s", err.Error())
306
-	}
307
-
308 295
 	if options != nil {
309
-		_, err = cert.Verify(*options)
296
+		// Ensure we don't report errors for expired certs or if
297
+		// the validity is in the future.
298
+		// Not that this can be for the actual certificate or any
299
+		// intermediates in the CA chain. This allows the router to
300
+		// still serve an expired/valid-in-the-future certificate
301
+		// and lets the client to control if it can tolerate that
302
+		// (just like for self-signed certs).
303
+		_, err = certs[0].Verify(*options)
310 304
 		if err != nil {
311
-			return cert, fmt.Errorf("error verifying certificate: %s", err.Error())
305
+			if invalidErr, ok := err.(x509.CertificateInvalidError); !ok || invalidErr.Reason != x509.Expired {
306
+				return certs, fmt.Errorf("error verifying certificate: %s", err.Error())
307
+			}
312 308
 		}
313 309
 	}
314 310
 
315
-	return cert, nil
311
+	return certs, nil
316 312
 }
317 313
 
318 314
 var (
... ...
@@ -110,6 +110,493 @@ bGvtpjWA4r9WASIDPFsxk/cDEEEO6iPxgMOf5MdpQC2y2MU0rzF/Gg==
110 110
 -----END CERTIFICATE-----`
111 111
 
112 112
 	testDestinationCACertificate = testCACertificate
113
+
114
+	testValidInFutureCert = `-----BEGIN CERTIFICATE-----
115
+MIIDjzCCAnegAwIBAgIJAJcdKWMFNUEGMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
116
+BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsM
117
+ClNlbGZTaWduZXIxGTAXBgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwIBcNMzgwMTAx
118
+MDgwMDAyWhgPMjA1ODAxMDEwODAwMDJaMF0xCzAJBgNVBAYTAlVTMQswCQYDVQQI
119
+DAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsMClNlbGZTaWduZXIxGTAX
120
+BgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
121
+ggEKAoIBAQDBAtP5vHkVS9qZNmI9QKj7B/ATt2+Fw+f4xD+6Q2+1sOkLH3x6+D85
122
+5A+xAAvQdz5qf+yfvtNOhWqmIG5Zh0TzaiA5lw2U0YL4FT4Z4nbYAPMO45lctvRH
123
+nXBeSO7N/JiFBlvMPqP4gsimstEgiNm225KlQRHOqMfOEAC15pyUrE643Gs0DCVR
124
+L1tZuwdfBUpybxAPDWpgx7CNTc0beuNXooroMU1dCdM+BjYHYfSCnoNwa4qp130e
125
+6vRWnzlhfXbFTsCVCe4y6edF/+M3PegIx0+PhkgeSOxd2+nBsiatrG5ZyiP5iaRK
126
+2278nFERyUQ1SbhicDrhlU9TQAMcTMAvAgMBAAGjUDBOMB0GA1UdDgQWBBQ28jRf
127
+N/CCqVyOU8mOZpG8ow86WjAfBgNVHSMEGDAWgBQ28jRfN/CCqVyOU8mOZpG8ow86
128
+WjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC+Nu8pEUB7agGHUU/e
129
+1NHI84guwKKA2qNnkQZKn6h49AA/bPjKr9SFQHNxFFMyrVInt1Ez9sRNviArQc+w
130
+DToHY+T/3WUVcQIQnRW3m4r6UUsxKZjtrSBD2Dhr6nL9hVVtGIfimuuxxJt1JItJ
131
+UaOY+Kq4gtWOJMcV5xTEaPmkphAgwoZzjZj7Z9SZwVLGopJa8kB3EvlkxUO3DmSp
132
+9Lq3AhHRYgwWcjcd9UC9NyXQ9hBTV2iPBSvc2I4vmYQwnOutBEeNM0IPQQk7f2VL
133
+fKSS26HocZpiN0e7vO0XoJfh4VkOIn7BGNwxiDr9cIRL4ZHhZ0/kRQuXCHHYbTdq
134
+9mKv
135
+-----END CERTIFICATE-----`
136
+
137
+	testValidInFutureKey = `-----BEGIN PRIVATE KEY-----
138
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBAtP5vHkVS9qZ
139
+NmI9QKj7B/ATt2+Fw+f4xD+6Q2+1sOkLH3x6+D855A+xAAvQdz5qf+yfvtNOhWqm
140
+IG5Zh0TzaiA5lw2U0YL4FT4Z4nbYAPMO45lctvRHnXBeSO7N/JiFBlvMPqP4gsim
141
+stEgiNm225KlQRHOqMfOEAC15pyUrE643Gs0DCVRL1tZuwdfBUpybxAPDWpgx7CN
142
+Tc0beuNXooroMU1dCdM+BjYHYfSCnoNwa4qp130e6vRWnzlhfXbFTsCVCe4y6edF
143
+/+M3PegIx0+PhkgeSOxd2+nBsiatrG5ZyiP5iaRK2278nFERyUQ1SbhicDrhlU9T
144
+QAMcTMAvAgMBAAECggEAWYJvPd0bJjY0XWNsMc3fz/NBclNao+VTmfmhOEd38gHm
145
+QaNLflfMMpPCdyp3UClMx+UlnnvH0R1sdTiLFHf4EQ7BfRPBV6fGHjjzwNtWlBv0
146
+nI4OnIG4TdIEv6UBIoQnU2G8hr7yGhjE5xH8jCMLHJM9see4U2fQqY6gVbtqGEP1
147
+w29IhoYcCPsqIhBYlmOaxvEBA12SKjZEaLT4dTImcvNsYuNAHbKpS1m6nA7KaqLN
148
+hkFJ5oKPlsMT2bFCaHzB7Es/90FgkLk3EULx9G5uV+26FcovhSKI/j4kkBZ57BZG
149
+rGuMScjxGLolY7dv0PlQvSzDmsA4EEzEQECy5kJFAQKBgQDv7jhEBsuKs9t6UOBF
150
+QBsmAsTs5I9UoQd5ZBy1QoOxmN5aLjNNfFd86LBomC/oF0AZpEKfHA+Ha8ttdJNX
151
+vjkSIbfJKYfd4J/A4J7Wna3RPExu0wqN3g2xiPNeyYmzd8H2ER1t850YzFbT8f7M
152
+pSQbbqWkjLzRw3wUBVQao/PlrwKBgQDN8CPWZuKzIhSsBLKtG41evnSCMOoSWRRQ
153
+VmLnxIa7x8Ng/v8T39S4Tzpx50uq0ZAoegmI5aMvJEwayMShZdHt++DIjNfnayXS
154
+yQ6Cr+FqObeZX1B25eChiyN/O/RPx1zJ6eW0FUKlTheYIv4u+D0AwzmyaySeAEyo
155
+ZhiOnS3tgQKBgD9y3NhIf70fURQonRZTHJrRsqf+zVSQ/PwCGIFqpI7roSlx/Ekq
156
+b6xtkHEohcq3k1D0mlWfQxAJ1pMMeAaFHGyKFCMTY4WuaDDGddrFefjSHFhWYP0h
157
+Ure3Qry3ST33lohvADxaZxnut6t23G3b4g+LFCzOtwQ10PMucY5V+yKrAoGAfAyc
158
+OckN46Oy2g+WZYoENT76RXYbeWPpRZ9TwpJyKmjheur/UcRxiXhIF1ahEMtdT9R7
159
+K9hP3NS7dyLatvHza6xesc+NOlwjk34C3Jv/Z5JO0vdEK+q6zfRXNIwz1V6cuQ/I
160
+ixqHY7XPppfljvt/G5d9iMjbbMV3Z7TgM//gK4ECgYBkSU6B77LnXtb0QPTsBdq6
161
+7hvEPH4lhnpcXRemfq3Q0/GYeACSoAPUGxy8LwT50pagaIf6ZG1esMFiALFsJWer
162
+XdzRo+/NffATcVvoof1Gnjhe/qt0kby66wR42JJMK/q4BKAN0kitfkzOPC4HVoF4
163
+DOGy/dMN+k0W2RgJ5JKR3g==
164
+-----END PRIVATE KEY-----`
165
+
166
+	testSelfSignedCert = `-----BEGIN CERTIFICATE-----
167
+MIIDjTCCAnWgAwIBAgIJAKM4rr3VRQARMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
168
+BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsM
169
+ClNlbGZTaWduZXIxGTAXBgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwHhcNMTYxMTAx
170
+MjEzNzU4WhcNMzYxMTAxMjEzNzU4WjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwC
171
+Q0ExETAPBgNVBAoMCFNlY3VyaXR5MRMwEQYDVQQLDApTZWxmU2lnbmVyMRkwFwYD
172
+VQQDDBBzZWxmLnNpZ25lci50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
173
+CgKCAQEAvF0Rw580En6xCPvoLoMBUzI9HD5D7UFycpOG/qL5ZtmhzYR62WBKhc/C
174
+ysWxRL3+GFD9m5zoDuB2qGMohBfsIVF2TX7oqgovKkX7BDO92vrDtGJo/QJnUhku
175
+pASTmAgPMacxwvSQM5yJgb5GNtkvoulXbE31S5VDamcsH+ej0VKYKKXPtbFDBMxx
176
+NysoUCCb1SiPBicgx9V69VlU6UeataNHz0oyxH9ijCYShePbk0TQRXlyTzdMIaL0
177
+AeWLlngmlVYP1RoZXGNupX5R8EAdrc5nRV5+epkJDzOHfxE3bbSM8fzPcI7KyHkp
178
+sA3PBPf8uUFfGNGpt4ubc4Kp0yL1vwIDAQABo1AwTjAdBgNVHQ4EFgQUNvPQ5ChF
179
+G8UpyLlnVlrXmN9Oi0QwHwYDVR0jBBgwFoAUNvPQ5ChFG8UpyLlnVlrXmN9Oi0Qw
180
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAhOCb94qvpwad4ZyGfeV9
181
+aE/9wIGT/xs0KnV7wS1OopGnglcgogns5Vcs2rzBrcN04n5EYZ+V7naMjReVhpBv
182
+gJ26YYfnitrGkWazncGW1BYI7fXAdU2cBJ+LLCbZX1zz9BqBW5ldvbk/XWTg4ols
183
+29j8kpLwA2UEApE25xWmXBBHyDIzvNzyiwswrdo26BUZdHCA/pplPFpz6UEYLYEX
184
+Bv95o5CLf2CQIxC6uE7BENrQo7ItwHvJoYlkdkYil3V/Qx25YafulH+wbL6ccN6F
185
+fjEOS33MDf9AIbgSgiPlGSwkikVjy73ADWWdQCOJhrMUnSnqE05gCRd5qIggACf1
186
+0A==
187
+-----END CERTIFICATE-----`
188
+
189
+	testSelfSignedKey = `-----BEGIN PRIVATE KEY-----
190
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC8XRHDnzQSfrEI
191
+YyiEF+whUXZNfuiqCi8qRfsEM73a+sO0Ymj9AmdSGS6kBJOYCA8xpzHC9JAznImB
192
+vkY22S+i6VdsTfVLlUNqZywf56PRUpgopc+1sUMEzHE3KyhQIJvVKI8GJyDH1Xr1
193
+WVTpR5q1o0fPSjLEf2KMJhKF49uTRNBFeXJPN0whovQB5YuWeCaVVg/VGhlcY26l
194
+flHwQB2tzmdFXn56mQkPM4d/ETdttIzx/M9wjsrIeSmwDc8E9/y5QV8Y0am3i5tz
195
+gqnTIvW/AgMBAAECggEBAKkJqJByRau3UC5syj87R6wesKKw6gp3qjpSVFodbU20
196
+TrT9h7Wd6SLOgNOxt9Sl3+p4fC7zD3mSTEnuuoRYZ4q67Ty8gBVgkFUSeiKaQG3M
197
+jmZJzkgHqSsO+EEu7jkIOoJntYtsKCB5ARmS5LYCD/LWDqNeDpymtdo9/mYfXW7R
198
+cwCIbv0mXjybx4YUKLvVAstszmvr4uZXPqBlceaBv4jTx2xZlzCM6WAgMbjJM3vS
199
+3BLFcICy3fhXSzEtaAefTnFVRzXAUZjgKn73JpHsPqScfFw4Q/eR/AN/jpjPkrsx
200
+scRFqpRFEVO3/9A+PoFzL3ofaD6pTPVdCYdQCtA14iECgYEA4XHWGNUO7+HhAxb8
201
+2XhtkuvDN3HH/QswCqI5zyXnYoE47OD3stLD1YsDl2wm+XCl5/N5u0qx2Hh0956q
202
+Zwk2BBZnHU4yfLsCieSiyDff8ulJMX1Xh0Ssk3bmDucMjatmfWXrMsMVhB+Tm+oA
203
+yhMGe3rKKk4aGMfEQ2vAbFRwuDECgYEA1eSk7bqJeRn4Y0iW0I4w09CJ9DlmzR/S
204
+3VDEmbHcny4noEHRNPMacjDvNuj04XOlbsm4R785M4WRgoZxQXDpXSfL23UFbmPU
205
+yxxNYw3dc10q2u+PjzXc6bzv/qYsNuc6SmNeUT1puI9SnEEYT7+6CaeHeJB4W1RL
206
+B2pSEqmXAO8CgYEAonH7WmNTYwh4sVhEE5OSKPaW8QGcoDoKgO8KBriCNNl2IkGs
207
+Wf9Cu0Fy8g4tOzmvYiZvhcQ5yAhsB+0dTic189YMsPIisPuzxZaosOqKBSeR5QYz
208
+JrYWQB/Bf+V+hyqFLEBfLHGjtFNockU4EmOJHTqKJ9elOEvhoM8olSZ3HlECgYAw
209
+114F3uOHYLPEUA4IH3/sziDCQN1Fl6+507ig8+lR++MWiBDyi1SNoLjvC/DnDlZH
210
+Xw6Sa4rvRd+9M1/nNpZDLFQzj5wm4er0Wkkdhkv8DNk9Vxir9fu07+zJdD6CZvh7
211
+hgdCe8iJWUje30pi43/itnuLv0mMaUocrl2BX3JYxwKBgQC5+usY3fF/q8wLYGgo
212
+BRjkyMvkeRgidMwJMnimflZ7X9Svfh4gw7JYub8Vksys5RYQ/3wSZuwy2dxamCxr
213
+H6e+rtFlOu/BZSBUUgcOJ4xSDUilztVSMGHK7AxhBGlBHzPRwY8bjQfMaODs9pD8
214
+qOFcy/8ogwZdP9nTV73O2wG56g==
215
+-----END PRIVATE KEY-----`
216
+
217
+	testExpiredCertNoKey = `-----BEGIN CERTIFICATE-----
218
+MIIDIjCCAgqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCVVMx
219
+CzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
220
+ZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0ExGjAYBgNVBAMMEXd3
221
+dy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu
222
+Y29tMB4XDTE1MDExMjE0MTk0MVoXDTE2MDExMjE0MTk0MVowfDEYMBYGA1UEAwwP
223
+d3d3LmV4YW1wbGUuY29tMQswCQYDVQQIDAJTQzELMAkGA1UEBhMCVVMxIjAgBgkq
224
+hkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUx
225
+EDAOBgNVBAsMB0V4YW1wbGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrv
226
+gu6ZTTefNN7jjiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm
227
+47VRx5Qrf/YLXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1M
228
+mNrQUgZyQC6XIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAGjDTALMAkGA1UdEwQC
229
+MAAwDQYJKoZIhvcNAQEFBQADggEBAFCi7ZlkMnESvzlZCvv82Pq6S46AAOTPXdFd
230
+TMvrh12E1sdVALF1P1oYFJzG1EiZ5ezOx88fEDTW+Lxb9anw5/KJzwtWcfsupf1m
231
+V7J0D3qKzw5C1wjzYHh9/Pz7B1D0KthQRATQCfNf8s6bbFLaw/dmiIUhHLtIH5Qc
232
+yfrejTZbOSP77z8NOWir+BWWgIDDB2//3AkDIQvT20vmkZRhkqSdT7et4NmXOX/j
233
+jhPti4b2Fie0LeuvgaOdKjCpQQNrYthZHXeVlOLRhMTSk3qUczenkKTOhvP7IS9q
234
++Dzv5hqgSfvMG392KWh5f8xXfJNs4W5KLbZyl901MeReiLrPH3w=
235
+-----END CERTIFICATE-----`
236
+
237
+	testIntCACertificateChain = `-----BEGIN CERTIFICATE-----
238
+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
268
+r2RUXNnvSmi8ubzDBls=
269
+-----END CERTIFICATE-----
270
+-----BEGIN CERTIFICATE-----
271
+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
301
+G0k/6pTJTZwfsA==
302
+-----END CERTIFICATE-----`
303
+
304
+	testCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
305
+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
339
+OyxyJrGdmLclqzBEW1Zv3j5ywA==
340
+-----END CERTIFICATE-----`
341
+
342
+	testPrivateKeyWithIntCA = `-----BEGIN RSA PRIVATE KEY-----
343
+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
392
+-----END RSA PRIVATE KEY-----`
393
+
394
+	testExpiredCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
395
+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
429
++wlvPN8TwYpdQ/skn6pz9kx0V2FQaQFisF+x
430
+-----END CERTIFICATE-----`
431
+
432
+	testExpiredCertificateKey = `-----BEGIN RSA PRIVATE KEY-----
433
+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
482
+-----END RSA PRIVATE KEY-----`
483
+
484
+	testFutureValidCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
485
+MIIGgTCCBGmgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMx
486
+CzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNo
487
+aWZ0MyB0ZXN0IENBMRwwGgYDVQQDDBNpbnRlcm1lZGlhdGUuY2Eub3JnMCAYDzIw
488
+MzYwMjI4MTAxMDMwWhcNMzYxMTAzMDAxNzE3WjBwMQswCQYDVQQGEwJVUzELMAkG
489
+A1UECAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hpZnQz
490
+IHRlc3QgQ0ExJDAiBgNVBAMMG3ZhbGlkLmluLnRoZS5mdXR1cmUuY2EudGVzdDCC
491
+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN6DzbjCo4EvQ9NKIBCMZXAb
492
+0OnhLkDJa5P4O4sjRuOFAbl/e6SZ05olK7uNgbuis5aebzKC8nb+UuS4b8GXTWkL
493
+TS5sbGUsrIZ6PDCA+cvEj4ZwYPjqNCurimLNyQYyroNy+pRxtkSfV+9TS7zndRxo
494
+aWZECQ4ApXageNu7Afg9M9/ainQR0w5TyJ2kKB6O0+0dF/7re30tD7FX+wHfN6/z
495
+owbM5qGEPcFINGYZPik8ZGkVsv98BFI3MTHjlgQ5a44Rmg3jVhdCuI2sy41pm2pM
496
+2x1pUGqj6UjxbwXq7yKOle0W6dni3TpR57Pq5/jfpsMITGtYM++J/i2LxjTTsIpI
497
+9Qe6gHRapYA8Ab1ro9QHgAe6LVUt39ki7O6EVGBq08405tnna5uvDm3/Bl7qYq6O
498
+erhRKATRyj/Vf1PJ7823NvOgQzvwx6w6c2kJJQIPcYppUfsUpYgIRQuy8759jAMA
499
+RESXQfCK/W6ub1P0dYSKBejf5cf1QhrVfxqkun222qyHk9PDNt/FTzG9V/Y9w4y8
500
+uTnUWXHDLVHHtrOCyLEZLsdaZbZnt7g1Q+zuaJ/0CTnkMsksroLfZLwbuPJdRezR
501
+z8MbgLodjDgwKh8RpXdXPdIanP0SgZsTjpGlAYUr/GA4l9x/lf8GfG6KTRMC9dKi
502
+jIpB5MNxkYrkP2NuFdvlAgMBAAGjggEpMIIBJTAJBgNVHRMEAjAAMBEGCWCGSAGG
503
++EIBAQQEAwIGQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2Vy
504
+dmVyIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ9aWYDwIp0t7yQTTyfA77g5OcRtDCB
505
+iwYDVR0jBIGDMIGAgBSJpW4a7QM2MkPIdhDrAIEEGc2Rg6FkpGIwYDELMAkGA1UE
506
+BhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwS
507
+T3BlblNoaWZ0MyB0ZXN0IENBMRQwEgYDVQQDDAtyb290LmNhLm9yZ4ICEAAwDgYD
508
+VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUA
509
+A4ICAQAtneFpJw97r8GkNK5oY86PKStfj9e1W8v3EfHc9YkhkZ7qDKXvSuY0UC0T
510
+abhhgL2IDF3zmnH71RY+WMNmDCbJWZoOe2NXjo3TxG38fLqk9C2ayi860TasPQNM
511
+rcZ0E+FiDxm582wrmBdD+GpgrNlwiQ2Z5U897IDZv7LiPI7rSYF3OvI/xxz2Q7ZT
512
+VDJBH22Fg7UY3JqVRMU/4ff3jiWuelbepSyk7LqxYQuAcBR2nTA/8UGw1YplESm0
513
+YWEHwE8GykJB5LVXQsVNo/MlEU3vwa5YnseFWdtkg3JKyK9dv6QE3LAnbw0kwx5R
514
+HUBXN0N57aODaQbx1amSHqAmNnpZtfoZfJhdZR0RVvUeIv7D9HjIpJio+pEcNJwY
515
+xyVVqbD/tYc4tUFeAtHl9jM1Ob2p/nHj/yOjCy3GTY/eUPNLgGs0DX4aFo4WTDdd
516
+GKEd0EKjqXLFYFHUWuNAh2+0J7xAXR8oP7sOdg5DiclCZMT874YOlS5Ps6E/PnvR
517
+sgOg6zar/gx5Rp8ext2NVkXgTww2fzVgf0+FF1GrhjdugsGLjyqfFEspZ85Yrkdo
518
+hYnY5k0G+POAuJKmPgUd7W1QltLnRRvsFyEse+qkTj7cxj4ZwsJ8YJuM8yO5/+ol
519
+XzV329s9fh8ILFaY4196hzqNsEX5ZHYxc/AtcoMMniDPATyK1w==
520
+-----END CERTIFICATE-----`
521
+
522
+	testFutureValidCertificateKey = `-----BEGIN RSA PRIVATE KEY-----
523
+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
572
+-----END RSA PRIVATE KEY-----`
573
+
574
+	testInvalidCANoCert1 = `-----BEGIN CERTIFICATE REQUEST-----
575
+MIICnTCCAYUCAQAwWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQK
576
+DAhTZWN1cml0eTETMBEGA1UECwwKT3BlblNoaWZ0MzEUMBIGA1UEAwwLcm91dGVy
577
+LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS7tHwWAJ0PBuU
578
+u8RJ5i98FoDmXgaL0uiLR+n46FACiRW0tKA0WvXX9afSFSa5nb+Z9GHxMBsIe1lu
579
+noM+k2lBScW8PnGTW5mzkEHVzGb9zmM8lSE6gcRjZwPPre3bnWnemXU1Loa6IV+W
580
+p9w8x/SqlZAlS+Vab+5opC8dSXM4OG1qIb0JqPrXPx8e7RaLr53fmbEm3iIT/wjk
581
+GWfQFAUToswERt2Jx5Ojri5qe+VDwlfOXt6GjWDPJsYroufDXxWmboZZtYxsVZnY
582
+xWgnwHVaHaTdbogafXWWyfLhSdNpjUX9bnXWSh+VR5m7SxjgjqqYK8EpqNyxay+E
583
+mBdaVgWPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAnVnDhysDJY3MPqIYYXwE
584
+Yg9pkV4j5MStP2sSR+oWgqBP1BGZn2yaK2Bb8jGeBw53uuH0S+NifnVVXi1Q7rmV
585
+P8SLmCRvWDbeRgQC4fWgrzEkB8kePTGuvZM6/wLTiw3i1AxcG8Z8aDVNRrJq0im5
586
+dAz9X4YF0m9ZweqB9LeYd/UXbI2ZMHBkOgY08Co1X7+DpfohzCOflix1vjuygViR
587
+1MXW8UIYFktyyhSeL7eshW0BhqfMoku+btO4LZ/IZHDZsF3gd5NOPoNX28m0E74y
588
+xhfvmedJE9ck2tEbxQk8BcdCXCN4HFePO8gpCYeC7r309E/QwFjU9+xw6qrpW5uP
589
+GA==
590
+-----END CERTIFICATE REQUEST-----`
591
+
592
+	testInvalidCANoCert2 = testSelfSignedKey
593
+
594
+	testInvalidCAMalformedCert = `-----BEGIN CERTIFICATE-----
595
+MIIDjTCCAnWgAwIBAgIJAKM4rr3VRQARMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
596
+The+rest+of+the+certificate+info+is+invalid+and+badly+malformed/
597
+0A==
598
+-----END CERTIFICATE-----`
113 599
 )
114 600
 
115 601
 func createRouteSpecTo(name string, kind string) api.RouteTargetReference {
... ...
@@ -917,7 +1404,21 @@ func TestExtendedValidateRoute(t *testing.T) {
917 917
 			expectedErrors: 1,
918 918
 		},
919 919
 		{
920
-			name: "Edge termination expired cert",
920
+			name: "Edge termination expired cert unknown CA",
921
+			route: &api.Route{
922
+				Spec: api.RouteSpec{
923
+					Host: "www.example.com",
924
+					TLS: &api.TLSConfig{
925
+						Termination: api.TLSTerminationEdge,
926
+						Certificate: testExpiredCAUnknownCertificate,
927
+						Key:         testExpiredCertPrivateKey,
928
+					},
929
+				},
930
+			},
931
+			expectedErrors: 0,
932
+		},
933
+		{
934
+			name: "Edge termination expired cert mismatched CA",
921 935
 			route: &api.Route{
922 936
 				Spec: api.RouteSpec{
923 937
 					Host: "www.example.com",
... ...
@@ -1031,6 +1532,349 @@ func TestExtendedValidateRoute(t *testing.T) {
1031 1031
 			},
1032 1032
 			expectedErrors: 4,
1033 1033
 		},
1034
+		{
1035
+			name: "example cert",
1036
+			route: &api.Route{
1037
+				Spec: api.RouteSpec{
1038
+					Host: "www.example.com",
1039
+					TLS: &api.TLSConfig{
1040
+						Termination:   api.TLSTerminationEdge,
1041
+						Certificate:   testCertificate,
1042
+						Key:           testPrivateKey,
1043
+						CACertificate: testCACertificate,
1044
+					},
1045
+				},
1046
+			},
1047
+			expectedErrors: 0,
1048
+		},
1049
+		{
1050
+			name: "Expired cert",
1051
+			route: &api.Route{
1052
+				Spec: api.RouteSpec{
1053
+					Host: "www.example.com",
1054
+					TLS: &api.TLSConfig{
1055
+						Termination:   api.TLSTerminationEdge,
1056
+						Certificate:   testCertificate,
1057
+						Key:           testPrivateKey,
1058
+						CACertificate: testCACertificate,
1059
+					},
1060
+				},
1061
+			},
1062
+			expectedErrors: 0,
1063
+		},
1064
+		{
1065
+			name: "Expired cert reencrypt",
1066
+			route: &api.Route{
1067
+				Spec: api.RouteSpec{
1068
+					Host: "www.example.com",
1069
+					TLS: &api.TLSConfig{
1070
+						Termination:              api.TLSTerminationReencrypt,
1071
+						Certificate:              testCertificate,
1072
+						Key:                      testPrivateKey,
1073
+						CACertificate:            testCACertificate,
1074
+						DestinationCACertificate: testCACertificate,
1075
+					},
1076
+				},
1077
+			},
1078
+			expectedErrors: 0,
1079
+		},
1080
+		{
1081
+			name: "Expired cert invalid key",
1082
+			route: &api.Route{
1083
+				Spec: api.RouteSpec{
1084
+					Host: "www.example.com",
1085
+					TLS: &api.TLSConfig{
1086
+						Termination: api.TLSTerminationEdge,
1087
+						Certificate: testExpiredCertNoKey,
1088
+					},
1089
+				},
1090
+			},
1091
+			expectedErrors: 1,
1092
+		},
1093
+		{
1094
+			name: "Expired cert mismatched key",
1095
+			route: &api.Route{
1096
+				Spec: api.RouteSpec{
1097
+					Host: "www.example.com",
1098
+					TLS: &api.TLSConfig{
1099
+						Termination: api.TLSTerminationEdge,
1100
+						Certificate: testExpiredCertNoKey,
1101
+						Key:         testPrivateKey,
1102
+					},
1103
+				},
1104
+			},
1105
+			expectedErrors: 1,
1106
+		},
1107
+		{
1108
+			name: "Expired cert invalid key reencrypt",
1109
+			route: &api.Route{
1110
+				Spec: api.RouteSpec{
1111
+					Host: "www.example.com",
1112
+					TLS: &api.TLSConfig{
1113
+						Termination:              api.TLSTerminationReencrypt,
1114
+						Certificate:              testExpiredCertNoKey,
1115
+						DestinationCACertificate: testExpiredCertNoKey,
1116
+					},
1117
+				},
1118
+			},
1119
+			expectedErrors: 1,
1120
+		},
1121
+		{
1122
+			name: "Expired cert with a different route host",
1123
+			route: &api.Route{
1124
+				Spec: api.RouteSpec{
1125
+					Host: "think.different.test",
1126
+					TLS: &api.TLSConfig{
1127
+						Termination:   api.TLSTerminationEdge,
1128
+						Certificate:   testCertificate,
1129
+						Key:           testPrivateKey,
1130
+						CACertificate: testCACertificate,
1131
+					},
1132
+				},
1133
+			},
1134
+			expectedErrors: 0,
1135
+		},
1136
+		{
1137
+			name: "self-signed cert",
1138
+			route: &api.Route{
1139
+				Spec: api.RouteSpec{
1140
+					Host: "self.signer.test",
1141
+					TLS: &api.TLSConfig{
1142
+						Termination: api.TLSTerminationReencrypt,
1143
+						Certificate: testSelfSignedCert,
1144
+						Key:         testSelfSignedKey,
1145
+
1146
+						DestinationCACertificate: testSelfSignedCert,
1147
+					},
1148
+				},
1149
+			},
1150
+			expectedErrors: 0,
1151
+		},
1152
+		{
1153
+			name: "self-signed cert with different host",
1154
+			route: &api.Route{
1155
+				Spec: api.RouteSpec{
1156
+					Host: "different.co.us",
1157
+					TLS: &api.TLSConfig{
1158
+						Termination: api.TLSTerminationEdge,
1159
+						Certificate: testSelfSignedCert,
1160
+						Key:         testSelfSignedKey,
1161
+					},
1162
+				},
1163
+			},
1164
+			expectedErrors: 0,
1165
+		},
1166
+		{
1167
+			name: "future validity date 2038 cert",
1168
+			route: &api.Route{
1169
+				Spec: api.RouteSpec{
1170
+					Host: "self.signer.test",
1171
+					TLS: &api.TLSConfig{
1172
+						Termination: api.TLSTerminationEdge,
1173
+						Certificate: testValidInFutureCert,
1174
+						Key:         testValidInFutureKey,
1175
+					},
1176
+				},
1177
+			},
1178
+			expectedErrors: 0,
1179
+		},
1180
+		{
1181
+			name: "future validity date 2038 cert with different host",
1182
+			route: &api.Route{
1183
+				Spec: api.RouteSpec{
1184
+					Host: "www.in.the.future.test",
1185
+					TLS: &api.TLSConfig{
1186
+						Termination: api.TLSTerminationEdge,
1187
+						Certificate: testValidInFutureCert,
1188
+						Key:         testValidInFutureKey,
1189
+					},
1190
+				},
1191
+			},
1192
+			expectedErrors: 0,
1193
+		},
1194
+		{
1195
+			name: "cert with intermediate CA",
1196
+			route: &api.Route{
1197
+				Spec: api.RouteSpec{
1198
+					Host: "www.ca.test",
1199
+					TLS: &api.TLSConfig{
1200
+						Termination:   api.TLSTerminationEdge,
1201
+						Certificate:   testCertificateWithIntCA,
1202
+						Key:           testPrivateKeyWithIntCA,
1203
+						CACertificate: testIntCACertificateChain,
1204
+					},
1205
+				},
1206
+			},
1207
+			expectedErrors: 0,
1208
+		},
1209
+		{
1210
+			name: "cert with intermediate CA and diff host",
1211
+			route: &api.Route{
1212
+				Spec: api.RouteSpec{
1213
+					Host: "different.ca.test",
1214
+					TLS: &api.TLSConfig{
1215
+						Termination:   api.TLSTerminationEdge,
1216
+						Certificate:   testCertificateWithIntCA,
1217
+						Key:           testPrivateKeyWithIntCA,
1218
+						CACertificate: testIntCACertificateChain,
1219
+					},
1220
+				},
1221
+			},
1222
+			expectedErrors: 0,
1223
+		},
1224
+		{
1225
+			name: "expired cert with intermediate CA",
1226
+			route: &api.Route{
1227
+				Spec: api.RouteSpec{
1228
+					Host: "expired.ca.test",
1229
+					TLS: &api.TLSConfig{
1230
+						Termination:   api.TLSTerminationEdge,
1231
+						Certificate:   testExpiredCertificateWithIntCA,
1232
+						Key:           testExpiredCertificateKey,
1233
+						CACertificate: testIntCACertificateChain,
1234
+					},
1235
+				},
1236
+			},
1237
+			expectedErrors: 0,
1238
+		},
1239
+		{
1240
+			name: "expired cert with intermediate CA and diff host",
1241
+			route: &api.Route{
1242
+				Spec: api.RouteSpec{
1243
+					Host: "still.expired.test",
1244
+					TLS: &api.TLSConfig{
1245
+						Termination:   api.TLSTerminationEdge,
1246
+						Certificate:   testExpiredCertificateWithIntCA,
1247
+						Key:           testExpiredCertificateKey,
1248
+						CACertificate: testIntCACertificateChain,
1249
+					},
1250
+				},
1251
+			},
1252
+			expectedErrors: 0,
1253
+		},
1254
+		{
1255
+			name: "future valid cert with intermediate CA",
1256
+			route: &api.Route{
1257
+				Spec: api.RouteSpec{
1258
+					Host: "valid.in.the.future.ca.test",
1259
+					TLS: &api.TLSConfig{
1260
+						Termination:   api.TLSTerminationEdge,
1261
+						Certificate:   testFutureValidCertificateWithIntCA,
1262
+						Key:           testFutureValidCertificateKey,
1263
+						CACertificate: testIntCACertificateChain,
1264
+					},
1265
+				},
1266
+			},
1267
+			expectedErrors: 0,
1268
+		},
1269
+		{
1270
+			name: "future valid cert with intermediate CA and diff host",
1271
+			route: &api.Route{
1272
+				Spec: api.RouteSpec{
1273
+					Host: "future.valid.test",
1274
+					TLS: &api.TLSConfig{
1275
+						Termination:   api.TLSTerminationEdge,
1276
+						Certificate:   testFutureValidCertificateWithIntCA,
1277
+						Key:           testFutureValidCertificateKey,
1278
+						CACertificate: testIntCACertificateChain,
1279
+					},
1280
+				},
1281
+			},
1282
+			expectedErrors: 0,
1283
+		},
1284
+		{
1285
+			name: "invalid CA with csr",
1286
+			route: &api.Route{
1287
+				Spec: api.RouteSpec{
1288
+					Host: "invalid.ca.test",
1289
+					TLS: &api.TLSConfig{
1290
+						Termination:   api.TLSTerminationEdge,
1291
+						Certificate:   testCertificate,
1292
+						Key:           testPrivateKey,
1293
+						CACertificate: testInvalidCANoCert1,
1294
+					},
1295
+				},
1296
+			},
1297
+			expectedErrors: 2,
1298
+		},
1299
+		{
1300
+			name: "another invalid CA with private key",
1301
+			route: &api.Route{
1302
+				Spec: api.RouteSpec{
1303
+					Host: "another.invalid.ca.test",
1304
+					TLS: &api.TLSConfig{
1305
+						Termination:   api.TLSTerminationEdge,
1306
+						Certificate:   testCertificate,
1307
+						Key:           testPrivateKey,
1308
+						CACertificate: testInvalidCANoCert2,
1309
+					},
1310
+				},
1311
+			},
1312
+			expectedErrors: 2,
1313
+		},
1314
+		{
1315
+			name: "invalid CA malformed certificate",
1316
+			route: &api.Route{
1317
+				Spec: api.RouteSpec{
1318
+					Host: "malformed.ca.test",
1319
+					TLS: &api.TLSConfig{
1320
+						Termination:   api.TLSTerminationEdge,
1321
+						Certificate:   testCertificate,
1322
+						Key:           testPrivateKey,
1323
+						CACertificate: testInvalidCAMalformedCert,
1324
+					},
1325
+				},
1326
+			},
1327
+			expectedErrors: 2,
1328
+		},
1329
+		{
1330
+			name: "invalid destination CA with csr",
1331
+			route: &api.Route{
1332
+				Spec: api.RouteSpec{
1333
+					Host: "csr.destination.ca",
1334
+					TLS: &api.TLSConfig{
1335
+						Termination: api.TLSTerminationReencrypt,
1336
+						Certificate: testSelfSignedCert,
1337
+						Key:         testSelfSignedKey,
1338
+
1339
+						DestinationCACertificate: testInvalidCANoCert1,
1340
+					},
1341
+				},
1342
+			},
1343
+			expectedErrors: 1,
1344
+		},
1345
+		{
1346
+			name: "invalid destination CA with private key",
1347
+			route: &api.Route{
1348
+				Spec: api.RouteSpec{
1349
+					Host: "key.destination.ca",
1350
+					TLS: &api.TLSConfig{
1351
+						Termination: api.TLSTerminationReencrypt,
1352
+						Certificate: testSelfSignedCert,
1353
+						Key:         testSelfSignedKey,
1354
+
1355
+						DestinationCACertificate: testInvalidCANoCert1,
1356
+					},
1357
+				},
1358
+			},
1359
+			expectedErrors: 1,
1360
+		},
1361
+		{
1362
+			name: "malformed destination CA",
1363
+			route: &api.Route{
1364
+				Spec: api.RouteSpec{
1365
+					Host: "malformed.destination.ca",
1366
+					TLS: &api.TLSConfig{
1367
+						Termination: api.TLSTerminationReencrypt,
1368
+						Certificate: testSelfSignedCert,
1369
+						Key:         testSelfSignedKey,
1370
+
1371
+						DestinationCACertificate: testInvalidCAMalformedCert,
1372
+					},
1373
+				},
1374
+			},
1375
+			expectedErrors: 1,
1376
+		},
1034 1377
 	}
1035 1378
 
1036 1379
 	for _, tc := range tests {