package evaluator import ( "testing" "github.com/stretchr/testify/assert" ) // These certificates can be regenerated by running: // // go run ./gen-test-certs.go // // (Copy and paste the output here.) const ( testCA = ` -----BEGIN CERTIFICATE----- MIIBaTCCAQ6gAwIBAgICEAAwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA2MjExMzI0WjAaMRgw FgYDVQQDEw9UcnVzdGVkIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AATcFCe6i6IqnevuUoR8nTrka8fikGYB3ciKfRyS0NUfm27MGsbuU2ribMYjhuz2 K4/nU7A2hcu393JNKriXgwoyo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQU0SX0xv9f6gYAcLC926z+Bt9vTAMwCgYIKoZIzj0E AwIDSQAwRgIhAJIFP4r9Gbo0D2MM/fzPx5wtXsjH1IoQMpn0aw+G1WkmAiEAi56g gO7l3bJj1YZtBv3tEkZPzaZ+xL3Nllcjv1K12Ac= -----END CERTIFICATE----- ` testValidCert = ` -----BEGIN CERTIFICATE----- MIIBYTCCAQigAwIBAgICEAEwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA2MjExMzI0WjAeMRww GgYDVQQDExN0cnVzdGVkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAE3xjPIJPp9v+qu89DNHnqcIfkOSkLb8irRAnFmAYdJJLRqWRNRjmzRHtZ htT4TWvhEw6VsFbRlsd510+dEASm9aM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw HwYDVR0jBBgwFoAU0SX0xv9f6gYAcLC926z+Bt9vTAMwCgYIKoZIzj0EAwIDRwAw RAIgYZaCYXhfBBR8w/AfqUm9MVLYrgkz78mndNFFjz+YvpwCIFsfyIjft/vRcuaU xlJFtrmFMSt4x1TecZfJsWDA0M55 -----END CERTIFICATE----- ` testUntrustedCert = ` -----BEGIN CERTIFICATE----- MIIBZzCCAQygAwIBAgICEAEwCgYIKoZIzj0EAwIwHDEaMBgGA1UEAxMRVW50cnVz dGVkIFJvb3QgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDYyMTEzMjRaMCAx HjAcBgNVBAMTFXVudHJ1c3RlZCBjbGllbnQgY2VydDBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABCLf7g3vlTE+xuIDttn/FYMpAAzlCKqr37rzBnBtuEhCDypW6Y/Y MbIboFx9o2M9FYLzDJCS7Bj3cp2qd145HdqjODA2MBMGA1UdJQQMMAoGCCsGAQUF BwMCMB8GA1UdIwQYMBaAFGGTTkLU8r+tXUCs+nMR5Xm3KkgLMAoGCCqGSM49BAMC A0kAMEYCIQCELFkfQak8X+Yvc7H95j+shSnVgwUuOYT1Lv2NLT1qPAIhAMEvKiwc ZkWK0F4PJLpSt1wsbnVtfK7kXwHxdp2Z8yy7 -----END CERTIFICATE----- ` testRevokedCert = ` -----BEGIN CERTIFICATE----- MIIBYTCCAQigAwIBAgICEAIwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA2MjExMzI0WjAeMRww GgYDVQQDExNyZXZva2VkIGNsaWVudCBjZXJ0MFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAENFshpve+if3UmlNyPi5sVz8A03F9AAt6u1LxqiR5cMO6eU+L91Bey/XC XYrqgpJzbRgTuC4LCFx6cwwl5ff/4KM4MDYwEwYDVR0lBAwwCgYIKwYBBQUHAwIw HwYDVR0jBBgwFoAU0SX0xv9f6gYAcLC926z+Bt9vTAMwCgYIKoZIzj0EAwIDRwAw RAIgappua0SnpXDzp9nml4iHqKtYAHTn/rg0w405ahdqBQwCIHulKmPGFNLDw1dq 1bZyKsG1t58DfFsO9G27sRssvCgV -----END CERTIFICATE----- ` testCRL = ` -----BEGIN X509 CRL----- MIHeMIGFAgEBMAoGCCqGSM49BAMCMBoxGDAWBgNVBAMTD1RydXN0ZWQgUm9vdCBD QRgPMDAwMTAxMDEwMDAwMDBaMBUwEwICEAIXDTIzMDgwOTIxMTMyNFqgMDAuMB8G A1UdIwQYMBaAFNEl9Mb/X+oGAHCwvdus/gbfb0wDMAsGA1UdFAQEAgIgADAKBggq hkjOPQQDAgNIADBFAiEA1QoleqO9qKhxSxKUc+SOQlFTG9sTbs3ztniUhi0CxhAC IBElm/lXpVVuWrt0PJhcQHhHqbOxnfkx3HUxVEBWMOzX -----END X509 CRL----- ` testIntermediateCA = ` -----BEGIN CERTIFICATE----- MIIBkjCCATegAwIBAgICEAMwCgYIKoZIzj0EAwIwGjEYMBYGA1UEAxMPVHJ1c3Rl ZCBSb290IENBMCAYDzAwMDEwMTAxMDAwMDAwWhcNMzMwODA2MjExMzI0WjAiMSAw HgYDVQQDExdUcnVzdGVkIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABJyxF8EUBMMh/avAul6M8AjoKstuIULPIHOvjYftT/hSqGHNYM6g 0NIBW1g2QX/fnHG9tBy45ReTkVY5HMoO2wujYzBhMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRe0Fh8zjBKzxms/xpbS/vHY5hqujAf BgNVHSMEGDAWgBTRJfTG/1/qBgBwsL3brP4G329MAzAKBggqhkjOPQQDAgNJADBG AiEAsnob34JrBGbJjoTZS84mfno2Vb+QPJ1xy3U7AbgyYM4CIQCL3P2A3w1Z87Nr 0A/i8rXw+kiGP1OHbs4k85ZIg6FAtQ== -----END CERTIFICATE----- ` testValidIntermediateCert = ` -----BEGIN CERTIFICATE----- MIIBdTCCARqgAwIBAgICEAAwCgYIKoZIzj0EAwIwIjEgMB4GA1UEAxMXVHJ1c3Rl ZCBJbnRlcm1lZGlhdGUgQ0EwIBgPMDAwMTAxMDEwMDAwMDBaFw0zMzA4MDYyMTEz MjRaMCgxJjAkBgNVBAMTHWNsaWVudCBjZXJ0IGZyb20gaW50ZXJtZWRpYXRlMFkw EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvv9cmqtcuPuSXv6Qup0ycveDtx4PYC4V UKp5BU1B/1h/IupoIlX165rERkNCxyDXjfw5zkcHXsP1qRbc3LSXT6M4MDYwEwYD VR0lBAwwCgYIKwYBBQUHAwIwHwYDVR0jBBgwFoAUXtBYfM4wSs8ZrP8aW0v7x2OY arowCgYIKoZIzj0EAwIDSQAwRgIhAJJwdjSiC3avGDc1KZo/AZ1cMPDcFZkI92E6 BVAnH/e8AiEAjy8cP1msG62BeDaAVU5NcU9RAXDw1Oz4HkpELXQWqK8= -----END CERTIFICATE----- ` ) func Test_isValidClientCertificate(t *testing.T) { t.Run("no ca", func(t *testing.T) { valid, err := isValidClientCertificate("", "", ClientCertificateInfo{Leaf: "WHATEVER!"}) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") }) t.Run("no cert", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{}) assert.NoError(t, err, "should not return an error") assert.False(t, valid, "should return false") }) t.Run("valid cert", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{ Presented: true, Leaf: testValidCert, }) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") }) t.Run("valid cert with intermediate", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{ Presented: true, Leaf: testValidIntermediateCert, Intermediates: testIntermediateCA, }) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") }) t.Run("valid cert missing intermediate", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{ Presented: true, Leaf: testValidIntermediateCert, Intermediates: "", }) assert.NoError(t, err, "should not return an error") assert.False(t, valid, "should return false") }) t.Run("intermediate CA as root", func(t *testing.T) { valid, err := isValidClientCertificate(testIntermediateCA, "", ClientCertificateInfo{ Presented: true, Leaf: testValidIntermediateCert, }) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") }) t.Run("unsigned cert", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{ Presented: true, Leaf: testUntrustedCert, }) assert.NoError(t, err, "should not return an error") assert.False(t, valid, "should return false") }) t.Run("not a cert", func(t *testing.T) { valid, err := isValidClientCertificate(testCA, "", ClientCertificateInfo{ Presented: true, Leaf: "WHATEVER!", }) assert.Error(t, err, "should return an error") assert.False(t, valid, "should return false") }) t.Run("revoked cert", func(t *testing.T) { revokedCertInfo := ClientCertificateInfo{ Presented: true, Leaf: testRevokedCert, } // The "revoked cert" should otherwise be valid (when no CRL is specified). valid, err := isValidClientCertificate(testCA, "", revokedCertInfo) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") valid, err = isValidClientCertificate(testCA, testCRL, revokedCertInfo) assert.NoError(t, err, "should not return an error") assert.False(t, valid, "should return false") // Specifying a CRL containing the revoked cert should not affect other certs. valid, err = isValidClientCertificate(testCA, testCRL, ClientCertificateInfo{ Presented: true, Leaf: testValidCert, }) assert.NoError(t, err, "should not return an error") assert.True(t, valid, "should return true") }) t.Run("missing CRL", func(t *testing.T) { // If a CRL is provided for any CA, it must be provided for all CAs. valid, err := isValidClientCertificate(testCA, testCRL, ClientCertificateInfo{ Presented: true, Leaf: testValidIntermediateCert, Intermediates: testIntermediateCA, }) assert.NoError(t, err, "should not return an error") assert.False(t, valid, "should return false") }) }