diff --git a/command/operator_diagnose.go b/command/operator_diagnose.go index 880f36b369..941296764d 100644 --- a/command/operator_diagnose.go +++ b/command/operator_diagnose.go @@ -535,6 +535,11 @@ SEALFAIL: } if ln.Config.TLSDisableClientCerts { diagnose.Warn(listenerTLSContext, "TLS for a listener is turned on without requiring client certs.") + + } + err = diagnose.TLSMutualExclusionCertCheck(ln.Config) + if err != nil { + diagnose.Warn(listenerTLSContext, fmt.Sprintf("TLSDisableClientCerts and TLSRequireAndVerifyClientCert should not both be set. %s", err)) } sanitizedListeners = append(sanitizedListeners, listenerutil.Listener{ diff --git a/vault/diagnose/test-fixtures/chain.crt.pem b/vault/diagnose/test-fixtures/chain.crt.pem new file mode 100644 index 0000000000..35e82d5b04 --- /dev/null +++ b/vault/diagnose/test-fixtures/chain.crt.pem @@ -0,0 +1,64 @@ +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgICEAAwDQYJKoZIhvcNAQENBQAwWDELMAkGA1UEBhMCQ0Ex +CzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRvMRQwEgYDVQQKDAtleGFtcGxl +LmNvbTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjEwNjE3MTUyOTA4WhcNMzEw +NjE1MTUyOTA4WjBYMQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xFDASBgNVBAoM +C2V4YW1wbGUuY29tMQwwCgYDVQQLDANpbnQxGDAWBgNVBAMMD2ludC5leGFtcGxl +LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPcI9yYyT4jxvo7g +23mrjdAJC4tNeg2+eyujaVpxNWkwqecFiyCeN1qVNSzjY95wKk95Pd51oUsup3Ja +zQ/Prdt6eabPr3g/7eZOw87AW1g/fe2soh46+IIZA0JJxKDjJNY4JasRNvusHjYX +7hSZR+PnHcMuTx1h2arVnJX+ln6DmRRMNvPs0In+TG1z4wJbIRFq3m/uLgnEd7fv +/fvX4jphz7dk/I/I1b7NedHyl/wO52mBRQ6IdT8/hR7uT90CDxd66to2r5nnttLu +oVFjZkHrG4BJh9QO5Fp55QOy8wmAhlaDewbRUui0OpvFnxamarNd2vql4Kt645cc +R4+fpYHWTzJPM/8HqocrnI63NVaa7wSfGgCHBhNo1GYF2QL+5zAEHdKkSDPLszoc +dXAOZBDVZssgRZt5nWIAp7Kkm4gmsqPdUrO0OB+0v9+q2UjOT5/dhCDKdRsZ4K30 +gU5BEJyfO31oM2QRRKlqjM4yN7/TRm5RlbFcVXobuVKWYsfkfhANa/hbWII3bB+v +G/V+HOqd0zwfhaTYNSRiUKfAcZBUxDW2XCWfxIV2bygu1Ev9POjrWteWqYTga3le +y+rnIq6mcAkjNKPIiRmM3guyl0XPqzfqHf2TMGRNf/Y6GlxkBDLcEF7cB420/FWz +zXM2DqpMKTvPnBm+I4nvO2lkZuNxAgMBAAGjZjBkMB0GA1UdDgQWBBSqAVbbvHD5 +V/Cc0NjmmFyHBmX08zAfBgNVHSMEGDAWgBQDJwHpS6RzHvUmYhKXj3u++kF/sjAS +BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0F +AAOCAgEAl7BViBti9cGf/bEvOv1DmMDPQRy9GBwnzyBGeF8zYw79yGhOezruicg8 +UzjgKL2zzNEdCQfetz+iEiuFAu/cpy2gpOkjuYa3KSNQJzmKwRlTAPNo3yHisSxM +YSvCD1csthZJVxBbM4XwiLg3zD1dOfVByasCPZ41PA2Ott5Xs0xwIYbYytypJ5WL +2bwMrt8vVkBz+SicoiUIbfNXAYP2NoW0JTg6gbVY7RbBi4suJDzjT4w75UbYMKzA +GudSvWi/8jC3AtXMu1usMVRc3Mpjo8NTnpTRcigHbRIHOO+s3UyXaDxyXXu1ML+u +8+DMq7PL+2EKWGIy8edj2VG2niRIV3WO15w5/LeGiAIfBEMbxDq3Y4m2VsObTEjh +3R4AHnyvfLjxk1wlFUfApcl/TQ3d/KI8e4FS3cB6XVO6oJSTfrm4QcWxHgZ9xJ6i +iVX3RahohR/5QcRsCPFJ19Iik9WvwZBQ/vh1BwDgGGOIUy/chzPIbJDg/OcBMfFk +xXA5Db8ykpMhpLD0FGdzTCIzCMitv46mRLSff3+4PyqEiZ7GOrKnduiBF6tkI34i +etQ4LvFmwloKfwPgAbRXtwp0XCnk+C/adT8fT16JGviHc4Q8fglUKZLVYJiqgb+x +CQZJrtWk7AgmiaeWQkfPcPbRGJjwXaJ7OvoFhXmZyDRWwOcCunQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFjjCCA3agAwIBAgIBADANBgkqhkiG9w0BAQ0FADBYMQswCQYDVQQGEwJDQTEL +MAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8xFDASBgNVBAoMC2V4YW1wbGUu +Y29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yMTA2MTcxNTEyMDZaFw0zMTA2 +MTUxNTEyMDZaMFgxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwH +VG9yb250bzEUMBIGA1UECgwLZXhhbXBsZS5jb20xFDASBgNVBAMMC2V4YW1wbGUu +Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqhfgT3MSg+QfWFCp +RQ/z9GdrV3AGH/NMnlzpWFo39pUul8bGTSLiSNJZnfn4ZR6nL01gBVC14lD2W4a/ +az6tkAR1s0Rfn9EfZFW8dWesYs0t98ENvsW7kZnJTtZX822XquE65hYOxI7ul87L +XsbMQBoAuQk44kla2gJ0VIJosvA+LyZIHZXcA4UYL70mcqWn72D3hLkIzUpapG8f +czoGhLW51anScQnJ3MStnOsvTpk1QVsrHLACNala7Pe+OIXHrg9D4eZorX3TZRIo +EVOcHyJVx40BkTnGhjgTAFuhTvc1NqHW7IpcAQawNV583JIZ8RvTXmCQGsJEgiDO +1HP1wVc8uUyCsZ0J/qbUohdWdFpgAwM5OkOV+0QOkvhD4ZOvwK2NxBlIwOxDdhTl +BmiKoLutvTXIc1dT+bU3g5T4024ulfsG3ZISJAGWB8b0KKPFl8oT3DGruMAA7dLn +pa9a35FF4zyERm5PTYVNRg59+bbpYOeZbUS3SoJdenjcL/pV8z9bmeSsWTZf4GtD +5sfvlnamUcqVveBSGNJQ/4TkTrWqpyEbQTpiAndqetJEDb8Ta7K2IaFzWwvYYFkB +o2G1jvr7qB19yChedu3DREtsDz4jaBEVSw+oyLHdN37iaDksP7cgmnjsmTnO5SdR +zjHt24CuwdpdPPf3m3XxZfWgb9MCAwEAAaNjMGEwHQYDVR0OBBYEFAMnAelLpHMe +9SZiEpePe776QX+yMB8GA1UdIwQYMBaAFAMnAelLpHMe9SZiEpePe776QX+yMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IC +AQAkyoX6Wzl7xWPa6rqSj3gxTDs8rKMCw6mmjLIRsKU+vRQ/a8uDYunJXQrDQ21e +AKJfCPRt+d/gTllJ/OOuDW55zRvJX486aIQzQnU4TGgj58HUYaA9z8pQEpCN36Dp +X0UWarGKDGBJ/fb3GJf71TXQgCLgd9IWgtN0Y59MMOQyiUYjulBcSD9eTTsSezcQ +OYTSybma8mZxERMmuEMWZUJl91PLBogAwelwoFoOoCDFyZXcnXD5yDL4uhzMG+px +0A2zWM8dYYq+Hn1zfzu5cyxeiyGSLYtaKxQCxZJ9FunSLwgLfYRH9YZx92ZcVuMG +FylUhQVEkH3d+Pjgys8q/avWGkj0LBzK8/KkZGzO/SMlIJRHtqQgzKi4hbc57vRQ +F32H8/zGTfwDwdjZSy4UvvATNLGbYa/nXYgGzqzQiQd5SIIBMzyG89ZeEsYb3EKD +rZPqDfhSzXs0gZj+JDgFCkro7203k1mRjXa/txfmjjGKEggPk80J2joeHHbsQOj2 +vLl/GE8XiLpT0rZQY1VvlrM0NdG/Ncfs9K3BZWh4yisspJgq6blURRhGV8rWHUMH +bnXMYXDb9bhmsbho0e+KYdN8EzdzZP0kX0Ro5uj6JlR+DtTX0MGQwawwdtrAbjGV +EDFilaw7tcZUQFXRmn5YTs8k7kowY8v5acOaeTJBoOSqBg== +-----END CERTIFICATE----- diff --git a/vault/diagnose/test-fixtures/intermediateCert.pem b/vault/diagnose/test-fixtures/intermediateCert.pem new file mode 100644 index 0000000000..024baaa605 --- /dev/null +++ b/vault/diagnose/test-fixtures/intermediateCert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgICEAAwDQYJKoZIhvcNAQENBQAwWDELMAkGA1UEBhMCQ0Ex +CzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRvMRQwEgYDVQQKDAtleGFtcGxl +LmNvbTEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjEwNjE3MTUyOTA4WhcNMzEw +NjE1MTUyOTA4WjBYMQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xFDASBgNVBAoM +C2V4YW1wbGUuY29tMQwwCgYDVQQLDANpbnQxGDAWBgNVBAMMD2ludC5leGFtcGxl +LmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPcI9yYyT4jxvo7g +23mrjdAJC4tNeg2+eyujaVpxNWkwqecFiyCeN1qVNSzjY95wKk95Pd51oUsup3Ja +zQ/Prdt6eabPr3g/7eZOw87AW1g/fe2soh46+IIZA0JJxKDjJNY4JasRNvusHjYX +7hSZR+PnHcMuTx1h2arVnJX+ln6DmRRMNvPs0In+TG1z4wJbIRFq3m/uLgnEd7fv +/fvX4jphz7dk/I/I1b7NedHyl/wO52mBRQ6IdT8/hR7uT90CDxd66to2r5nnttLu +oVFjZkHrG4BJh9QO5Fp55QOy8wmAhlaDewbRUui0OpvFnxamarNd2vql4Kt645cc +R4+fpYHWTzJPM/8HqocrnI63NVaa7wSfGgCHBhNo1GYF2QL+5zAEHdKkSDPLszoc +dXAOZBDVZssgRZt5nWIAp7Kkm4gmsqPdUrO0OB+0v9+q2UjOT5/dhCDKdRsZ4K30 +gU5BEJyfO31oM2QRRKlqjM4yN7/TRm5RlbFcVXobuVKWYsfkfhANa/hbWII3bB+v +G/V+HOqd0zwfhaTYNSRiUKfAcZBUxDW2XCWfxIV2bygu1Ev9POjrWteWqYTga3le +y+rnIq6mcAkjNKPIiRmM3guyl0XPqzfqHf2TMGRNf/Y6GlxkBDLcEF7cB420/FWz +zXM2DqpMKTvPnBm+I4nvO2lkZuNxAgMBAAGjZjBkMB0GA1UdDgQWBBSqAVbbvHD5 +V/Cc0NjmmFyHBmX08zAfBgNVHSMEGDAWgBQDJwHpS6RzHvUmYhKXj3u++kF/sjAS +BgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0F +AAOCAgEAl7BViBti9cGf/bEvOv1DmMDPQRy9GBwnzyBGeF8zYw79yGhOezruicg8 +UzjgKL2zzNEdCQfetz+iEiuFAu/cpy2gpOkjuYa3KSNQJzmKwRlTAPNo3yHisSxM +YSvCD1csthZJVxBbM4XwiLg3zD1dOfVByasCPZ41PA2Ott5Xs0xwIYbYytypJ5WL +2bwMrt8vVkBz+SicoiUIbfNXAYP2NoW0JTg6gbVY7RbBi4suJDzjT4w75UbYMKzA +GudSvWi/8jC3AtXMu1usMVRc3Mpjo8NTnpTRcigHbRIHOO+s3UyXaDxyXXu1ML+u +8+DMq7PL+2EKWGIy8edj2VG2niRIV3WO15w5/LeGiAIfBEMbxDq3Y4m2VsObTEjh +3R4AHnyvfLjxk1wlFUfApcl/TQ3d/KI8e4FS3cB6XVO6oJSTfrm4QcWxHgZ9xJ6i +iVX3RahohR/5QcRsCPFJ19Iik9WvwZBQ/vh1BwDgGGOIUy/chzPIbJDg/OcBMfFk +xXA5Db8ykpMhpLD0FGdzTCIzCMitv46mRLSff3+4PyqEiZ7GOrKnduiBF6tkI34i +etQ4LvFmwloKfwPgAbRXtwp0XCnk+C/adT8fT16JGviHc4Q8fglUKZLVYJiqgb+x +CQZJrtWk7AgmiaeWQkfPcPbRGJjwXaJ7OvoFhXmZyDRWwOcCunQ= +-----END CERTIFICATE----- diff --git a/vault/diagnose/test-fixtures/selfSignedCert.pem b/vault/diagnose/test-fixtures/selfSignedCert.pem new file mode 100644 index 0000000000..1ae49f8447 --- /dev/null +++ b/vault/diagnose/test-fixtures/selfSignedCert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEujCCAqICCQC/sjLTDP0XszANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRn +aXRodWIuaGFzaGljb3JwLmNvbTAeFw0yMTA2MTYyMDUwNDRaFw0yMjA2MTYyMDUw +NDRaMB8xHTAbBgNVBAMMFGdpdGh1Yi5oYXNoaWNvcnAuY29tMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEA7a2YsR6fPZPYGpUDQVsSFJSaX7ZqOecQiuTa +gIbbiPNVWgznMwPtHVdmZjjZQspMM49ox6wXiT2WqBGIgraFB+VW00I8XMwM64ge +Pcr7NK8INgwphvlI9cbrHQYce6wWexLO/S7EJ0UFSns6LGRn8FctXIalu1HgkeT3 +jLpo3Fnr2UnwQAxljb8vW+5otpBDCRRXfgSq5dvZrPh+hxrfBNFZsd0gJGSJEzd1 +9485+e5cvSKs7kyaeQBlxEEBP/ai7zroPhzEyBTm7/2qnr8sWmpFUHIgC0zO8qf3 +TnJ6HDCGGwKXLEjHB+vrRBB4iAgDmUsYlW6G8A+U2hAAjTi3k2JHna5QBL7CEeza +U4GzyS2Kf3MQLLMyqntRIlotXzKBaoIQl8PSZZddyxWnd3qrwawYC4lDEFo1KnE5 +m+jUojXx84ioKwqj2vZ7+LT6kCErrT/Di47ii89Y7KibF26ZA3IcpUtYNeypHmt1 +A4eCxLIddf6rKtBwVb8cH/dvde/CErSQKsmA9LVvvm5V91y+oAyf6czpknU70F3h +YuCjFN347ipYSUYvDqvuIMnFo/gAqkonqDdYc7W7l1GMfvxr9c9oymqMml5W0FNM +77wnL6kUNJhlgaddVFHVWiUjeuX+G4uv2EemdzPmwB8BtC1X6ePEKUlWXVVg+OLf +hFdvor0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAjtrZzh9qx5RJ2vBLKugaLK80 +aFIxIOqIZ/oJOMeTvqK1NLUCrRHP7mjhvkB0sYs0OS1ypOjhDOM9ccfkh2q9hwzz +m/gCqeUUOL+tpvA3VQyxxX5OnFCLdXVMPGd74BBWrYyFoZj28yNqEOAIUU5seJL5 +A7bY/1rUG8YH1p82lPr8DOLg5OfPCIoaoOZE7i7/rL5j97RkFukYQX1pJiiPLfJi +s0cUOySSnnkqvo0u3UZIOexOlCLxfO32/UA1VW6/LBVitTVgzOSiORbkkXv+vxOZ +C/qr2XpEENj9vjP/1phPhyYDpVnrzXWPgJ30gl81IU+qTafONUzGftF7ELX0rNvK +5bFnEFJY7GeBdLLdUOxKlZ9L9Qd1d2Q+iQV25kwzf714dh/t4Oz4K0ZJ5mxpujcA +bbrEKMvqq7vIAfigHpI8W79BDEC7AP+QPSD1G3QzcxJRG2ctyfODXqTvw5zL/Fy7 +ZYLVWhJuNnHE1pHNmUDRiT8sYl1xGdrUofvSQrnhju9g3FYX/OARRDzFYRq4Dwq/ +ktZEcBcC6QN3fhVaefpsA+QdpMOdDwA+5NA7r7W3qqgAa9qoBdGtzKAzA9J1I67b +dGgdRrEjr6eP7enrOR+iymTWxun53H2Y4dseqrn18LmyrVV82dgLWH9xkWch5W0/ +kQXne4cSrE727hmkw4k= +-----END CERTIFICATE----- diff --git a/vault/diagnose/test-fixtures/twoRootCA.pem b/vault/diagnose/test-fixtures/twoRootCA.pem new file mode 100644 index 0000000000..75074dac08 --- /dev/null +++ b/vault/diagnose/test-fixtures/twoRootCA.pem @@ -0,0 +1,52 @@ +-----BEGIN CERTIFICATE----- +MIIDPDCCAiSgAwIBAgIUb5id+GcaMeMnYBv3MvdTGWigyJ0wDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAxMLZXhhbXBsZS5jb20wHhcNMTYwMjI5MDIyNzI5WhcNMjYw +MjI2MDIyNzU5WjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAOxTMvhTuIRc2YhxZpmPwegP86cgnqfT1mXxi1A7 +Q7qax24Nqbf00I3oDMQtAJlj2RB3hvRSCb0/lkF7i1Bub+TGxuM7NtZqp2F8FgG0 +z2md+W6adwW26rlxbQKjmRvMn66G9YPTkoJmPmxt2Tccb9+apmwW7lslL5j8H48x +AHJTMb+PMP9kbOHV5Abr3PT4jXUPUr/mWBvBiKiHG0Xd/HEmlyOEPeAThxK+I5tb +6m+eB+7cL9BsvQpy135+2bRAxUphvFi5NhryJ2vlAvoJ8UqigsNK3E28ut60FAoH +SWRfFUFFYtfPgTDS1yOKU/z/XMU2giQv2HrleWt0mp4jqBUCAwEAAaOBgTB/MA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSdxLNP/ocx +7HK6JT3/sSAe76iTmzAfBgNVHSMEGDAWgBSdxLNP/ocx7HK6JT3/sSAe76iTmzAc +BgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEA +wHThDRsXJunKbAapxmQ6bDxSvTvkLA6m97TXlsFgL+Q3Jrg9HoJCNowJ0pUTwhP2 +U946dCnSCkZck0fqkwVi4vJ5EQnkvyEbfN4W5qVsQKOFaFVzep6Qid4rZT6owWPa +cNNzNcXAee3/j6hgr6OQ/i3J6fYR4YouYxYkjojYyg+CMdn6q8BoV0BTsHdnw1/N +ScbnBHQIvIZMBDAmQueQZolgJcdOuBLYHe/kRy167z8nGg+PUFKIYOL8NaOU1+CJ +t2YaEibVq5MRqCbRgnd9a2vG0jr5a3Mn4CUUYv+5qIjP3hUusYenW1/EWtn1s/gk +zehNe5dFTjFpylg1o6b8Ow== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFjjCCA3agAwIBAgIBADANBgkqhkiG9w0BAQ0FADBYMQswCQYDVQQGEwJDQTEL +MAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8xFDASBgNVBAoMC2V4YW1wbGUu +Y29tMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yMTA2MTcxNTEyMDZaFw0zMTA2 +MTUxNTEyMDZaMFgxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwH +VG9yb250bzEUMBIGA1UECgwLZXhhbXBsZS5jb20xFDASBgNVBAMMC2V4YW1wbGUu +Y29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqhfgT3MSg+QfWFCp +RQ/z9GdrV3AGH/NMnlzpWFo39pUul8bGTSLiSNJZnfn4ZR6nL01gBVC14lD2W4a/ +az6tkAR1s0Rfn9EfZFW8dWesYs0t98ENvsW7kZnJTtZX822XquE65hYOxI7ul87L +XsbMQBoAuQk44kla2gJ0VIJosvA+LyZIHZXcA4UYL70mcqWn72D3hLkIzUpapG8f +czoGhLW51anScQnJ3MStnOsvTpk1QVsrHLACNala7Pe+OIXHrg9D4eZorX3TZRIo +EVOcHyJVx40BkTnGhjgTAFuhTvc1NqHW7IpcAQawNV583JIZ8RvTXmCQGsJEgiDO +1HP1wVc8uUyCsZ0J/qbUohdWdFpgAwM5OkOV+0QOkvhD4ZOvwK2NxBlIwOxDdhTl +BmiKoLutvTXIc1dT+bU3g5T4024ulfsG3ZISJAGWB8b0KKPFl8oT3DGruMAA7dLn +pa9a35FF4zyERm5PTYVNRg59+bbpYOeZbUS3SoJdenjcL/pV8z9bmeSsWTZf4GtD +5sfvlnamUcqVveBSGNJQ/4TkTrWqpyEbQTpiAndqetJEDb8Ta7K2IaFzWwvYYFkB +o2G1jvr7qB19yChedu3DREtsDz4jaBEVSw+oyLHdN37iaDksP7cgmnjsmTnO5SdR +zjHt24CuwdpdPPf3m3XxZfWgb9MCAwEAAaNjMGEwHQYDVR0OBBYEFAMnAelLpHMe +9SZiEpePe776QX+yMB8GA1UdIwQYMBaAFAMnAelLpHMe9SZiEpePe776QX+yMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBDQUAA4IC +AQAkyoX6Wzl7xWPa6rqSj3gxTDs8rKMCw6mmjLIRsKU+vRQ/a8uDYunJXQrDQ21e +AKJfCPRt+d/gTllJ/OOuDW55zRvJX486aIQzQnU4TGgj58HUYaA9z8pQEpCN36Dp +X0UWarGKDGBJ/fb3GJf71TXQgCLgd9IWgtN0Y59MMOQyiUYjulBcSD9eTTsSezcQ +OYTSybma8mZxERMmuEMWZUJl91PLBogAwelwoFoOoCDFyZXcnXD5yDL4uhzMG+px +0A2zWM8dYYq+Hn1zfzu5cyxeiyGSLYtaKxQCxZJ9FunSLwgLfYRH9YZx92ZcVuMG +FylUhQVEkH3d+Pjgys8q/avWGkj0LBzK8/KkZGzO/SMlIJRHtqQgzKi4hbc57vRQ +F32H8/zGTfwDwdjZSy4UvvATNLGbYa/nXYgGzqzQiQd5SIIBMzyG89ZeEsYb3EKD +rZPqDfhSzXs0gZj+JDgFCkro7203k1mRjXa/txfmjjGKEggPk80J2joeHHbsQOj2 +vLl/GE8XiLpT0rZQY1VvlrM0NdG/Ncfs9K3BZWh4yisspJgq6blURRhGV8rWHUMH +bnXMYXDb9bhmsbho0e+KYdN8EzdzZP0kX0Ro5uj6JlR+DtTX0MGQwawwdtrAbjGV +EDFilaw7tcZUQFXRmn5YTs8k7kowY8v5acOaeTJBoOSqBg== +-----END CERTIFICATE----- diff --git a/vault/diagnose/tls_verification.go b/vault/diagnose/tls_verification.go index e02b55017d..0270fa802a 100644 --- a/vault/diagnose/tls_verification.go +++ b/vault/diagnose/tls_verification.go @@ -8,8 +8,10 @@ import ( "encoding/pem" "fmt" "io/ioutil" + "strings" "time" + "github.com/hashicorp/vault/internalshared/configutil" "github.com/hashicorp/vault/internalshared/listenerutil" "github.com/hashicorp/vault/sdk/helper/tlsutil" ) @@ -52,16 +54,11 @@ func ListenerChecks(ctx context.Context, listeners []listenerutil.Listener) ([]s // Perform checks on the TLS Cryptographic Information. warnings, err := TLSFileChecks(l.TLSCertFile, l.TLSKeyFile) - for _, warning := range warnings { - warning = listenerID + ": " + warning - listenerWarnings = append(listenerWarnings, warning) - Warn(ctx, warning) - } - if err != nil { - errMsg := listenerID + ": " + err.Error() - listenerErrors = append(listenerErrors, fmt.Errorf(errMsg)) - Error(ctx, fmt.Errorf(errMsg)) - } + listenerWarnings, listenerErrors = outputError(ctx, warnings, listenerWarnings, err, listenerErrors, listenerID) + + // Perform checks on the Client CA Cert + warnings, err = TLSClientCAFileCheck(l) + listenerWarnings, listenerErrors = outputError(ctx, warnings, listenerWarnings, err, listenerErrors, listenerID) // TODO: Use listenerutil.TLSConfig to warn on incorrect protocol specified // Alternatively, use tlsutil.SetupTLSConfig. @@ -69,6 +66,21 @@ func ListenerChecks(ctx context.Context, listeners []listenerutil.Listener) ([]s return listenerWarnings, listenerErrors } +func outputError(ctx context.Context, newWarnings, listenerWarnings []string, newErr error, listenerErrors []error, listenerID string) ([]string, []error) { + for _, warning := range newWarnings { + warning = listenerID + ": " + warning + listenerWarnings = append(listenerWarnings, warning) + Warn(ctx, warning) + } + if newErr != nil { + errMsg := listenerID + ": " + newErr.Error() + listenerErrors = append(listenerErrors, fmt.Errorf(errMsg)) + Error(ctx, fmt.Errorf(errMsg)) + + } + return listenerWarnings, listenerErrors +} + // TLSFileChecks returns an error and warnings after checking TLS information func TLSFileChecks(certpath, keypath string) ([]string, error) { // Parse TLS Certs from the certpath @@ -136,13 +148,18 @@ func ParseTLSInformation(certFilePath string) ([]*x509.Certificate, []*x509.Cert leafCerts = append(leafCerts, cert) } } + return leafCerts, interCerts, rootCerts, nil } // TLSErrorChecks contains manual error checks against the TLS configuration func TLSErrorChecks(leafCerts, interCerts, rootCerts []*x509.Certificate) error { - // First, create root pools and interPools from the root and inter certs lists + // Make sure there's the proper number of leafCerts. If there are multiple, it's a bad pem file. + if len(leafCerts) == 0 { + return fmt.Errorf("No leaf certificates detected.") + } + // First, create root pools and interPools from the root and inter certs lists rootPool := x509.NewCertPool() interPool := x509.NewCertPool() @@ -153,29 +170,48 @@ func TLSErrorChecks(leafCerts, interCerts, rootCerts []*x509.Certificate) error interPool.AddCert(inter) } - // Make sure there's only one leaf. If there are multiple, it's a bad pem file. - if len(leafCerts) != 1 { - return fmt.Errorf("Number of leaf certificates detected is not one. Instead, it is: %d", len(leafCerts)) + var err error + // Verify checks that certificate isn't expired, is of correct usage type, and has an appropriate + // chain. We start with Root + for _, root := range rootCerts { + _, err = root.Verify(x509.VerifyOptions{ + Roots: rootPool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + }) + if err != nil { + return fmt.Errorf("failed to verify root certificate: %w", err) + } + } + + // Verifying intermediate certs + for _, inter := range interCerts { + _, err = inter.Verify(x509.VerifyOptions{ + Roots: rootPool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + }) + if err != nil { + return fmt.Errorf("failed to verify intermediate certificate: %w", err) + } } rootSubjs := rootPool.Subjects() - if len(rootSubjs) == 0 { + if len(rootSubjs) == 0 && len(leafCerts) > 0 { // this is a self signed server certificate, or the root is just not provided. In any // case, we need to bypass the root verification step by adding the leaf itself to the // root pool. rootPool.AddCert(leafCerts[0]) } - // Verify checks that certificate isn't expired, is of correct usage type, and has an appropriate - // chain. - _, err := leafCerts[0].Verify(x509.VerifyOptions{ - Roots: rootPool, - Intermediates: interPool, - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - }) - - if err != nil { - return fmt.Errorf("failed to verify primary provided leaf certificate: %w", err) + // Verifying leaf cert + for _, leaf := range leafCerts { + _, err = leaf.Verify(x509.VerifyOptions{ + Roots: rootPool, + Intermediates: interPool, + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + }) + if err != nil { + return fmt.Errorf("failed to verify primary provided leaf certificate: %w", err) + } } return nil @@ -185,6 +221,12 @@ func TLSErrorChecks(leafCerts, interCerts, rootCerts []*x509.Certificate) error // and root certificates provided. func TLSFileWarningChecks(leafCerts, interCerts, rootCerts []*x509.Certificate) ([]string, error) { var warnings []string + + // add a warning for when there are more than one leaf certs + if len(leafCerts) > 1 { + warnings = append(warnings, "leafCerts contains more than one cert.") + } + for _, c := range leafCerts { if willExpire, timeToExpiry := NearExpiration(c); willExpire { warnings = append(warnings, fmt.Sprintf("leaf certificate %d is expired or near expiry. Time to expire is: %s", c.SerialNumber, timeToExpiry)) @@ -214,3 +256,76 @@ func NearExpiration(c *x509.Certificate) (bool, time.Duration) { } return false, timeToExpiry } + +// TLSMutualExclusionCertCheck returns error if both TLSDisableClientCerts and TLSRequireAndVerifyClientCert are set +func TLSMutualExclusionCertCheck(l *configutil.Listener) error { + + if l.TLSDisableClientCerts { + if l.TLSRequireAndVerifyClientCert { + return fmt.Errorf("the tls_disable_client_certs and tls_require_and_verify_client_cert fields in the " + + "listener stanza of the vault server config are mutually exclusive fields. Please ensure they are not both set to true.") + } + } + return nil +} + +// TLSClientCAFileCheck Checks the validity of a client CA file +func TLSClientCAFileCheck(l *configutil.Listener) ([]string, error) { + + if l.TLSDisableClientCerts { + return nil, nil + } else if !l.TLSRequireAndVerifyClientCert { + return nil, nil + } + + var warningsSlc []string + + // Parse TLS Certs from the tls config + leafCerts, interCerts, rootCerts, err := ParseTLSInformation(l.TLSClientCAFile) + if err != nil { + return nil, err + } + + if len(rootCerts) == 0 { + return nil, fmt.Errorf("No root cert found!") + } + if len(rootCerts) > 1 { + warningsSlc = append(warningsSlc, fmt.Sprintf("Found Multiple rootCerts instead of just one!")) + } + + // Checking for Self-Signed cert and return an explicit error about it. + // Self-Signed certs are placed in the leafCerts slice when parsed. + if len(leafCerts) > 0 && !leafCerts[0].IsCA && bytes.Equal(leafCerts[0].RawIssuer, leafCerts[0].RawSubject) { + return warningsSlc, fmt.Errorf("Found a Self-Signed certificate!") + } + + if len(interCerts) > 0 { + return warningsSlc, fmt.Errorf("Found at least one intermediate cert in a root CA cert.") + } + + if len(leafCerts) > 0 { + return warningsSlc, fmt.Errorf("Found at least one leafCert in a root CA cert.") + } + + var warnings []string + // Check for TLS Warnings + warnings, err = TLSFileWarningChecks(leafCerts, interCerts, rootCerts) + warningsSlc = append(warningsSlc, warnings...) + for i, warning := range warningsSlc { + warningsSlc[i] = strings.Replace(warning, "leaf", "root", -1) + } + if err != nil { + return warningsSlc, err + } + + // Adding rootCerts to leafCert to perform verification in TLSErrorChecks + leafCerts = append(leafCerts, rootCerts[0]) + + // Check for TLS Errors + if err = TLSErrorChecks(leafCerts, interCerts, rootCerts); err != nil { + return warningsSlc, fmt.Errorf(strings.Replace(err.Error(), "leaf", "root", -1)) + } + + return warningsSlc, err + +} diff --git a/vault/diagnose/tls_verification_test.go b/vault/diagnose/tls_verification_test.go index a10b4d8057..1eefb4fbad 100644 --- a/vault/diagnose/tls_verification_test.go +++ b/vault/diagnose/tls_verification_test.go @@ -16,14 +16,13 @@ func TestTLSValidCert(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/goodcertwithroot.pem", - TLSKeyFile: "./test-fixtures/goodkey.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/goodcertwithroot.pem", + TLSKeyFile: "./test-fixtures/goodkey.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -42,14 +41,13 @@ func TestTLSFakeCert(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/fakecert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/fakecert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -73,14 +71,13 @@ func TestTLSTrailingData(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/trailingdatacert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/trailingdatacert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -99,14 +96,13 @@ func TestTLSExpiredCert(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/expiredcert.pem", - TLSKeyFile: "./test-fixtures/expiredprivatekey.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/expiredcert.pem", + TLSKeyFile: "./test-fixtures/expiredprivatekey.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -121,7 +117,7 @@ func TestTLSExpiredCert(t *testing.T) { t.Fatalf("TLS Config check on fake certificate should warn") } if !strings.Contains(warnings[0], "expired or near expiry") { - t.Fatalf("Bad warning: %s", errs[0]) + t.Fatalf("Bad warning: %s", warnings[0]) } } @@ -131,14 +127,13 @@ func TestTLSMismatchedCryptographicInfo(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./test-fixtures/ecdsa.key", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./test-fixtures/ecdsa.key", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -153,15 +148,14 @@ func TestTLSMismatchedCryptographicInfo(t *testing.T) { listeners = []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/ecdsa.crt", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/ecdsa.crt", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -179,15 +173,14 @@ func TestTLSMultiKeys(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/key.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/key.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -201,18 +194,17 @@ func TestTLSMultiKeys(t *testing.T) { } // TestTLSMultiCerts verifies that a unique error message is thrown when a cert is specified twice. -func TestTLSMultiCerts(t *testing.T) { +func TestTLSCertAsKey(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/cert.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/cert.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -232,14 +224,13 @@ func TestTLSInvalidRoot(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./test-fixtures/goodcertbadroot.pem", - TLSKeyFile: "./test-fixtures/goodkey.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./test-fixtures/goodcertbadroot.pem", + TLSKeyFile: "./test-fixtures/goodkey.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -259,14 +250,13 @@ func TestTLSNoRoot(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./test-fixtures/goodkey.pem", - TLSMinVersion: "tls10", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./test-fixtures/goodkey.pem", + TLSMinVersion: "tls10", + TLSDisableClientCerts: true, }, }, } @@ -282,15 +272,14 @@ func TestTLSInvalidMinVersion(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", - TLSMinVersion: "0", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMinVersion: "0", + TLSDisableClientCerts: true, }, }, } @@ -309,15 +298,14 @@ func TestTLSInvalidMaxVersion(t *testing.T) { listeners := []listenerutil.Listener{ { Config: &configutil.Listener{ - Type: "tcp", - Address: "127.0.0.1:443", - ClusterAddress: "127.0.0.1:8201", - TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", - TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", - TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", - TLSMaxVersion: "0", - TLSRequireAndVerifyClientCert: true, - TLSDisableClientCerts: false, + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "0", + TLSDisableClientCerts: true, }, }, } @@ -329,3 +317,260 @@ func TestTLSInvalidMaxVersion(t *testing.T) { t.Fatalf("Bad error message: %s", errs[0]) } } + +// TestDisabledClientCertsAndDisabledTLSClientCAVerfiy checks that a listener works properly when both +// TLSRequireAndVerifyClientCert and TLSDisableClientCerts are false +func TestDisabledClientCertsAndDisabledTLSClientCAVerfiy(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: false, + TLSDisableClientCerts: false, + }, + }, + } + err := TLSMutualExclusionCertCheck(listeners[0].Config) + if err != nil { + t.Fatalf("TLS config failed when both TLSRequireAndVerifyClientCert and TLSDisableClientCerts are false") + } +} + +// TestTLSClientCAVerfiy checks that a listener which has TLS client certs checks enabled works as expected +func TestTLSClientCAVerfiy(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + err := TLSMutualExclusionCertCheck(listeners[0].Config) + if err != nil { + t.Fatalf("TLS config check failed with %s", err) + } +} + +// TestTLSClientCAVerfiySkip checks that TLS client cert checks are skipped if TLSDisableClientCerts is true +// regardless of the value for TLSRequireAndVerifyClientCert +func TestTLSClientCAVerfiySkip(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: false, + TLSDisableClientCerts: true, + }, + }, + } + err := TLSMutualExclusionCertCheck(listeners[0].Config) + if err != nil { + t.Fatalf("TLS config check did not skip verification and failed with %s", err) + } +} + +// TestTLSClientCAVerfiyMutualExclusion checks that TLS client cert checks are skipped if TLSDisableClientCerts is true +// regardless of the value for TLSRequireAndVerifyClientCert +func TestTLSClientCAVerfiyMutualExclusion(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: true, + }, + }, + } + err := TLSMutualExclusionCertCheck(listeners[0].Config) + if err == nil { + t.Fatalf("TLS config check should have failed when both 'tls_disable_client_certs' and 'tls_require_and_verify_client_cert' are true") + } + if !strings.Contains(err.Error(), "the tls_disable_client_certs and tls_require_and_verify_client_cert fields in the "+ + "listener stanza of the vault server config are mutually exclusive fields") { + t.Fatalf("Bad error message: %s", err) + } +} + +// TestTLSClientCAVerfiy checks that a listener which has TLS client certs checks enabled works as expected +func TestTLSClientCAFileCheck(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./../../api/test-fixtures/root/rootcacert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + warnings, errs := ListenerChecks(context.Background(), listeners) + if errs != nil { + t.Fatalf("TLS config check failed while a good ClientCAFile was used") + } + if warnings != nil { + t.Fatalf("TLS config check return warning while a good ClientCAFile was used") + } +} + +// TestTLSLeafCertInClientCAFile checks if a leafCert exist in TLSClientCAFile +func TestTLSLeafCertInClientCAFile(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./test-fixtures/goodcertbadroot.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + _, errs := ListenerChecks(context.Background(), listeners) + if errs == nil || len(errs) != 1 { + t.Fatalf("TLS Config check on bad ClientCAFile certificate should fail") + } + if !strings.Contains(errs[0].Error(), "Found at least one leafCert in a root CA cert.") { + t.Fatalf("Bad error message: %s", errs[0]) + } +} + +// TestTLSNoRootInClientCAFile checks if no Root cert exist in TLSClientCAFile +func TestTLSNoRootInClientCAFile(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./test-fixtures/intermediateCert.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + _, errs := ListenerChecks(context.Background(), listeners) + if errs == nil { + t.Fatalf("TLS Config check on bad ClientCAFile certificate should fail") + } + if !strings.Contains(errs[0].Error(), "No root cert found!") { + t.Fatalf("Bad error message: %s", errs[0]) + } +} + +// TestTLSIntermediateCertInClientCAFile checks if an intermediate cert is included in TLSClientCAFile +func TestTLSIntermediateCertInClientCAFile(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./test-fixtures/chain.crt.pem", + TLSMaxVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + _, errs := ListenerChecks(context.Background(), listeners) + if errs == nil || len(errs) != 1 { + t.Fatalf("TLS Config check on bad ClientCAFile certificate should fail") + } + if !strings.Contains(errs[0].Error(), "Found at least one intermediate cert in a root CA cert.") { + t.Fatalf("Bad error message: %s", errs[0]) + } +} + +// TestTLSMultipleRootInClietCACert checks if multiple roots included in TLSClientCAFile +func TestTLSMultipleRootInClietCACert(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "./test-fixtures/twoRootCA.pem", + TLSMinVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + warnings, errs := ListenerChecks(context.Background(), listeners) + if errs != nil { + t.Fatalf("TLS Config check on valid certificate should not fail") + } + if warnings == nil { + t.Fatalf("TLS Config check on valid but bad certificate should warn") + } + if !strings.Contains(warnings[0], "Found Multiple rootCerts instead of just one!") { + t.Fatalf("Bad warning: %s", warnings[0]) + } +} + +func TestTLSSelfSignedCert(t *testing.T) { + listeners := []listenerutil.Listener{ + { + Config: &configutil.Listener{ + Type: "tcp", + Address: "127.0.0.1:443", + ClusterAddress: "127.0.0.1:8201", + TLSCertFile: "./../../api/test-fixtures/keys/cert.pem", + TLSKeyFile: "./../../api/test-fixtures/keys/key.pem", + TLSClientCAFile: "test-fixtures/selfSignedCert.pem", + TLSMinVersion: "tls10", + TLSRequireAndVerifyClientCert: true, + TLSDisableClientCerts: false, + }, + }, + } + _, errs := ListenerChecks(context.Background(), listeners) + if errs == nil { + t.Fatalf("Self-signed certificate is insecure") + } + if !strings.Contains(errs[0].Error(), "No root cert found!") { + t.Fatalf("Bad error message: %s", errs[0]) + } +}