package validation

import (
	"testing"

	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/intstr"

	"github.com/openshift/origin/pkg/route/api"
)

const (
	testExpiredCAUnknownCertificate = `-----BEGIN CERTIFICATE-----
MIIDIjCCAgqgAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
ZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0ExGjAYBgNVBAMMEXd3
dy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu
Y29tMB4XDTE2MDExMzE5NDA1N1oXDTI2MDExMDE5NDA1N1owfDEYMBYGA1UEAxMP
d3d3LmV4YW1wbGUuY29tMQswCQYDVQQIEwJTQzELMAkGA1UEBhMCVVMxIjAgBgkq
hkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20xEDAOBgNVBAoTB0V4YW1wbGUx
EDAOBgNVBAsTB0V4YW1wbGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM0B
u++oHV1wcphWRbMLUft8fD7nPG95xs7UeLPphFZuShIhhdAQMpvcsFeg+Bg9PWCu
v3jZljmk06MLvuWLfwjYfo9q/V+qOZVfTVHHbaIO5RTXJMC2Nn+ACF0kHBmNcbth
OOgF8L854a/P8tjm1iPR++vHnkex0NH7lyosVc/vAgMBAAGjDTALMAkGA1UdEwQC
MAAwDQYJKoZIhvcNAQEFBQADggEBADjFm5AlNH3DNT1Uzx3m66fFjqqrHEs25geT
yA3rvBuynflEHQO95M/8wCxYVyuAx4Z1i4YDC7tx0vmOn/2GXZHY9MAj1I8KCnwt
Jik7E2r1/yY0MrkawljOAxisXs821kJ+Z/51Ud2t5uhGxS6hJypbGspMS7OtBbw7
8oThK7cWtCXOldNF6ruqY1agWnhRdAq5qSMnuBXuicOP0Kbtx51a1ugE3SnvQenJ
nZxdtYUXvEsHZC/6bAtTfNh+/SwgxQJuL2ZM+VG3X2JIKY8xTDui+il7uTh422lq
wED8uwKl+bOj6xFDyw4gWoBxRobsbFaME8pkykP1+GnKDberyAM=
-----END CERTIFICATE-----`

	testExpiredCertPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDNAbvvqB1dcHKYVkWzC1H7fHw+5zxvecbO1Hiz6YRWbkoSIYXQ
EDKb3LBXoPgYPT1grr942ZY5pNOjC77li38I2H6Pav1fqjmVX01Rx22iDuUU1yTA
tjZ/gAhdJBwZjXG7YTjoBfC/OeGvz/LY5tYj0fvrx55HsdDR+5cqLFXP7wIDAQAB
AoGAfE7P4Zsj6zOzGPI/Izj7Bi5OvGnEeKfzyBiH9Dflue74VRQkqqwXs/DWsNv3
c+M2Y3iyu5ncgKmUduo5X8D9To2ymPRLGuCdfZTxnBMpIDKSJ0FTwVPkr6cYyyBk
5VCbc470pQPxTAAtl2eaO1sIrzR4PcgwqrSOjwBQQocsGAECQQD8QOra/mZmxPbt
bRh8U5lhgZmirImk5RY3QMPI/1/f4k+fyjkU5FRq/yqSyin75aSAXg8IupAFRgyZ
W7BT6zwBAkEA0A0ugAGorpCbuTa25SsIOMxkEzCiKYvh0O+GfGkzWG4lkSeJqGME
keuJGlXrZNKNoCYLluAKLPmnd72X2yTL7wJARM0kAXUP0wn324w8+HQIyqqBj/gF
Vt9Q7uMQQ3s72CGu3ANZDFS2nbRZFU5koxrggk6lRRk1fOq9NvrmHg10AQJABOea
pgfj+yGLmkUw8JwgGH6xCUbHO+WBUFSlPf+Y50fJeO+OrjqPXAVKeSV3ZCwWjKT4
9viXJNJJ4WfF0bO/XwJAOMB1wQnEOSZ4v+laMwNtMq6hre5K8woqteXICoGcIWe8
u3YLAbyW/lHhOCiZu2iAI8AbmXem9lW6Tr7p/97s0w==
-----END RSA PRIVATE KEY-----`

	testCertificate = `-----BEGIN CERTIFICATE-----
MIICwjCCAiugAwIBAgIBATANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEL
MAkGA1UECAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hp
ZnQzIHRlc3QgQ0ExFzAVBgNVBAMMDmhlYWRlci50ZXN0IENBMB4XDTE2MDMxMjA0
MjEwM1oXDTM2MDMxMjA0MjEwM1owWDEUMBIGA1UEAwwLaGVhZGVyLnRlc3QxCzAJ
BgNVBAgMAkNBMQswCQYDVQQGEwJVUzERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNV
BAsMCk9wZW5TaGlmdDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD0
XEAzUMflZy8zluwzqMKnu8jYK3yUoEGLN0Bw0A/7ydno1g0E92ee8M9p59TCCWA6
nKnt1DEK5285xAKs9AveutSYiDkpf2px59GvCVx2ecfFBTECWHMAJ/6Y7pqlWOt2
hvPx5rP+jVeNLAfK9d+f57FGvWXrQAcBnFTegS6J910kbvDgNP4Nerj6RPAx2UOq
6URqA4j7qZs63nReeu/1t//BQHNokKddfxw2ZXcL/5itgpPug16thp+ugGVdjcFs
aasLJOjErUS0D+7bot98FL0TSpxWqwtCF117bSLY7UczZFNAZAOnZBFmSZBxcJJa
TZzkda0Oiqo0J3GPcZ+rAgMBAAGjDTALMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEL
BQADgYEACkdKRUm9ERjgbe6w0fw4VY1s5XC9qR1m5AwLMVVwKxHJVG2zMzeDTHyg
3cjxmfZdFU9yxmNUCh3mRsi2+qjEoFfGRyMwMMx7cduYhsFY3KA+Fl4vBRXAuPLR
eCI4ErCPi+Y08vOto9VVXg2f4YFQYLq1X6TiXD5RpQAN0t8AYk4=
-----END CERTIFICATE-----`

	testPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA9FxAM1DH5WcvM5bsM6jCp7vI2Ct8lKBBizdAcNAP+8nZ6NYN
BPdnnvDPaefUwglgOpyp7dQxCudvOcQCrPQL3rrUmIg5KX9qcefRrwlcdnnHxQUx
AlhzACf+mO6apVjrdobz8eaz/o1XjSwHyvXfn+exRr1l60AHAZxU3oEuifddJG7w
4DT+DXq4+kTwMdlDqulEagOI+6mbOt50Xnrv9bf/wUBzaJCnXX8cNmV3C/+YrYKT
7oNerYafroBlXY3BbGmrCyToxK1EtA/u26LffBS9E0qcVqsLQhdde20i2O1HM2RT
QGQDp2QRZkmQcXCSWk2c5HWtDoqqNCdxj3GfqwIDAQABAoIBAEfl+NHge+CIur+w
MXGFvziBLThFm1NTz9U5fZFz9q/8FUzH5m7GqMuASVb86oHpJlI4lFsw6vktXXGe
tbbT28Y+LJ1wv3jxT42SSwT4eSc278uNmnz5L2UlX2j6E7CA+E8YqCBN5DoKtm8I
PIbAT3sKPgP1aE6OuUEFEYeidOIMvjco2aQH0338sl6cObkQFEgnWf2ncun3KGnb
s+dMO5EdYLo0rOdDXY88sElfqiNYYl/FRu9O3OfqHvScA5uo9FlIhukcrRkbjFcq
j/7k4tt0iLs9B2j+4ihBWYo5eRFIde4Izj6a6ArEk0ShEUvwlZBuGMM/vs+jvbDK
l3+0NpECgYEA/+qxwvOGjmlYNKFK/rzxd51EnfCISnV+tb17pNyRmlGToi1/LmmV
+jcJfcwlf2o8mTFn3xAdD3fSaHF7t8Li7xDwH2S+sSuFE/8bhgHUvw1S7oILMYyO
hO6sWG+JocMhr8IejaAnQxav9VvP01YDfw/XBB0O1EIuzzr2KHq+AGMCgYEA9HCY
JGTcv7lfs3kcCAkDtjl8NbjNRMxRErG0dfYS+6OSaXOOMg1TsaSNEgjOGyUX+yQ4
4vtKcLwHk7+qz3ZPbhS6m7theZG9jUwMrQRGyCE7z3JUy8vmV/N+HP0V+boT+4KM
Tai3+I3hf9+QMHYx/Z/VA0K6f27LwP+kEL9C8hkCgYEAoiHeXNRL+w1ihHVrPdgW
YuGQBz/MGOA3VoylON1Eoa/tCGIqoQzjp5IWwUwEtaRon+VdGUTsJFCVTPYYm2Ms
wqjIeBsrdLNNrE2C8nNWhXO7hr98t/eEk1NifOStHX6yaNdi4/cC6M4GzDtOf2WO
8YDniAOg0Xjcjw2bxil9FmECgYBuUeq4cjUW6okArSYzki30rhka/d7WsAffEgjK
PFbw7zADG74PZOhjAksQ2px6r9EU7ZInDxbXrmUVD6n9m/3ZRs25v2YMwfP0s1/9
LjLr2+PsikMu/0VkaGaAmtCyNoMSPicoXX86VH5zgejHlnCVcO9oW1NkdBLNdhML
4+ZI8QKBgQDb+SH7i50Yu3adwvPkDSp3ACCzPoHXno79a7Y5S2JzpFtNq+cNLWEb
HP8gHJSZnaGrLKmjwNeQNsARYajKmDKO5HJ9g5H5Hae8enOb2yie541dneDT8rID
4054dMQJnijd8620yf8wiNy05ZPOQQ0JvA/rW3WWZc5PGm8c2PsVjg==
-----END RSA PRIVATE KEY-----`

	testCACertificate = `-----BEGIN CERTIFICATE-----
MIIClDCCAf2gAwIBAgIJAPU57OGhuqJtMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxGzAZBgNVBAsM
Ek9wZW5TaGlmdDMgdGVzdCBDQTEXMBUGA1UEAwwOaGVhZGVyLnRlc3QgQ0EwHhcN
MTYwMzEyMDQyMTAzWhcNMzYwMzEyMDQyMTAzWjBjMQswCQYDVQQGEwJVUzELMAkG
A1UECAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hpZnQz
IHRlc3QgQ0ExFzAVBgNVBAMMDmhlYWRlci50ZXN0IENBMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQCsdVIJ6GSrkFdE9LzsMItYGE4q3qqSqIbs/uwMoVsMT+33
pLeyzeecPuoQsdO6SEuqhUM1ivUN4GyXIR1+aW2baMwMXpjX9VIJu5d4FqtGi6SD
RfV+tbERWwifPJlN+ryuvqbbDxrjQeXhemeo7yrJdgJ1oyDmoM5pTiSUUmltvQID
AQABo1AwTjAdBgNVHQ4EFgQUOVuieqGfp2wnKo7lX2fQt+Yk1C4wHwYDVR0jBBgw
FoAUOVuieqGfp2wnKo7lX2fQt+Yk1C4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOBgQA8VhmNeicRnKgXInVyYZDjL0P4WRbKJY7DkJxRMRWxikbEVHdySki6
jegpqgJqYbzU6EiuTS2sl2bAjIK9nGUtTDt1PJIC1Evn5Q6v5ylNflpv6GxtUbCt
bGvtpjWA4r9WASIDPFsxk/cDEEEO6iPxgMOf5MdpQC2y2MU0rzF/Gg==
-----END CERTIFICATE-----`

	testDestinationCACertificate = testCACertificate

	testValidInFutureCert = `-----BEGIN CERTIFICATE-----
MIIDjzCCAnegAwIBAgIJAJcdKWMFNUEGMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsM
ClNlbGZTaWduZXIxGTAXBgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwIBcNMzgwMTAx
MDgwMDAyWhgPMjA1ODAxMDEwODAwMDJaMF0xCzAJBgNVBAYTAlVTMQswCQYDVQQI
DAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsMClNlbGZTaWduZXIxGTAX
BgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDBAtP5vHkVS9qZNmI9QKj7B/ATt2+Fw+f4xD+6Q2+1sOkLH3x6+D85
5A+xAAvQdz5qf+yfvtNOhWqmIG5Zh0TzaiA5lw2U0YL4FT4Z4nbYAPMO45lctvRH
nXBeSO7N/JiFBlvMPqP4gsimstEgiNm225KlQRHOqMfOEAC15pyUrE643Gs0DCVR
L1tZuwdfBUpybxAPDWpgx7CNTc0beuNXooroMU1dCdM+BjYHYfSCnoNwa4qp130e
6vRWnzlhfXbFTsCVCe4y6edF/+M3PegIx0+PhkgeSOxd2+nBsiatrG5ZyiP5iaRK
2278nFERyUQ1SbhicDrhlU9TQAMcTMAvAgMBAAGjUDBOMB0GA1UdDgQWBBQ28jRf
N/CCqVyOU8mOZpG8ow86WjAfBgNVHSMEGDAWgBQ28jRfN/CCqVyOU8mOZpG8ow86
WjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC+Nu8pEUB7agGHUU/e
1NHI84guwKKA2qNnkQZKn6h49AA/bPjKr9SFQHNxFFMyrVInt1Ez9sRNviArQc+w
DToHY+T/3WUVcQIQnRW3m4r6UUsxKZjtrSBD2Dhr6nL9hVVtGIfimuuxxJt1JItJ
UaOY+Kq4gtWOJMcV5xTEaPmkphAgwoZzjZj7Z9SZwVLGopJa8kB3EvlkxUO3DmSp
9Lq3AhHRYgwWcjcd9UC9NyXQ9hBTV2iPBSvc2I4vmYQwnOutBEeNM0IPQQk7f2VL
fKSS26HocZpiN0e7vO0XoJfh4VkOIn7BGNwxiDr9cIRL4ZHhZ0/kRQuXCHHYbTdq
9mKv
-----END CERTIFICATE-----`

	testValidInFutureKey = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBAtP5vHkVS9qZ
NmI9QKj7B/ATt2+Fw+f4xD+6Q2+1sOkLH3x6+D855A+xAAvQdz5qf+yfvtNOhWqm
IG5Zh0TzaiA5lw2U0YL4FT4Z4nbYAPMO45lctvRHnXBeSO7N/JiFBlvMPqP4gsim
stEgiNm225KlQRHOqMfOEAC15pyUrE643Gs0DCVRL1tZuwdfBUpybxAPDWpgx7CN
Tc0beuNXooroMU1dCdM+BjYHYfSCnoNwa4qp130e6vRWnzlhfXbFTsCVCe4y6edF
/+M3PegIx0+PhkgeSOxd2+nBsiatrG5ZyiP5iaRK2278nFERyUQ1SbhicDrhlU9T
QAMcTMAvAgMBAAECggEAWYJvPd0bJjY0XWNsMc3fz/NBclNao+VTmfmhOEd38gHm
QaNLflfMMpPCdyp3UClMx+UlnnvH0R1sdTiLFHf4EQ7BfRPBV6fGHjjzwNtWlBv0
nI4OnIG4TdIEv6UBIoQnU2G8hr7yGhjE5xH8jCMLHJM9see4U2fQqY6gVbtqGEP1
w29IhoYcCPsqIhBYlmOaxvEBA12SKjZEaLT4dTImcvNsYuNAHbKpS1m6nA7KaqLN
hkFJ5oKPlsMT2bFCaHzB7Es/90FgkLk3EULx9G5uV+26FcovhSKI/j4kkBZ57BZG
rGuMScjxGLolY7dv0PlQvSzDmsA4EEzEQECy5kJFAQKBgQDv7jhEBsuKs9t6UOBF
QBsmAsTs5I9UoQd5ZBy1QoOxmN5aLjNNfFd86LBomC/oF0AZpEKfHA+Ha8ttdJNX
vjkSIbfJKYfd4J/A4J7Wna3RPExu0wqN3g2xiPNeyYmzd8H2ER1t850YzFbT8f7M
pSQbbqWkjLzRw3wUBVQao/PlrwKBgQDN8CPWZuKzIhSsBLKtG41evnSCMOoSWRRQ
VmLnxIa7x8Ng/v8T39S4Tzpx50uq0ZAoegmI5aMvJEwayMShZdHt++DIjNfnayXS
yQ6Cr+FqObeZX1B25eChiyN/O/RPx1zJ6eW0FUKlTheYIv4u+D0AwzmyaySeAEyo
ZhiOnS3tgQKBgD9y3NhIf70fURQonRZTHJrRsqf+zVSQ/PwCGIFqpI7roSlx/Ekq
b6xtkHEohcq3k1D0mlWfQxAJ1pMMeAaFHGyKFCMTY4WuaDDGddrFefjSHFhWYP0h
Ure3Qry3ST33lohvADxaZxnut6t23G3b4g+LFCzOtwQ10PMucY5V+yKrAoGAfAyc
OckN46Oy2g+WZYoENT76RXYbeWPpRZ9TwpJyKmjheur/UcRxiXhIF1ahEMtdT9R7
K9hP3NS7dyLatvHza6xesc+NOlwjk34C3Jv/Z5JO0vdEK+q6zfRXNIwz1V6cuQ/I
ixqHY7XPppfljvt/G5d9iMjbbMV3Z7TgM//gK4ECgYBkSU6B77LnXtb0QPTsBdq6
7hvEPH4lhnpcXRemfq3Q0/GYeACSoAPUGxy8LwT50pagaIf6ZG1esMFiALFsJWer
XdzRo+/NffATcVvoof1Gnjhe/qt0kby66wR42JJMK/q4BKAN0kitfkzOPC4HVoF4
DOGy/dMN+k0W2RgJ5JKR3g==
-----END PRIVATE KEY-----`

	testSelfSignedCert = `-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIJAKM4rr3VRQARMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxEzARBgNVBAsM
ClNlbGZTaWduZXIxGTAXBgNVBAMMEHNlbGYuc2lnbmVyLnRlc3QwHhcNMTYxMTAx
MjEzNzU4WhcNMzYxMTAxMjEzNzU4WjBdMQswCQYDVQQGEwJVUzELMAkGA1UECAwC
Q0ExETAPBgNVBAoMCFNlY3VyaXR5MRMwEQYDVQQLDApTZWxmU2lnbmVyMRkwFwYD
VQQDDBBzZWxmLnNpZ25lci50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAvF0Rw580En6xCPvoLoMBUzI9HD5D7UFycpOG/qL5ZtmhzYR62WBKhc/C
ysWxRL3+GFD9m5zoDuB2qGMohBfsIVF2TX7oqgovKkX7BDO92vrDtGJo/QJnUhku
pASTmAgPMacxwvSQM5yJgb5GNtkvoulXbE31S5VDamcsH+ej0VKYKKXPtbFDBMxx
NysoUCCb1SiPBicgx9V69VlU6UeataNHz0oyxH9ijCYShePbk0TQRXlyTzdMIaL0
AeWLlngmlVYP1RoZXGNupX5R8EAdrc5nRV5+epkJDzOHfxE3bbSM8fzPcI7KyHkp
sA3PBPf8uUFfGNGpt4ubc4Kp0yL1vwIDAQABo1AwTjAdBgNVHQ4EFgQUNvPQ5ChF
G8UpyLlnVlrXmN9Oi0QwHwYDVR0jBBgwFoAUNvPQ5ChFG8UpyLlnVlrXmN9Oi0Qw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAhOCb94qvpwad4ZyGfeV9
aE/9wIGT/xs0KnV7wS1OopGnglcgogns5Vcs2rzBrcN04n5EYZ+V7naMjReVhpBv
gJ26YYfnitrGkWazncGW1BYI7fXAdU2cBJ+LLCbZX1zz9BqBW5ldvbk/XWTg4ols
29j8kpLwA2UEApE25xWmXBBHyDIzvNzyiwswrdo26BUZdHCA/pplPFpz6UEYLYEX
Bv95o5CLf2CQIxC6uE7BENrQo7ItwHvJoYlkdkYil3V/Qx25YafulH+wbL6ccN6F
fjEOS33MDf9AIbgSgiPlGSwkikVjy73ADWWdQCOJhrMUnSnqE05gCRd5qIggACf1
0A==
-----END CERTIFICATE-----`

	testSelfSignedKey = `-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC8XRHDnzQSfrEI
++gugwFTMj0cPkPtQXJyk4b+ovlm2aHNhHrZYEqFz8LKxbFEvf4YUP2bnOgO4Hao
YyiEF+whUXZNfuiqCi8qRfsEM73a+sO0Ymj9AmdSGS6kBJOYCA8xpzHC9JAznImB
vkY22S+i6VdsTfVLlUNqZywf56PRUpgopc+1sUMEzHE3KyhQIJvVKI8GJyDH1Xr1
WVTpR5q1o0fPSjLEf2KMJhKF49uTRNBFeXJPN0whovQB5YuWeCaVVg/VGhlcY26l
flHwQB2tzmdFXn56mQkPM4d/ETdttIzx/M9wjsrIeSmwDc8E9/y5QV8Y0am3i5tz
gqnTIvW/AgMBAAECggEBAKkJqJByRau3UC5syj87R6wesKKw6gp3qjpSVFodbU20
TrT9h7Wd6SLOgNOxt9Sl3+p4fC7zD3mSTEnuuoRYZ4q67Ty8gBVgkFUSeiKaQG3M
jmZJzkgHqSsO+EEu7jkIOoJntYtsKCB5ARmS5LYCD/LWDqNeDpymtdo9/mYfXW7R
cwCIbv0mXjybx4YUKLvVAstszmvr4uZXPqBlceaBv4jTx2xZlzCM6WAgMbjJM3vS
3BLFcICy3fhXSzEtaAefTnFVRzXAUZjgKn73JpHsPqScfFw4Q/eR/AN/jpjPkrsx
scRFqpRFEVO3/9A+PoFzL3ofaD6pTPVdCYdQCtA14iECgYEA4XHWGNUO7+HhAxb8
2XhtkuvDN3HH/QswCqI5zyXnYoE47OD3stLD1YsDl2wm+XCl5/N5u0qx2Hh0956q
Zwk2BBZnHU4yfLsCieSiyDff8ulJMX1Xh0Ssk3bmDucMjatmfWXrMsMVhB+Tm+oA
yhMGe3rKKk4aGMfEQ2vAbFRwuDECgYEA1eSk7bqJeRn4Y0iW0I4w09CJ9DlmzR/S
3VDEmbHcny4noEHRNPMacjDvNuj04XOlbsm4R785M4WRgoZxQXDpXSfL23UFbmPU
yxxNYw3dc10q2u+PjzXc6bzv/qYsNuc6SmNeUT1puI9SnEEYT7+6CaeHeJB4W1RL
B2pSEqmXAO8CgYEAonH7WmNTYwh4sVhEE5OSKPaW8QGcoDoKgO8KBriCNNl2IkGs
Wf9Cu0Fy8g4tOzmvYiZvhcQ5yAhsB+0dTic189YMsPIisPuzxZaosOqKBSeR5QYz
JrYWQB/Bf+V+hyqFLEBfLHGjtFNockU4EmOJHTqKJ9elOEvhoM8olSZ3HlECgYAw
114F3uOHYLPEUA4IH3/sziDCQN1Fl6+507ig8+lR++MWiBDyi1SNoLjvC/DnDlZH
Xw6Sa4rvRd+9M1/nNpZDLFQzj5wm4er0Wkkdhkv8DNk9Vxir9fu07+zJdD6CZvh7
hgdCe8iJWUje30pi43/itnuLv0mMaUocrl2BX3JYxwKBgQC5+usY3fF/q8wLYGgo
BRjkyMvkeRgidMwJMnimflZ7X9Svfh4gw7JYub8Vksys5RYQ/3wSZuwy2dxamCxr
H6e+rtFlOu/BZSBUUgcOJ4xSDUilztVSMGHK7AxhBGlBHzPRwY8bjQfMaODs9pD8
qOFcy/8ogwZdP9nTV73O2wG56g==
-----END PRIVATE KEY-----`

	testExpiredCertNoKey = `-----BEGIN CERTIFICATE-----
MIIDIjCCAgqgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBoTELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAlNDMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl
ZmF1bHQgQ29tcGFueSBMdGQxEDAOBgNVBAsMB1Rlc3QgQ0ExGjAYBgNVBAMMEXd3
dy5leGFtcGxlY2EuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu
Y29tMB4XDTE1MDExMjE0MTk0MVoXDTE2MDExMjE0MTk0MVowfDEYMBYGA1UEAwwP
d3d3LmV4YW1wbGUuY29tMQswCQYDVQQIDAJTQzELMAkGA1UEBhMCVVMxIjAgBgkq
hkiG9w0BCQEWE2V4YW1wbGVAZXhhbXBsZS5jb20xEDAOBgNVBAoMB0V4YW1wbGUx
EDAOBgNVBAsMB0V4YW1wbGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrv
gu6ZTTefNN7jjiZbS/xvQjyXjYMN7oVXv76jbX8gjMOmg9m0xoVZZFAE4XyQDuCm
47VRx5Qrf/YLXmB2VtCFvB0AhXr5zSeWzPwaAPrjA4ebG+LUo24ziS8KqNxrFs1M
mNrQUgZyQC6XIe1JHXc9t+JlL5UZyZQC1IfaJulDAgMBAAGjDTALMAkGA1UdEwQC
MAAwDQYJKoZIhvcNAQEFBQADggEBAFCi7ZlkMnESvzlZCvv82Pq6S46AAOTPXdFd
TMvrh12E1sdVALF1P1oYFJzG1EiZ5ezOx88fEDTW+Lxb9anw5/KJzwtWcfsupf1m
V7J0D3qKzw5C1wjzYHh9/Pz7B1D0KthQRATQCfNf8s6bbFLaw/dmiIUhHLtIH5Qc
yfrejTZbOSP77z8NOWir+BWWgIDDB2//3AkDIQvT20vmkZRhkqSdT7et4NmXOX/j
jhPti4b2Fie0LeuvgaOdKjCpQQNrYthZHXeVlOLRhMTSk3qUczenkKTOhvP7IS9q
+Dzv5hqgSfvMG392KWh5f8xXfJNs4W5KLbZyl901MeReiLrPH3w=
-----END CERTIFICATE-----`

	testIntCACertificateChain = `-----BEGIN CERTIFICATE-----
MIIFqjCCA5KgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNo
aWZ0MyB0ZXN0IENBMRQwEgYDVQQDDAtyb290LmNhLm9yZzAeFw0xNjExMDMwMDE3
MTNaFw0zNjExMDMwMDE3MTNaMGgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTER
MA8GA1UECgwIU2VjdXJpdHkxGzAZBgNVBAsMEk9wZW5TaGlmdDMgdGVzdCBDQTEc
MBoGA1UEAwwTaW50ZXJtZWRpYXRlLmNhLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBALrPYF7ah6vwSknXQj9IeoCXGnsMtin0UCFb5jsvDnoKrYqh
46/XMfiPGz/gr6wqkAis2n31/7H2oHUxgI5AjnWOzpyRRl2/NurVXYDaLCKiMsTm
nt54d90VG5Yl4oFwzT7Az2xBBeJMTUyW4tB+66RCenlAq3AxO3Sp50Z4N1Cm34qI
hg0/Wbs6VuzdKsyU5Tux0LrplF656A9BkpcOqvJmO6g9dKTA4KmhRyC+fxAk0p8d
+WLuvumYQ19ta2ZjJxdCoVpaNMIsQ+ZyUTuq2VtIFLJVl/7Q5oZX1LDurtf0Ho/O
TQq4L4sWQjYFXTCibU+logeg+qhPtO3kSuXcJBlaO1NqteA8sVQ2AQY48HNIr8VN
ZsGFX+gmAZYesL62kFckKm39fsbuYQ/4mPHdgzYCuiNGFceoHcA/RBc42A4F7v9X
Owm/OVccOnQTAZsZUUKj5cq16Is8K8j7hYJPIyfR2RIE7X52C1U7KLyra+Ld20ix
JO1j59TmyQhBElEz1OZq3qX2TbpHG1sVjHyhZmbAjJDwpXCwZOPt/Icg9Qs6125X
Rrr1zyTU/jr3TBBmdcBn4BFvtkWvAGndzNC1kun05vwEfqyQIfY/hbAWyZlPkWqP
DETVGCN7ZQ21BPSaDsT29mD519FyMAbPAZxlou+yk//VeSgRh+N58SFKU/G/AgMB
AAGjZjBkMB0GA1UdDgQWBBSJpW4a7QM2MkPIdhDrAIEEGc2RgzAfBgNVHSMEGDAW
gBRS9nnAAIUE7lGEcTXwhJ6lsndnSTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud
DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAcKzpwgek+Bq+xLo77wQAL84V
ezU1d+/bHWn/1pICbBpAmK6uuyeAKal/gZv7LVcpue4Wk+/WbAx8jUXi53pN7Qp+
oYMLF4eXiqolOO9lgSEoYyiO6qjXWKuiFlGOYsDzLeEWv6FhP3gpMXvMNidSFmLt
qsUcsEtlFU9+Aub6msOsjKdsSQQMnj0Pfd4m35D6T3ZqW7swaEcvd72kbT6rkI2T
aVt6dfEQS1qQrMOBYTr/5DUxkCaysYOGAd/eqfK3h00JcsllpoM1F8nYKSqrilLI
Zts8rZg7GFbF76vJTEsYagrarhEg76p4Hdl2ZRr54+JA5Y7IEJBtA7UscXFiYR03
+2+1x9bYIcXR3uDa2WK20NsbDznO8rfbrX5m/X9McT7fbn+TE9MjKGaOMqwGoZdS
1hxwUeDqu6hf5qdETkqCaKCjIGBb8fg1cKmQXAAKTIS+6iI3iaF/bRTTa3gICZN7
FDdPRjMJDZ/k4cicAipzjKx2NQkiA59Q8z2aa5ahTWF2kz0YcdHtVDjIeDDR/KzT
EodWld0L6StnRQ1kAIif0wAuQ//JVOBpCi93wykYPbdJ15A8qmqiS4bAbFdKCXph
sP3gunYZT8RCrfAqJG/Is1RgChq2USckxvD4h8Q65J4VVRDkxvuLpjSh8ZJlI1xG
r2RUXNnvSmi8ubzDBls=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFpjCCA46gAwIBAgIJANRKflwkpS0cMA0GCSqGSIb3DQEBCwUAMGAxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxGzAZBgNVBAsM
Ek9wZW5TaGlmdDMgdGVzdCBDQTEUMBIGA1UEAwwLcm9vdC5jYS5vcmcwHhcNMTYx
MTAzMDAxNzEyWhcNMzYxMTAzMDAxNzEyWjBgMQswCQYDVQQGEwJVUzELMAkGA1UE
CAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hpZnQzIHRl
c3QgQ0ExFDASBgNVBAMMC3Jvb3QuY2Eub3JnMIICIjANBgkqhkiG9w0BAQEFAAOC
Ag8AMIICCgKCAgEAojn1uV7bB37377bjZdwFvZpdk69fUgYGM2MlT/bdKGgLFXIx
8kUSjk8H84RiiZiPlyE+orTOdzv8umicW92qGF1y+rlLIAgTCdpEaiRvELCD4hsl
5fLK2686SbB1lQZzhi1ounFph7q0R6plfG762xdnGMLnsXDaYYz1kWWyDbJbd5DL
grttZxfDsRwIDwiHVEsu5thOkL/C06/ipHQC9iDgnaeIeAp2UhLUblitgoeBLKLH
+zu4cgKvQnSosIBIT11mQGrPe3B72/HBXSNAl7yuiCYnTantnLQxEHV4y9iQzmZ+
/F9ryZuBWMU49KKA952C5InDtjAjZjgdoqPRmiHMDoYqlnZdoMgYZPmEGhCnNMni
pvB6qSwFa6l1xC4nlcYjyfkZzdg30P7dZwbtwG52e8tXHxwTm9LKbb3sCj2EAZSo
6h87NKxZX4o1WZbwPaNPVEVrlev7mdJsjZt9Qthzurm1Vcs9b1kDwEmyty4ssmPW
F+UhPxSDZR28utTzFv99g94qmnjxzBoiAip2wAGdU4tzc1Cvh1njQYXhElJZpjlU
RBQAeRvhKRQjnuripuZvTs29sIzLRuBKuY2u4xkDXVpvl3H+3CoFsN9oQ38qyZo/
uEeMHLuSMVDQycKHXJolMZOTHdB2O6CbhmYOkViG2cGHBpswLZ4IlgJ6ARsCAwEA
AaNjMGEwHQYDVR0OBBYEFFL2ecAAhQTuUYRxNfCEnqWyd2dJMB8GA1UdIwQYMBaA
FFL2ecAAhQTuUYRxNfCEnqWyd2dJMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAcDKBGtSxnt/hZpRjrti2NDlwcn9SS
ojkkKHnu4GdtO+8AHPfCHfUA5Ba1ydiddpxcR3tvjPCsfWTtmpoQ4wVFPGsMELqu
elC/H3jEZxn1I+FdLFRB3QvBFQ3VvtbS6NemvMupWBxmimlOmp0woMW3wfH9MnPt
EF5OFkcjhRKq1/bkzpKLkBpCQ/IIAm9ATgJmc9rADQxXbGvwHVpjORLOD55jOAl0
m5nFvawpKnJUVGKQ40MbHAz6tI5crSFJnA7VUWPfeCuQT04X9t3GNARUYnFxNBex
/K7A/Of6CPqMNlXgeYieQyVJ/rbNtDLXne8uZhSUGd55B35QJ1HUxOJ/KcTC1Fw9
1jUBMkyco1wBvv/xtBUulzKpMOh7Dq5ABGa+lh9mANP822CmLO1DrQDmsjPiTEU0
n81Ir0FXVt12gXYtmWqDyILPrbcKImuiSojoH3rAD2sdnTNmgFQcBWQj/6TG+5Tm
tSefyc9/CCsmIw0zrOVLfxs23k/Wts1acqTldWP5dY3MEyWrVOW6XakgYvPHdZa2
AkefO2oUf6dnu9JScZiEztIcr8IMfY7q+YOQKjDuH3gG2+SE6PPC46ajq0MoFeJU
qA0au8ygoLaCLhYK+HnzGRVAYqc4hb4LKNhIbAveHLOTUKNeAFADxq8REsPkpeM7
G0k/6pTJTZwfsA==
-----END CERTIFICATE-----`

	testCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
MIIGbzCCBFegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNo
aWZ0MyB0ZXN0IENBMRwwGgYDVQQDDBNpbnRlcm1lZGlhdGUuY2Eub3JnMB4XDTE2
MTEwMzAwMTcxNFoXDTM2MTEwMzAwMTcxNFowYDELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNoaWZ0MyB0
ZXN0IENBMRQwEgYDVQQDDAt3d3cuY2EudGVzdDCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAJjnlw48H8YdfeFR2mKym1a77wbGL4MAysLA/V7bmQdiHbQh
wMEINrEsWTIOnldT5+P1iNA10/wDz21XWXPSc+hp+O6wr+n/QjFUv5arKfeM2Nc3
7A+j8lTi83XXryLUNYrRVwX7qggBzCjWT1bKHYdZoi5YAvC/jsTrVtWdx/q67h66
jnKPxvLZVWov28azVfvrK9sP67osKIaT79lOS7jCJhgtpaQ3ds7BUR9SvoKgZnje
1cMNvxggqMwIRNxr9c1uu1irVu6XkT84oT2Q/shiKsjUpZBYaWEnYvQtT9Qp4yuH
qV5Cs3IDonvK1E37UnwZJZdcfYFjoaahE8WD8Dn2BydbV+DGT9NMhx/5mVTQmYPm
y1yItE1v+Bv3JZO6oiQcos2peS9XgM/EjGkQyOGOslr5qTgp2rOp8i1kMxObxAuo
ddadqPHGTqcm4Tm1YQUlGNFA1N25GKKPtTC/Fv/BglY6RaCKzL7uW/AVfKBbCzPS
r1hHfPYZu5jaBy4EEcV3K6ix3wjf/gA6YeAt96ltFOBCUC2me0Za5Es3PfzTPdfs
vIlE+NpqAMGMauNs2swCHblLWmCElZmuQNbyfdH6APSK3sDLWAI0SfZTZKy9n944
lq8JYvGsFjE6D5zN60Q1xybhqku4tUvRJkvxN28TzEd2U6BoP1BU1r7OJWAjAgMB
AAGjggEpMIIBJTAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAzBglghkgB
hvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0G
A1UdDgQWBBQASym2L5vYZKo9PnqDiSRyOHQ5zDCBiwYDVR0jBIGDMIGAgBSJpW4a
7QM2MkPIdhDrAIEEGc2Rg6FkpGIwYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB
MREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNoaWZ0MyB0ZXN0IENB
MRQwEgYDVQQDDAtyb290LmNhLm9yZ4ICEAAwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud
JQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4ICAQBojUFZQKM8uItkQKcQ
oNA7prsl3Kq4bFMzhRgwHRyNigEkd3sYzD6BK1KmuAD3GFq8++RrXY99VZhDll0g
q9Ri/3hOuWZfYC/FXWth1/civgKTp1u1OX9W/8ezzXcTqQ1bLROaHHebaRtmhhwf
Ltqx/WldLHfEph7+xsUOf0KbpnIR3U5/EPGyIbd6HdPY8q4x83WLQU6zwwSAeAdF
kgum2JOdlvmkGTAUE3SHgwWltoem0Se9K/Za9g+N1emaTBdAK22bcwK3ypiiv1V9
6hsSSPwYgDW2LHNQSp0kORZOH4NYrWFbQaofgDelL6pA9yn3d+03ANdxyyURROTe
5uinwTpCoQZRsqcqGUYi0Yg4CYSjBfTAYev8DYAPsrC7oQnDb/0cMlVySCRdsx0t
M7zb8gxpIwoGXQHaJJfaGvfpQLy9bg+5nwkhDvstMq6Co5da8YVC6prsWhJnz3rs
j24WPpiLJDgfUZ9S1y+4N8enlLFRQ0VwvGySsqYPenuHA9v8LHDV3iVIL0gvKNI7
ymKGlQBFj8kERKljuA7ihAWLwGC2S1wgjUVcDyufV2GoEtzKLXQ6SeuucYsXqWH9
iP3E3dsMBWrtdVjLwFOsglJVTTv8JUkCzl2AOxFpgeorfi1hyBoS5qDBkET6xXhC
OyxyJrGdmLclqzBEW1Zv3j5ywA==
-----END CERTIFICATE-----`

	testPrivateKeyWithIntCA = `-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----`

	testExpiredCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
MIIGdzCCBF+gAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNo
aWZ0MyB0ZXN0IENBMRwwGgYDVQQDDBNpbnRlcm1lZGlhdGUuY2Eub3JnMCIYDzE5
OTAwMjI4MTAxMDMwWhgPMjAwMDAyMjcxMDExMTJaMGQxCzAJBgNVBAYTAlVTMQsw
CQYDVQQIDAJDQTERMA8GA1UECgwIU2VjdXJpdHkxGzAZBgNVBAsMEk9wZW5TaGlm
dDMgdGVzdCBDQTEYMBYGA1UEAwwPZXhwaXJlZC5jYS50ZXN0MIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAymVeWMYj4O5H5kYBoza3XdnHXVTtwBpX/nNQ
R5fMBtLGzjpYHIKrJSb5cqLrbxvdwVQhyWn1ORBvPVyT5aPocnKeKgcUGeAZDj37
ZcqB7INMIbk1bUZlGvlDHk7u0fxHtFr+pOu6UOyTbmHlQayaJ+7aPqI2zpP3CGM4
EFyyv8wd9nDb3fzMEPhlNLqVWhuUUUlTz3aLULAfOfsU0XPWmW246oLSfDZX4eUp
dxPPWQW2L17T+6lMUFdtdS9QH+wZL5ceGyMCxfGKBHz2y7XVLVKEb6u9l7rIIumy
/5avsLhhUmHPNJlAmVzmKjZFCJ4rlCdIp0PpT54MysNcdHxyYTRA9An1HWcSI87f
t8IGcBBEvpk0g3e5KE9guppwWuUxVh+UoBwux1pFwTbrBMcAVjssy8gAJ42oa/nx
CNrm1vFmr/BziDNXEzDDKlbnVLDkggPufpriGIwNbxWNRVLEdP3cq+mZ1MC61xSa
u87m0YV2dcxbtyF2eW7O8l8eT4N0bcvAa0UxyQGZJN5TF1rC4FTvQaZ7El/G6Xol
V/hi76yO807h1b+aBaf5AJGyJjoVGjehV7Qh4L0oR6klNH+g766+gAvjbMn49mpo
d6eh0Nz3BrRa/ur50L9wwp07n64X/BOif1tu2yyk7prWypJ864jRr/L0LCLClB/H
uOUArRECAwEAAaOCASkwggElMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZA
MDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlm
aWNhdGUwHQYDVR0OBBYEFMb6xBVJB2jTowuspCFkRwOgt2QjMIGLBgNVHSMEgYMw
gYCAFImlbhrtAzYyQ8h2EOsAgQQZzZGDoWSkYjBgMQswCQYDVQQGEwJVUzELMAkG
A1UECAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hpZnQz
IHRlc3QgQ0ExFDASBgNVBAMMC3Jvb3QuY2Eub3JnggIQADAOBgNVHQ8BAf8EBAMC
BaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggIBAELf51eR
qbkdec/xJoGFNy0Z7W4aIzlYBpdakB9lH4RmcIm8oFJJmt4LXfGKAYQ5WuWv8Evj
S4qMiMO1Lul/zBzvv8srFJy0+OFqDf/+dVOaZ0AEl4RQ4oT0tw9HGhde4YZICXZ/
nFjI/GmbhBFpZ6ZFRq6lCNG95fldLdFuCzJnpvOnKuzjSjpa6mmFIMvMqpEm9cUb
gs/LfBpZU4s7fYufnBUlaon2YLIvYtF5uLyKk+rFqwaakb14Dl8k+BW252sIu9UV
iKYul+Ham8r6EMBQ4eeHZVKXGztwg/x+wCRJriWjz9mWZCStlx9NjOV972hoBClf
jRA6IiVp7xgb5G0v4kv7tXtjOS1AY7v4k78cHkNytAZDtRNAyFXx5ZU1Tvej9ECS
1iwOlpanjc5Moi2gG9ga4E+DFLnMBVWzuQJGTZt2znuC1JWQgiDBLVVst2xMqSMc
A5s8mE+vA3LXVXNoBBpxS33cQQaphUfwuftrymJ6VPs/YASOXyT7m0O8512dsV8G
AP0Ju9SYA5ZMeGTUGRRKDM9NBrqfoUJ85SpjeZoHaltURRJPBEkh8ZFyUFNSfdaO
orbhEj5JaB5XEsNKST9cP+9e3l2fsrcB7cQspxnRzkJSzhpBWKgQHce0+6l2PVbp
+wlvPN8TwYpdQ/skn6pz9kx0V2FQaQFisF+x
-----END CERTIFICATE-----`

	testExpiredCertificateKey = `-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----`

	testFutureValidCertificateWithIntCA = `-----BEGIN CERTIFICATE-----
MIIGgTCCBGmgAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwaDELMAkGA1UEBhMCVVMx
CzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwST3BlblNo
aWZ0MyB0ZXN0IENBMRwwGgYDVQQDDBNpbnRlcm1lZGlhdGUuY2Eub3JnMCAYDzIw
MzYwMjI4MTAxMDMwWhcNMzYxMTAzMDAxNzE3WjBwMQswCQYDVQQGEwJVUzELMAkG
A1UECAwCQ0ExETAPBgNVBAoMCFNlY3VyaXR5MRswGQYDVQQLDBJPcGVuU2hpZnQz
IHRlc3QgQ0ExJDAiBgNVBAMMG3ZhbGlkLmluLnRoZS5mdXR1cmUuY2EudGVzdDCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN6DzbjCo4EvQ9NKIBCMZXAb
0OnhLkDJa5P4O4sjRuOFAbl/e6SZ05olK7uNgbuis5aebzKC8nb+UuS4b8GXTWkL
TS5sbGUsrIZ6PDCA+cvEj4ZwYPjqNCurimLNyQYyroNy+pRxtkSfV+9TS7zndRxo
aWZECQ4ApXageNu7Afg9M9/ainQR0w5TyJ2kKB6O0+0dF/7re30tD7FX+wHfN6/z
owbM5qGEPcFINGYZPik8ZGkVsv98BFI3MTHjlgQ5a44Rmg3jVhdCuI2sy41pm2pM
2x1pUGqj6UjxbwXq7yKOle0W6dni3TpR57Pq5/jfpsMITGtYM++J/i2LxjTTsIpI
9Qe6gHRapYA8Ab1ro9QHgAe6LVUt39ki7O6EVGBq08405tnna5uvDm3/Bl7qYq6O
erhRKATRyj/Vf1PJ7823NvOgQzvwx6w6c2kJJQIPcYppUfsUpYgIRQuy8759jAMA
RESXQfCK/W6ub1P0dYSKBejf5cf1QhrVfxqkun222qyHk9PDNt/FTzG9V/Y9w4y8
uTnUWXHDLVHHtrOCyLEZLsdaZbZnt7g1Q+zuaJ/0CTnkMsksroLfZLwbuPJdRezR
z8MbgLodjDgwKh8RpXdXPdIanP0SgZsTjpGlAYUr/GA4l9x/lf8GfG6KTRMC9dKi
jIpB5MNxkYrkP2NuFdvlAgMBAAGjggEpMIIBJTAJBgNVHRMEAjAAMBEGCWCGSAGG
+EIBAQQEAwIGQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2Vy
dmVyIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ9aWYDwIp0t7yQTTyfA77g5OcRtDCB
iwYDVR0jBIGDMIGAgBSJpW4a7QM2MkPIdhDrAIEEGc2Rg6FkpGIwYDELMAkGA1UE
BhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQKDAhTZWN1cml0eTEbMBkGA1UECwwS
T3BlblNoaWZ0MyB0ZXN0IENBMRQwEgYDVQQDDAtyb290LmNhLm9yZ4ICEAAwDgYD
VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUA
A4ICAQAtneFpJw97r8GkNK5oY86PKStfj9e1W8v3EfHc9YkhkZ7qDKXvSuY0UC0T
abhhgL2IDF3zmnH71RY+WMNmDCbJWZoOe2NXjo3TxG38fLqk9C2ayi860TasPQNM
rcZ0E+FiDxm582wrmBdD+GpgrNlwiQ2Z5U897IDZv7LiPI7rSYF3OvI/xxz2Q7ZT
VDJBH22Fg7UY3JqVRMU/4ff3jiWuelbepSyk7LqxYQuAcBR2nTA/8UGw1YplESm0
YWEHwE8GykJB5LVXQsVNo/MlEU3vwa5YnseFWdtkg3JKyK9dv6QE3LAnbw0kwx5R
HUBXN0N57aODaQbx1amSHqAmNnpZtfoZfJhdZR0RVvUeIv7D9HjIpJio+pEcNJwY
xyVVqbD/tYc4tUFeAtHl9jM1Ob2p/nHj/yOjCy3GTY/eUPNLgGs0DX4aFo4WTDdd
GKEd0EKjqXLFYFHUWuNAh2+0J7xAXR8oP7sOdg5DiclCZMT874YOlS5Ps6E/PnvR
sgOg6zar/gx5Rp8ext2NVkXgTww2fzVgf0+FF1GrhjdugsGLjyqfFEspZ85Yrkdo
hYnY5k0G+POAuJKmPgUd7W1QltLnRRvsFyEse+qkTj7cxj4ZwsJ8YJuM8yO5/+ol
XzV329s9fh8ILFaY4196hzqNsEX5ZHYxc/AtcoMMniDPATyK1w==
-----END CERTIFICATE-----`

	testFutureValidCertificateKey = `-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----`

	testInvalidCANoCert1 = `-----BEGIN CERTIFICATE REQUEST-----
MIICnTCCAYUCAQAwWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMREwDwYDVQQK
DAhTZWN1cml0eTETMBEGA1UECwwKT3BlblNoaWZ0MzEUMBIGA1UEAwwLcm91dGVy
LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS7tHwWAJ0PBuU
u8RJ5i98FoDmXgaL0uiLR+n46FACiRW0tKA0WvXX9afSFSa5nb+Z9GHxMBsIe1lu
noM+k2lBScW8PnGTW5mzkEHVzGb9zmM8lSE6gcRjZwPPre3bnWnemXU1Loa6IV+W
p9w8x/SqlZAlS+Vab+5opC8dSXM4OG1qIb0JqPrXPx8e7RaLr53fmbEm3iIT/wjk
GWfQFAUToswERt2Jx5Ojri5qe+VDwlfOXt6GjWDPJsYroufDXxWmboZZtYxsVZnY
xWgnwHVaHaTdbogafXWWyfLhSdNpjUX9bnXWSh+VR5m7SxjgjqqYK8EpqNyxay+E
mBdaVgWPAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAnVnDhysDJY3MPqIYYXwE
Yg9pkV4j5MStP2sSR+oWgqBP1BGZn2yaK2Bb8jGeBw53uuH0S+NifnVVXi1Q7rmV
P8SLmCRvWDbeRgQC4fWgrzEkB8kePTGuvZM6/wLTiw3i1AxcG8Z8aDVNRrJq0im5
dAz9X4YF0m9ZweqB9LeYd/UXbI2ZMHBkOgY08Co1X7+DpfohzCOflix1vjuygViR
1MXW8UIYFktyyhSeL7eshW0BhqfMoku+btO4LZ/IZHDZsF3gd5NOPoNX28m0E74y
xhfvmedJE9ck2tEbxQk8BcdCXCN4HFePO8gpCYeC7r309E/QwFjU9+xw6qrpW5uP
GA==
-----END CERTIFICATE REQUEST-----`

	testInvalidCANoCert2 = testSelfSignedKey

	testInvalidCAMalformedCert = `-----BEGIN CERTIFICATE-----
MIIDjTCCAnWgAwIBAgIJAKM4rr3VRQARMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
The+rest+of+the+certificate+info+is+invalid+and+badly+malformed/
0A==
-----END CERTIFICATE-----`
)

func createRouteSpecTo(name string, kind string) api.RouteTargetReference {
	svc := api.RouteTargetReference{
		Name: name,
		Kind: kind,
	}
	return svc
}

// TestValidateRouteBad ensures not specifying a required field results in error and a fully specified
// route passes successfully
func TestValidateRoute(t *testing.T) {
	tests := []struct {
		name           string
		route          *api.Route
		expectedErrors int
	}{
		{
			name: "No Name",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To:   createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 1,
		},
		{
			name: "No namespace",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name: "name",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To:   createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 1,
		},
		{
			name: "No host",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					To: createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Invalid DNS 952 host",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "**",
					To:   createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 1,
		},
		{
			name: "No service name",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To:   createRouteSpecTo("", "Service"),
				},
			},
			expectedErrors: 1,
		},
		{
			name: "No service kind",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To:   createRouteSpecTo("serviceName", ""),
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Zero port",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					To:   createRouteSpecTo("serviceName", "Service"),
					Port: &api.RoutePort{
						TargetPort: intstr.FromInt(0),
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Empty string port",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					To:   createRouteSpecTo("serviceName", "Service"),
					Port: &api.RoutePort{
						TargetPort: intstr.FromString(""),
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Valid route",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					To:   createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Valid route with path",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					To:   createRouteSpecTo("serviceName", "Service"),
					Path: "/test",
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Invalid route with path",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					To:   createRouteSpecTo("serviceName", "Service"),
					Path: "test",
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough route with path",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "name",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "www.example.com",
					Path: "/test",
					To:   createRouteSpecTo("serviceName", "Service"),
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationPassthrough,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "No wildcard policy",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "nowildcard",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host: "no.wildcard.test",
					To:   createRouteSpecTo("serviceName", "Service"),
				},
			},
			expectedErrors: 0,
		},
		{
			name: "wildcard policy none",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "nowildcard2",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host:           "none.wildcard.test",
					To:             createRouteSpecTo("serviceName", "Service"),
					WildcardPolicy: api.WildcardPolicyNone,
				},
			},
			expectedErrors: 0,
		},
		{
			name: "wildcard policy subdomain",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "wildcardpolicy",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host:           "subdomain.wildcard.test",
					To:             createRouteSpecTo("serviceName", "Service"),
					WildcardPolicy: api.WildcardPolicySubdomain,
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Invalid wildcard policy",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "badwildcard",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host:           "bad.wildcard.test",
					To:             createRouteSpecTo("serviceName", "Service"),
					WildcardPolicy: "bad-wolf",
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Invalid host for wildcard policy",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "badhost",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					To:             createRouteSpecTo("serviceName", "Service"),
					WildcardPolicy: api.WildcardPolicySubdomain,
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Empty host for wildcard policy",
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:      "emptyhost",
					Namespace: "foo",
				},
				Spec: api.RouteSpec{
					Host:           "",
					To:             createRouteSpecTo("serviceName", "Service"),
					WildcardPolicy: api.WildcardPolicySubdomain,
				},
			},
			expectedErrors: 1,
		},
	}

	for _, tc := range tests {
		errs := ValidateRoute(tc.route)

		if len(errs) != tc.expectedErrors {
			t.Errorf("Test case %s expected %d error(s), got %d. %v", tc.name, tc.expectedErrors, len(errs), errs)
		}
	}
}

func TestValidateTLS(t *testing.T) {
	tests := []struct {
		name           string
		route          *api.Route
		expectedErrors int
	}{
		{
			name: "No TLS Termination",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: "",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination OK",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationPassthrough,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination OK with certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              "def",
						Key:                      "ghi",
						CACertificate:            "jkl",
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination OK without certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination no dest cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationReencrypt,
						Certificate:   "def",
						Key:           "ghi",
						CACertificate: "jkl",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Edge termination OK with certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   "abc",
						Key:           "abc",
						CACertificate: "abc",
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination OK without certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination, dest cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationEdge,
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination, cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, Certificate: "test"},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination, key",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, Key: "test"},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination, ca cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, CACertificate: "test"},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination, dest ca cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, DestinationCACertificate: "test"},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Invalid termination type",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: "invalid",
					},
				},
			},
			expectedErrors: 1,
		},
	}

	for _, tc := range tests {
		errs := validateTLS(tc.route, nil)

		if len(errs) != tc.expectedErrors {
			t.Errorf("Test case %s expected %d error(s), got %d. %v", tc.name, tc.expectedErrors, len(errs), errs)
		}
	}
}

func TestValidatePassthroughInsecureEdgeTerminationPolicy(t *testing.T) {

	insecureTypes := map[api.InsecureEdgeTerminationPolicyType]bool{
		"": false,
		api.InsecureEdgeTerminationPolicyNone:     false,
		api.InsecureEdgeTerminationPolicyAllow:    true,
		api.InsecureEdgeTerminationPolicyRedirect: false,
		"support HTTPsec":                         true,
		"or maybe HSTS":                           true,
	}

	for key, expected := range insecureTypes {
		route := &api.Route{
			Spec: api.RouteSpec{
				TLS: &api.TLSConfig{
					Termination:                   api.TLSTerminationPassthrough,
					InsecureEdgeTerminationPolicy: key,
				},
			},
		}
		route.Spec.TLS.InsecureEdgeTerminationPolicy = key
		errs := validateTLS(route, nil)
		if !expected && len(errs) != 0 {
			t.Errorf("Test case for Passthrough termination with insecure=%s got %d errors where none where expected. %v",
				key, len(errs), errs)
		}
		if expected && len(errs) == 0 {
			t.Errorf("Test case for Passthrough termination with insecure=%s got no errors where some where expected.", key)
		}
	}
}

// TestValidateRouteBad ensures not specifying a required field results in error and a fully specified
// route passes successfully
func TestValidateRouteUpdate(t *testing.T) {
	tests := []struct {
		name           string
		route          *api.Route
		change         func(route *api.Route)
		expectedErrors int
	}{
		{
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:            "bar",
					Namespace:       "foo",
					ResourceVersion: "1",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To: api.RouteTargetReference{
						Name: "serviceName",
						Kind: "Service",
					},
				},
			},
			change:         func(route *api.Route) { route.Spec.Host = "" },
			expectedErrors: 1,
		},
		{
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:            "bar",
					Namespace:       "foo",
					ResourceVersion: "1",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To: api.RouteTargetReference{
						Name: "serviceName",
						Kind: "Service",
					},
				},
			},
			change:         func(route *api.Route) { route.Spec.Host = "other" },
			expectedErrors: 1,
		},
		{
			route: &api.Route{
				ObjectMeta: kapi.ObjectMeta{
					Name:            "bar",
					Namespace:       "foo",
					ResourceVersion: "1",
				},
				Spec: api.RouteSpec{
					Host: "host",
					To: api.RouteTargetReference{
						Name: "serviceName",
						Kind: "Service",
					},
				},
			},
			change:         func(route *api.Route) { route.Name = "baz" },
			expectedErrors: 1,
		},
	}

	for i, tc := range tests {
		copied, err := kapi.Scheme.Copy(tc.route)
		if err != nil {
			t.Fatal(err)
		}
		newRoute := copied.(*api.Route)
		tc.change(newRoute)
		errs := ValidateRouteUpdate(newRoute, tc.route)
		if len(errs) != tc.expectedErrors {
			t.Errorf("%d: expected %d error(s), got %d. %v", i, tc.expectedErrors, len(errs), errs)
		}
	}
}

func TestValidateInsecureEdgeTerminationPolicy(t *testing.T) {
	tests := []struct {
		name           string
		insecure       api.InsecureEdgeTerminationPolicyType
		expectedErrors int
	}{
		{
			name:           "empty insecure option",
			insecure:       "",
			expectedErrors: 0,
		},
		{
			name:           "foobar insecure option",
			insecure:       "foobar",
			expectedErrors: 1,
		},
		{
			name:           "insecure option none",
			insecure:       api.InsecureEdgeTerminationPolicyNone,
			expectedErrors: 0,
		},
		{
			name:           "insecure option allow",
			insecure:       api.InsecureEdgeTerminationPolicyAllow,
			expectedErrors: 0,
		},
		{
			name:           "insecure option redirect",
			insecure:       api.InsecureEdgeTerminationPolicyRedirect,
			expectedErrors: 0,
		},
		{
			name:           "insecure option other",
			insecure:       "something else",
			expectedErrors: 1,
		},
	}

	for _, tc := range tests {
		route := &api.Route{
			Spec: api.RouteSpec{
				TLS: &api.TLSConfig{
					Termination:                   api.TLSTerminationEdge,
					InsecureEdgeTerminationPolicy: tc.insecure,
				},
			},
		}
		errs := validateTLS(route, nil)

		if len(errs) != tc.expectedErrors {
			t.Errorf("Test case %s expected %d error(s), got %d. %v", tc.name, tc.expectedErrors, len(errs), errs)
		}
	}
}

func TestValidateEdgeReencryptInsecureEdgeTerminationPolicy(t *testing.T) {
	tests := []struct {
		name  string
		route *api.Route
	}{
		{
			name: "Reencrypt termination",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						DestinationCACertificate: "dca",
					},
				},
			},
		},
		{
			name: "Reencrypt termination DestCACert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						DestinationCACertificate: testDestinationCACertificate,
					},
				},
			},
		},
		{
			name: "Edge termination",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
					},
				},
			},
		},
	}

	insecureTypes := map[api.InsecureEdgeTerminationPolicyType]bool{
		api.InsecureEdgeTerminationPolicyNone:     false,
		api.InsecureEdgeTerminationPolicyAllow:    false,
		api.InsecureEdgeTerminationPolicyRedirect: false,
		"support HTTPsec":                         true,
		"or maybe HSTS":                           true,
	}

	for _, tc := range tests {
		for key, expected := range insecureTypes {
			tc.route.Spec.TLS.InsecureEdgeTerminationPolicy = key
			errs := validateTLS(tc.route, nil)
			if !expected && len(errs) != 0 {
				t.Errorf("Test case %s with insecure=%s got %d errors where none were expected. %v",
					tc.name, key, len(errs), errs)
			}
			if expected && len(errs) == 0 {
				t.Errorf("Test case %s  with insecure=%s got no errors where some were expected.", tc.name, key)
			}
		}
	}
}

// TestExtendedValidateRoute ensures that a route's certificate and keys
// are valid.
func TestExtendedValidateRoute(t *testing.T) {
	tests := []struct {
		name           string
		route          *api.Route
		expectedErrors int
	}{
		{
			name: "No TLS Termination",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: "",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination OK",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationPassthrough,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination OK with certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",

					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              testCertificate,
						Key:                      testPrivateKey,
						CACertificate:            testCACertificate,
						DestinationCACertificate: testDestinationCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination OK with bad config",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              "def",
						Key:                      "ghi",
						CACertificate:            "jkl",
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 4,
		},
		{
			name: "Reencrypt termination OK without certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						DestinationCACertificate: testDestinationCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Reencrypt termination bad config without certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Reencrypt termination no dest cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationReencrypt,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Edge termination OK with certs without host",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination OK with certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination bad config with certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   "abc",
						Key:           "abc",
						CACertificate: "abc",
					},
				},
			},
			expectedErrors: 3,
		},
		{
			name: "Edge termination mismatched key and cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testExpiredCertPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Edge termination expired cert unknown CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testExpiredCAUnknownCertificate,
						Key:         testExpiredCertPrivateKey,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination expired cert mismatched CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testExpiredCAUnknownCertificate,
						Key:           testExpiredCertPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Edge termination expired cert key mismatch",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testExpiredCAUnknownCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "Edge termination OK without certs",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Edge termination, dest cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationEdge,
						DestinationCACertificate: "abc",
					},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "Passthrough termination, cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, Certificate: "test"},
				},
			},
			expectedErrors: 3,
		},
		{
			name: "Passthrough termination, key",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, Key: "test"},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Passthrough termination, ca cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, CACertificate: "test"},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "Passthrough termination, dest ca cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{Termination: api.TLSTerminationPassthrough, DestinationCACertificate: "test"},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "Invalid termination type",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination: "invalid",
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Double escaped newlines",
			route: &api.Route{
				Spec: api.RouteSpec{
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              "d\\nef",
						Key:                      "g\\nhi",
						CACertificate:            "j\\nkl",
						DestinationCACertificate: "j\\nkl",
					},
				},
			},
			expectedErrors: 4,
		},
		{
			name: "example cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Expired cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Expired cert reencrypt",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              testCertificate,
						Key:                      testPrivateKey,
						CACertificate:            testCACertificate,
						DestinationCACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "Expired cert invalid key",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testExpiredCertNoKey,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Expired cert mismatched key",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testExpiredCertNoKey,
						Key:         testPrivateKey,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Expired cert invalid key reencrypt",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.com",
					TLS: &api.TLSConfig{
						Termination:              api.TLSTerminationReencrypt,
						Certificate:              testExpiredCertNoKey,
						DestinationCACertificate: testExpiredCertNoKey,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "Expired cert with a different route host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "think.different.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testCACertificate,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "self-signed cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "self.signer.test",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationReencrypt,
						Certificate: testSelfSignedCert,
						Key:         testSelfSignedKey,

						DestinationCACertificate: testSelfSignedCert,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "self-signed cert with different host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "different.co.us",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testSelfSignedCert,
						Key:         testSelfSignedKey,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "future validity date 2038 cert",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "self.signer.test",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testValidInFutureCert,
						Key:         testValidInFutureKey,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "future validity date 2038 cert with different host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.in.the.future.test",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationEdge,
						Certificate: testValidInFutureCert,
						Key:         testValidInFutureKey,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "cert with intermediate CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificateWithIntCA,
						Key:           testPrivateKeyWithIntCA,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "cert with intermediate CA and diff host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "different.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificateWithIntCA,
						Key:           testPrivateKeyWithIntCA,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "expired cert with intermediate CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "expired.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testExpiredCertificateWithIntCA,
						Key:           testExpiredCertificateKey,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "expired cert with intermediate CA and diff host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "still.expired.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testExpiredCertificateWithIntCA,
						Key:           testExpiredCertificateKey,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "future valid cert with intermediate CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "valid.in.the.future.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testFutureValidCertificateWithIntCA,
						Key:           testFutureValidCertificateKey,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "future valid cert with intermediate CA and diff host",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "future.valid.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testFutureValidCertificateWithIntCA,
						Key:           testFutureValidCertificateKey,
						CACertificate: testIntCACertificateChain,
					},
				},
			},
			expectedErrors: 0,
		},
		{
			name: "invalid CA with csr",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "invalid.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testInvalidCANoCert1,
					},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "another invalid CA with private key",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "another.invalid.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testInvalidCANoCert2,
					},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "invalid CA malformed certificate",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "malformed.ca.test",
					TLS: &api.TLSConfig{
						Termination:   api.TLSTerminationEdge,
						Certificate:   testCertificate,
						Key:           testPrivateKey,
						CACertificate: testInvalidCAMalformedCert,
					},
				},
			},
			expectedErrors: 2,
		},
		{
			name: "invalid destination CA with csr",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "csr.destination.ca",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationReencrypt,
						Certificate: testSelfSignedCert,
						Key:         testSelfSignedKey,

						DestinationCACertificate: testInvalidCANoCert1,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "invalid destination CA with private key",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "key.destination.ca",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationReencrypt,
						Certificate: testSelfSignedCert,
						Key:         testSelfSignedKey,

						DestinationCACertificate: testInvalidCANoCert1,
					},
				},
			},
			expectedErrors: 1,
		},
		{
			name: "malformed destination CA",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "malformed.destination.ca",
					TLS: &api.TLSConfig{
						Termination: api.TLSTerminationReencrypt,
						Certificate: testSelfSignedCert,
						Key:         testSelfSignedKey,

						DestinationCACertificate: testInvalidCAMalformedCert,
					},
				},
			},
			expectedErrors: 1,
		},
	}

	for _, tc := range tests {
		errs := ExtendedValidateRoute(tc.route)

		if len(errs) != tc.expectedErrors {
			t.Errorf("Test case %s expected %d error(s), got %d. %v", tc.name, tc.expectedErrors, len(errs), errs)
		}
	}
}

// TestValidateHostName checks that a route's host name matches DNS requirements.
func TestValidateHostName(t *testing.T) {
	tests := []struct {
		name           string
		route          *api.Route
		expectedErrors bool
	}{
		{
			name: "valid-host-name",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "www.example.test",
				},
			},
			expectedErrors: false,
		},
		{
			name: "invalid-host-name",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "name-namespace-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890-1234567890.example.test",
				},
			},
			expectedErrors: true,
		},
		{
			name: "valid-host-63-chars-label",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "name-namespace-1234567890-1234567890-1234567890-1234567890-1234.example.test",
				},
			},
			expectedErrors: false,
		},
		{
			name: "invalid-host-64-chars-label",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "name-namespace-1234567890-1234567890-1234567890-1234567890-12345.example.test",
				},
			},
			expectedErrors: true,
		},
		{
			name: "valid-name-253-chars",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "name-namespace.a1234567890.b1234567890.c1234567890.d1234567890.e1234567890.f1234567890.g1234567890.h1234567890.i1234567890.j1234567890.k1234567890.l1234567890.m1234567890.n1234567890.o1234567890.p1234567890.q1234567890.r1234567890.s12345678.example.test",
				},
			},
			expectedErrors: false,
		},
		{
			name: "invalid-name-279-chars",
			route: &api.Route{
				Spec: api.RouteSpec{
					Host: "name-namespace.a1234567890.b1234567890.c1234567890.d1234567890.e1234567890.f1234567890.g1234567890.h1234567890.i1234567890.j1234567890.k1234567890.l1234567890.m1234567890.n1234567890.o1234567890.p1234567890.q1234567890.r1234567890.s1234567890.t1234567890.u1234567890.example.test",
				},
			},
			expectedErrors: true,
		},
	}

	for _, tc := range tests {
		errs := ValidateHostName(tc.route)

		if tc.expectedErrors {
			if len(errs) < 1 {
				t.Errorf("Test case %s expected errors, got none.", tc.name)
			}
		} else {
			if len(errs) > 0 {
				t.Errorf("Test case %s expected no errors, got %d. %v", tc.name, len(errs), errs)
			}
		}
	}
}