/* Copyright 2014 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package x509 import ( "crypto/tls" "crypto/x509" "encoding/pem" "errors" "io/ioutil" "net/http" "reflect" "sort" "testing" "time" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" ) const ( /* > rootCACert openssl genrsa -out root.key 1024 && \ openssl rsa -in ./root.key -outform PEM -pubout -out ./root.pub && \ CONFIG="[ v3_req ]\n" && \ CONFIG="${CONFIG}subjectKeyIdentifier=hash\n" && \ CONFIG="${CONFIG}authorityKeyIdentifier=keyid:always,issuer\n" && \ CONFIG="${CONFIG}basicConstraints=CA:TRUE\n" && \ CONFIG="${CONFIG}keyUsage=keyCertSign,cRLSign\n" && \ openssl req -new -x509 -days 36500 \ -sha1 -key root.key \ -out root.crt \ -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=ROOT CA" \ -config <(printf "${CONFIG}") \ -extensions v3_req \ && \ openssl x509 -in root.crt -text > output Certificate: Data: Version: 3 (0x2) Serial Number: 2d:73:1a:2e:d7:8b:89:20:83:9c:42:9a:6e:f7:f5:f6:a1:ec:af:8c Signature Algorithm: sha1WithRSAEncryption Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA Validity Not Before: May 2 05:43:51 2024 GMT Not After : Apr 8 05:43:51 2124 GMT Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a8:c3:dc:de:1a:f6:3e:95:97:2a:d5:bf:8b:72: 93:06:85:72:4b:36:2a:d9:63:a8:9c:fb:80:3e:9b: 2f:84:c6:57:d2:ff:33:13:bf:32:e9:90:66:db:0a: 9a:05:c1:e3:c1:09:bb:25:75:b2:d7:fc:9c:09:86: 80:15:b0:6c:67:c5:1a:e9:76:01:32:40:22:58:ec: 4e:a1:b7:c5:05:01:49:55:d8:4f:4b:88:1d:bf:66: d3:de:58:4a:e7:26:b6:bf:af:33:d8:57:42:f1:bc: 34:67:44:88:b4:31:f6:4a:4a:b3:1e:c2:ca:6b:4b: 2e:5a:32:23:9b:1b:3f:97:35 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B X509v3 Authority Key Identifier: D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B X509v3 Basic Constraints: CA:TRUE X509v3 Key Usage: Certificate Sign, CRL Sign Signature Algorithm: sha1WithRSAEncryption Signature Value: 4a:54:07:46:71:c1:b2:a2:d3:32:e7:df:49:8c:af:87:46:ab: 81:11:c6:c5:4b:be:0b:0c:ea:7e:5f:38:14:79:43:92:f9:bb: 82:6f:f6:06:a6:43:19:e2:7c:52:66:36:13:6f:0f:73:16:3d: 79:5f:f9:a6:c8:4c:18:f9:ff:20:2b:de:7f:15:e0:ab:ae:44: fa:65:7a:86:8a:df:d0:63:82:b1:5c:f3:f8:5c:05:97:4e:1f: 09:d6:d9:55:e7:36:fc:08:3e:3f:66:99:68:b6:31:44:0f:63: 20:6a:b2:81:50:39:19:d0:47:de:20:94:f0:a2:2c:eb:69:93: 93:a3 -----BEGIN CERTIFICATE----- MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0 eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0 MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY 6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9 eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M= -----END CERTIFICATE----- */ rootCACert = `-----BEGIN CERTIFICATE----- MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0 eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0 MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY 6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9 eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M= -----END CERTIFICATE----- ` /* > selfSignedCert openssl genrsa -out selfsign.key 1024 && \ openssl req -new -x509 -days 36500 \ -sha1 -key selfsign.key \ -out selfsign.crt \ -subj "/C=US/ST=My State/L=My City/O=My Org/O=My Unit/CN=self1" \ && \ openssl x509 -in selfsign.crt -text > output Certificate: Data: Version: 3 (0x2) Serial Number: 72:ae:28:f9:b7:7f:16:0a:89:a7:9c:a1:a3:88:15:4b:20:eb:f5:b2 Signature Algorithm: sha1WithRSAEncryption Issuer: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1 Validity Not Before: May 2 00:25:12 2024 GMT Not After : Apr 8 00:25:12 2124 GMT Subject: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:94:91:e3:8a:4d:dd:f6:27:e9:71:9c:d2:f2:64: b9:af:ce:05:9d:82:a2:98:a9:15:40:8b:ff:a2:5c: 72:53:e8:d0:af:73:c6:76:4d:c7:6a:6e:9f:5d:a7: e2:f6:aa:6a:18:2b:c3:ee:3b:64:19:16:5d:94:0b: f2:f7:90:43:9a:5d:ce:7e:07:4d:b9:df:be:f0:39: 98:a4:41:eb:d3:17:90:12:d9:bc:d7:7f:a4:66:98: c3:91:17:30:5d:7b:c4:12:2b:a9:a9:48:ca:a3:14: 3a:36:ad:23:58:cf:88:b9:30:9a:b4:e6:8a:35:a1: ce:80:02:4a:aa:24:2b:7b:79 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16 X509v3 Authority Key Identifier: 56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16 X509v3 Basic Constraints: critical CA:TRUE Signature Algorithm: sha1WithRSAEncryption Signature Value: 5e:84:19:68:a2:f3:41:c5:f5:57:2f:1b:e5:14:4d:8c:50:ee: 5f:f4:aa:ec:4f:6a:06:4b:af:f3:2a:14:cc:0f:7b:a1:17:de: cc:da:f8:fb:c3:04:c7:a7:60:98:76:5c:32:82:5c:ec:95:a0: 51:74:12:12:c0:7a:8b:68:bc:8b:47:47:db:95:20:34:be:69: d2:fc:d5:d7:e7:4b:7c:e1:f3:bc:72:3c:b1:f5:d4:db:71:ad: d8:a7:ad:ab:91:68:c9:16:0a:e9:76:ed:87:0f:83:24:cd:ab: c7:a4:16:3f:c6:7c:99:18:bb:b1:12:11:a4:a5:99:af:17:11: e7:b1 -----BEGIN CERTIFICATE----- MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0 quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY u7ESEaSlma8XEeex -----END CERTIFICATE----- */ selfSignedCert = `-----BEGIN CERTIFICATE----- MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0 quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY u7ESEaSlma8XEeex -----END CERTIFICATE----- ` /* > clientCNCert openssl genrsa -out client.key 1024 && \ openssl rsa -in ./client.key -outform PEM \ -pubout -out ./client.pub && \ openssl req -key ./client.key -new\ -sha1 -out ./client.csr \ -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=client_cn" \ && \ EXTFILE="subjectKeyIdentifier=hash\n" && \ EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \ EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \ EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \ EXTFILE="${EXTFILE}extendedKeyUsage=clientAuth\n" && \ openssl x509 -req -days 36500 \ -in ./client.csr \ -extfile <(printf "${EXTFILE}") \ -CA ./root.crt \ -CAkey ./root.key \ -set_serial 1 \ -sha256 \ -out ./client.crt \ && \ openssl x509 -in client.crt -text > output is below */ clientCNCert = `Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA Validity Not Before: May 2 05:46:24 2024 GMT Not After : Apr 8 05:46:24 2124 GMT Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = client_cn Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:bd:3f:2d:d1:86:73:6d:b5:09:9c:ff:42:fb:27: 8e:07:69:a3:b6:d1:c7:72:d1:de:98:14:a5:61:9b: 83:03:1d:da:54:d1:d4:0d:7f:de:98:2e:cc:db:6f: e4:19:c7:41:43:59:ff:34:7b:82:06:80:01:ab:79: b3:40:d3:45:1f:52:2d:10:f9:55:40:a7:7a:61:f7: fd:9c:41:eb:d1:ec:7e:30:ca:1a:fa:0e:9e:0f:1e: 50:93:9a:ca:55:ea:64:80:6e:bb:49:7d:12:15:d8: 6f:a8:aa:3f:b9:10:24:6f:72:22:e9:4f:f3:a4:29: 1e:4e:71:a6:82:af:39:78:a9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F X509v3 Authority Key Identifier: D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: X509v3 Extended Key Usage: TLS Web Client Authentication Signature Algorithm: sha256WithRSAEncryption Signature Value: 6b:24:0f:2f:81:46:32:c4:c1:57:09:cd:64:6d:9f:50:ee:29: 4d:a7:14:d0:a0:0c:ea:a6:dc:e5:15:52:9a:42:08:eb:a2:91: 3c:ce:94:0e:f0:82:bc:fd:d7:23:d1:ad:d1:98:07:94:05:fa: ca:37:45:d7:f0:7d:aa:d2:ec:94:2b:8b:03:85:00:fb:af:1d: 35:28:53:a8:1d:f8:44:e1:ea:48:3f:a4:2a:46:3b:f6:19:bf: 30:df:b2:0e:8d:79:b0:0a:f5:34:c7:8a:6d:bf:58:39:9d:5d: a1:f5:35:a0:54:87:98:c6:5d:bf:ea:4e:46:f9:47:6d:d7:e6: 5a:f3 -----BEGIN CERTIFICATE----- MIICtTCCAh6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15 IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1 MDIwNTQ2MjRaGA8yMTI0MDQwODA1NDYyNFowaTELMAkGA1UEBhMCVVMxETAPBgNV BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCWNsaWVudF9jbjCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAvT8t0YZzbbUJnP9C+yeOB2mjttHHctHemBSlYZuD Ax3aVNHUDX/emC7M22/kGcdBQ1n/NHuCBoABq3mzQNNFH1ItEPlVQKd6Yff9nEHr 0ex+MMoa+g6eDx5Qk5rKVepkgG67SX0SFdhvqKo/uRAkb3Ii6U/zpCkeTnGmgq85 eKkCAwEAAaNtMGswHQYDVR0OBBYEFPt31tCEqBDf+k6k4PEqu7SA/U8/MB8GA1Ud IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw ADATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQBrJA8vgUYy xMFXCc1kbZ9Q7ilNpxTQoAzqptzlFVKaQgjropE8zpQO8IK8/dcj0a3RmAeUBfrK N0XX8H2q0uyUK4sDhQD7rx01KFOoHfhE4epIP6QqRjv2Gb8w37IOjXmwCvU0x4pt v1g5nV2h9TWgVIeYxl2/6k5G+Udt1+Za8w== -----END CERTIFICATE-----` /* > serverCert openssl genrsa -out server.key 1024 && \ openssl rsa -in ./server.key -outform PEM \ -pubout -out ./server.pub && \ openssl req -key ./server.key -new\ -sha1 -out ./server.csr \ -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=127.0.0.1" \ && \ EXTFILE="subjectKeyIdentifier=hash\n" && \ EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \ EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \ EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \ EXTFILE="${EXTFILE}extendedKeyUsage=serverAuth\n" && \ openssl x509 -req -days 36500 \ -in ./server.csr \ -extfile <(printf "${EXTFILE}") \ -CA ./root.crt \ -CAkey ./root.key \ -set_serial 7 \ -sha256 \ -out ./server.crt \ && \ openssl x509 -in server.crt -text > output is below */ serverCert = `Certificate: Data: Version: 3 (0x2) Serial Number: 7 (0x7) Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA Validity Not Before: May 2 05:47:31 2024 GMT Not After : Apr 8 05:47:31 2124 GMT Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = 127.0.0.1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:9d:1f:c3:9e:ac:51:92:27:df:2a:3a:48:b7:59: 40:23:a5:c3:a1:61:71:7a:00:df:d5:8b:a2:8a:7c: 54:f0:19:69:fe:ae:19:a3:e1:eb:1e:1b:39:2c:61: fb:7b:21:10:81:b2:ef:29:94:b6:14:6f:ca:eb:4d: f3:f6:84:93:5f:51:2c:7a:ab:9f:34:05:15:62:c4: 55:54:2e:75:b9:26:d1:0e:c5:63:41:e5:36:02:3f: 1c:5f:fc:1b:07:20:d2:1c:70:a5:a1:e8:08:1d:8f: 4c:c3:57:e0:54:72:a6:c9:24:1b:b0:fa:0d:86:f5: 26:1f:20:e5:1c:1c:c3:8f:d3 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: F2:AE:B7:50:D5:02:C1:E9:8D:38:0E:76:A5:D8:24:0B:1C:DB:08:0E X509v3 Authority Key Identifier: D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B X509v3 Basic Constraints: CA:FALSE X509v3 Subject Alternative Name: X509v3 Extended Key Usage: TLS Web Server Authentication Signature Algorithm: sha256WithRSAEncryption Signature Value: 3f:3d:d1:5d:d5:9f:c1:ab:6e:ba:c1:c2:1b:63:1a:a8:4f:d9: df:03:13:ff:6d:a8:ed:c9:8d:19:a6:8f:a6:e2:a8:23:a0:f7: 5d:5e:22:01:d1:29:9b:d0:95:75:66:46:f2:51:a7:08:1c:8c: aa:ca:4a:57:d8:ab:ed:1b:b3:77:25:58:38:1f:89:e0:a4:13: 0a:f2:99:d5:3d:24:00:08:06:7e:b3:1a:b0:0b:07:33:a7:c7: ff:f8:ef:bc:7c:c9:2e:aa:3f:7a:3e:8e:8a:49:cf:a4:5a:b5: 41:07:57:f1:36:f4:57:dc:6e:3f:70:38:0d:4e:71:9c:24:20: b4:36 -----BEGIN CERTIFICATE----- MIICtTCCAh6gAwIBAgIBBzANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15 IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1 MDIwNTQ3MzFaGA8yMTI0MDQwODA1NDczMVowaTELMAkGA1UEBhMCVVMxETAPBgNV BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCTEyNy4wLjAuMTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAnR/DnqxRkiffKjpIt1lAI6XDoWFxegDf1YuiinxU 8Blp/q4Zo+HrHhs5LGH7eyEQgbLvKZS2FG/K603z9oSTX1EsequfNAUVYsRVVC51 uSbRDsVjQeU2Aj8cX/wbByDSHHCloegIHY9Mw1fgVHKmySQbsPoNhvUmHyDlHBzD j9MCAwEAAaNtMGswHQYDVR0OBBYEFPKut1DVAsHpjTgOdqXYJAsc2wgOMB8GA1Ud IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw ADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOBgQA/PdFd1Z/B q266wcIbYxqoT9nfAxP/bajtyY0Zpo+m4qgjoPddXiIB0Smb0JV1ZkbyUacIHIyq ykpX2KvtG7N3JVg4H4ngpBMK8pnVPSQACAZ+sxqwCwczp8f/+O+8fMkuqj96Po6K Sc+kWrVBB1fxNvRX3G4/cDgNTnGcJCC0Ng== -----END CERTIFICATE----- ` /* openssl genrsa -out ca.key 4096 openssl req -new -x509 -days 36500 \ -sha256 -key ca.key -extensions v3_ca \ -out ca.crt \ -subj "/C=US/ST=My State/L=My City/O=My Org/O=My Org 1/O=My Org 2/CN=ROOT CA WITH GROUPS" openssl x509 -in ca.crt -text */ // A certificate with multiple organizations. caWithGroups = `Certificate: Data: Version: 3 (0x2) Serial Number: bc:57:6d:0b:7c:ff:cb:52 Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=My State, L=My City, O=My Org, O=My Org 1, O=My Org 2, CN=ROOT CA WITH GROUPS Validity Not Before: Aug 10 19:22:03 2016 GMT Not After : Jul 17 19:22:03 2116 GMT Subject: C=US, ST=My State, L=My City, O=My Org, O=My Org 1, O=My Org 2, CN=ROOT CA WITH GROUPS Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: 00:ba:3a:40:34:1a:ba:13:87:0d:c9:c7:bf:e5:8e: 6a:c7:d5:0f:8f:e3:e1:ac:9e:a5:fd:35:e1:39:52: 1d:22:77:c1:d2:3f:74:02:2e:23:c6:c1:fc:cd:30: b4:33:e7:12:04:6f:90:27:e1:be:8e:ec:c8:dc:87: 91:da:7d:5b:8a:1f:41:fb:62:24:d0:26:98:c6:f7: f8:ca:8a:56:15:c4:b3:5f:43:86:28:f6:4d:fc:e4: 03:52:1d:2b:25:f7:19:5c:13:c3:0e:04:91:06:f3: 29:b6:3f:8b:86:6d:b5:8e:43:2d:69:4e:60:53:5b: 75:8f:e7:d2:57:8c:db:bb:a1:0b:d7:c7:62:41:bc: f2:87:be:66:bb:b9:bf:8b:85:97:19:98:18:50:7b: ee:31:88:47:99:c1:04:e4:12:d2:a6:e2:bf:61:33: 82:11:79:c3:d5:39:7c:1c:15:9e:d2:61:f7:16:9f: 97:f1:39:05:8f:b9:f8:e0:5b:16:ca:da:bf:10:45: 10:0f:14:f9:67:10:66:77:05:f3:fe:21:d6:69:fb: 1e:dc:fd:f7:97:40:db:0d:59:99:8a:9d:e4:31:a3: b9:c2:4d:ff:85:ae:ea:da:18:d8:c7:a5:b7:ea:f3: a8:38:a5:44:1f:3b:23:71:fc:4c:5b:bd:36:6f:e0: 28:6d:f3:be:e8:c9:74:64:af:89:54:b3:12:c8:2d: 27:2d:1c:22:23:81:bd:69:b7:8b:76:63:e1:bf:80: a1:ba:d6:c6:fc:aa:37:2e:44:94:4b:4c:3f:c4:f2: c3:f8:25:54:ab:1f:0f:4c:19:2f:9c:b6:46:09:db: 26:52:b4:03:0a:35:75:53:94:33:5d:22:29:48:4a: 61:9c:d0:5a:6d:91:f5:18:bb:93:99:30:02:5c:6d: 7c:3f:4d:5a:ea:6f:ee:f7:7a:f9:07:9d:fe:e0:6f: 75:02:4a:ef:1e:25:c2:d5:8d:2c:57:a2:95:a7:df: 37:4f:32:60:94:09:85:4d:a7:67:05:e9:29:db:45: a8:89:ec:1e:e9:3a:49:92:23:17:5b:4a:9c:b8:0d: 6f:2a:54:ba:47:45:f8:d3:34:30:e8:db:48:6d:c7: 82:08:01:d5:93:6a:08:7c:4b:43:78:04:df:57:b7: fe:e3:d7:4c:ec:9c:dc:2d:0b:8c:e4:6f:aa:e2:30: 66:74:16:10:b9:44:c9:1e:73:53:86:25:25:cc:60: 3a:94:79:18:f1:c9:31:b0:e1:ca:b9:21:44:75:0a: 6c:e4:58:c1:37:ee:69:28:d1:d4:b8:78:21:64:ea: 27:d3:67:25:cf:3a:82:8d:de:27:51:b4:33:a2:85: db:07:89 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4 X509v3 Authority Key Identifier: keyid:AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha256WithRSAEncryption 1c:af:04:c9:10:f2:43:03:b6:24:2e:20:2e:47:46:4d:7f:b9: fa:1c:ea:8d:f0:30:a5:42:93:fe:e0:55:4a:b5:8b:4d:30:f4: e1:04:1f:20:ec:a1:27:ab:1f:b2:9d:da:58:2e:04:5c:b6:7c: 69:8c:00:59:42:4f:cc:c7:3c:d4:f7:30:84:2a:14:8e:5d:3a: 20:91:63:5c:ac:5c:e7:0c:78:fc:28:f3:f9:24:de:3d:30:e3: 64:ca:5d:a6:86:30:76:5e:53:a4:99:77:a4:7a:c5:52:62:cd: f9:79:42:69:57:1b:79:25:c5:51:45:42:ed:ae:9c:bc:f2:4c: 4d:9d:3a:17:73:b1:d2:94:ab:61:4a:90:fa:59:f1:96:c7:7c: 26:5b:0c:75:4b:94:6f:76:ac:6c:70:8f:68:5c:e3:e7:7b:b9: 38:c2:0f:f2:e3:2d:96:ec:79:fa:bf:df:33:02:f2:67:a1:19: d1:7d:ed:c4:3b:14:b8:1f:53:c5:6a:52:ad:19:2d:4c:43:19: c7:d3:14:75:7f:e7:18:40:38:79:b7:2c:ce:91:6f:cd:16:e3: d9:8f:87:be:bc:c0:c0:53:1a:93:d6:ff:a9:17:c0:d9:6f:6a: cc:0b:57:37:b8:da:30:98:4a:fc:e5:e9:dc:49:1a:33:35:f0: e9:9a:a7:a2:fd:6a:13:9e:85:df:66:a8:15:3f:94:30:4b:ca: 61:72:7e:1a:b1:83:88:65:21:e8:f6:58:4a:22:48:b5:29:3d: 00:6c:3e:a2:e5:bd:a5:a3:d9:5a:4d:a9:cb:2a:f8:47:ca:72: ea:9d:e1:87:e1:d1:75:5d:07:36:ba:ab:fd:7f:5f:d3:66:d0: 41:86:7c:6b:1e:a7:7c:9f:dc:26:7a:37:70:54:1e:7c:b3:66: 7f:f1:99:93:f4:8a:aa:81:02:e9:bf:5d:a5:90:94:82:6e:2a: a6:c8:e1:77:df:66:59:d8:6c:b1:55:a0:77:d6:53:6b:78:aa: 4b:0d:fc:34:06:5c:52:4e:e6:5e:c7:94:13:19:70:e8:2b:00: 6d:ea:90:b9:f4:6f:74:3f:cc:e7:1d:3e:22:ec:66:cb:84:19: 7a:40:3c:7e:38:77:b4:4e:da:8c:4b:af:dc:c2:23:28:9d:60: a5:4f:5a:c8:9e:17:df:b9:9d:92:bc:d3:c0:20:12:ec:22:d4: e8:d4:97:9f:da:3c:35:a0:e9:a3:8c:d1:42:7c:c1:27:1f:8a: 9b:5b:03:3d:2b:9b:df:25:b6:a8:a7:5a:48:0f:e8:1f:26:4b: 0e:3c:a2:50:0a:cd:02:33:4c:e4:7a:c9:2d:b8:b8:bf:80:5a: 6e:07:49:c4:c3:23:a0:2e -----BEGIN CERTIFICATE----- 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 PKJQCs0CM0zkesktuLi/gFpuB0nEwyOgLg== -----END CERTIFICATE-----` ) func TestX509(t *testing.T) { multilevelOpts := DefaultVerifyOptions() multilevelOpts.Roots = x509.NewCertPool() multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0]) testCases := map[string]struct { Insecure bool Certs []*x509.Certificate Opts x509.VerifyOptions User UserConversion ExpectUserName string ExpectGroups []string ExpectOK bool ExpectErr bool }{ "non-tls": { Insecure: true, ExpectOK: false, ExpectErr: false, }, "tls, no certs": { ExpectOK: false, ExpectErr: false, }, "self signed": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, selfSignedCert), User: CommonNameUserConversion, ExpectErr: true, }, "server cert": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, serverCert), User: CommonNameUserConversion, ExpectErr: true, }, "server cert allowing non-client cert usages": { Opts: x509.VerifyOptions{Roots: getRootCertPool(t)}, Certs: getCerts(t, serverCert), User: CommonNameUserConversion, ExpectUserName: "127.0.0.1", ExpectGroups: []string{"My Org"}, ExpectOK: true, ExpectErr: false, }, "common name": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, clientCNCert), User: CommonNameUserConversion, ExpectUserName: "client_cn", ExpectGroups: []string{"My Org"}, ExpectOK: true, ExpectErr: false, }, "ca with multiple organizations": { Opts: x509.VerifyOptions{ Roots: getRootCertPoolFor(t, caWithGroups), }, Certs: getCerts(t, caWithGroups), User: CommonNameUserConversion, ExpectUserName: "ROOT CA WITH GROUPS", ExpectGroups: []string{"My Org", "My Org 1", "My Org 2"}, ExpectOK: true, ExpectErr: false, }, "custom conversion error": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, clientCNCert), User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) { return nil, false, errors.New("custom error") }), ExpectOK: false, ExpectErr: true, }, "custom conversion success": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, clientCNCert), User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) { return &authenticator.Response{User: &user.DefaultInfo{Name: "custom"}}, true, nil }), ExpectUserName: "custom", ExpectOK: true, ExpectErr: false, }, "future cert": { Opts: x509.VerifyOptions{ CurrentTime: time.Now().Add(time.Duration(-100 * time.Hour * 24 * 365)), Roots: getRootCertPool(t), }, Certs: getCerts(t, clientCNCert), User: CommonNameUserConversion, ExpectOK: false, ExpectErr: true, }, "expired cert": { Opts: x509.VerifyOptions{ CurrentTime: time.Now().Add(time.Duration(100 * time.Hour * 24 * 365)), Roots: getRootCertPool(t), }, Certs: getCerts(t, clientCNCert), User: CommonNameUserConversion, ExpectOK: false, ExpectErr: true, }, "multi-level, valid": { Opts: multilevelOpts, Certs: getCertsFromFile(t, "client-valid", "intermediate"), User: CommonNameUserConversion, ExpectUserName: "My Client", ExpectOK: true, ExpectErr: false, }, "multi-level, expired": { Opts: multilevelOpts, Certs: getCertsFromFile(t, "client-expired", "intermediate"), User: CommonNameUserConversion, ExpectOK: false, ExpectErr: true, }, } for k, testCase := range testCases { req, _ := http.NewRequest("GET", "/", nil) if !testCase.Insecure { req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs} } // this effectively tests the simple dynamic verify function. a := New(testCase.Opts, testCase.User) resp, ok, err := a.AuthenticateRequest(req) if testCase.ExpectErr && err == nil { t.Errorf("%s: Expected error, got none", k) continue } if !testCase.ExpectErr && err != nil { t.Errorf("%s: Got unexpected error: %v", k, err) continue } if testCase.ExpectOK != ok { t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok) continue } if testCase.ExpectOK { if testCase.ExpectUserName != resp.User.GetName() { t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, resp.User.GetName()) } groups := resp.User.GetGroups() sort.Strings(testCase.ExpectGroups) sort.Strings(groups) if !reflect.DeepEqual(testCase.ExpectGroups, groups) { t.Errorf("%s: Expected user.groups=%v, got %v", k, testCase.ExpectGroups, groups) } } } } func TestX509Verifier(t *testing.T) { multilevelOpts := DefaultVerifyOptions() multilevelOpts.Roots = x509.NewCertPool() multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0]) testCases := map[string]struct { Insecure bool Certs []*x509.Certificate Opts x509.VerifyOptions AllowedCNs sets.String ExpectOK bool ExpectErr bool }{ "non-tls": { Insecure: true, ExpectOK: false, ExpectErr: false, }, "tls, no certs": { ExpectOK: false, ExpectErr: false, }, "self signed": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, selfSignedCert), ExpectErr: true, }, "server cert disallowed": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, serverCert), ExpectErr: true, }, "server cert allowing non-client cert usages": { Opts: x509.VerifyOptions{Roots: getRootCertPool(t)}, Certs: getCerts(t, serverCert), ExpectOK: true, ExpectErr: false, }, "valid client cert": { Opts: getDefaultVerifyOptions(t), Certs: getCerts(t, clientCNCert), ExpectOK: true, ExpectErr: false, }, "valid client cert with wrong CN": { Opts: getDefaultVerifyOptions(t), AllowedCNs: sets.NewString("foo", "bar"), Certs: getCerts(t, clientCNCert), ExpectOK: false, ExpectErr: true, }, "valid client cert with right CN": { Opts: getDefaultVerifyOptions(t), AllowedCNs: sets.NewString("client_cn"), Certs: getCerts(t, clientCNCert), ExpectOK: true, ExpectErr: false, }, "future cert": { Opts: x509.VerifyOptions{ CurrentTime: time.Now().Add(-100 * time.Hour * 24 * 365), Roots: getRootCertPool(t), }, Certs: getCerts(t, clientCNCert), ExpectOK: false, ExpectErr: true, }, "expired cert": { Opts: x509.VerifyOptions{ CurrentTime: time.Now().Add(100 * time.Hour * 24 * 365), Roots: getRootCertPool(t), }, Certs: getCerts(t, clientCNCert), ExpectOK: false, ExpectErr: true, }, "multi-level, valid": { Opts: multilevelOpts, Certs: getCertsFromFile(t, "client-valid", "intermediate"), ExpectOK: true, ExpectErr: false, }, "multi-level, expired": { Opts: multilevelOpts, Certs: getCertsFromFile(t, "client-expired", "intermediate"), ExpectOK: false, ExpectErr: true, }, } for k, testCase := range testCases { req, _ := http.NewRequest("GET", "/", nil) if !testCase.Insecure { req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs} } authCall := false auth := authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { authCall = true return &authenticator.Response{User: &user.DefaultInfo{Name: "innerauth"}}, true, nil }) a := NewVerifier(testCase.Opts, auth, testCase.AllowedCNs) resp, ok, err := a.AuthenticateRequest(req) if testCase.ExpectErr && err == nil { t.Errorf("%s: Expected error, got none", k) continue } if !testCase.ExpectErr && err != nil { t.Errorf("%s: Got unexpected error: %v", k, err) continue } if testCase.ExpectOK != ok { t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok) continue } if testCase.ExpectOK { if !authCall { t.Errorf("%s: Expected inner auth called, wasn't", k) continue } if "innerauth" != resp.User.GetName() { t.Errorf("%s: Expected user.name=%v, got %v", k, "innerauth", resp.User.GetName()) continue } } else { if authCall { t.Errorf("%s: Expected inner auth not to be called, was", k) continue } } } } func getDefaultVerifyOptions(t *testing.T) x509.VerifyOptions { options := DefaultVerifyOptions() options.Roots = getRootCertPool(t) return options } func getRootCertPool(t *testing.T) *x509.CertPool { return getRootCertPoolFor(t, rootCACert) } func getRootCertPoolFor(t *testing.T, certs ...string) *x509.CertPool { pool := x509.NewCertPool() for _, cert := range certs { pool.AddCert(getCert(t, cert)) } return pool } func getCertsFromFile(t *testing.T, names ...string) []*x509.Certificate { certs := []*x509.Certificate{} for _, name := range names { filename := "testdata/" + name + ".pem" data, err := ioutil.ReadFile(filename) if err != nil { t.Fatalf("error reading %s: %v", filename, err) } certs = append(certs, getCert(t, string(data))) } return certs } func getCert(t *testing.T, pemData string) *x509.Certificate { t.Helper() pemBlock, _ := pem.Decode([]byte(pemData)) cert, err := x509.ParseCertificate(pemBlock.Bytes) if err != nil { t.Fatalf("Error parsing cert: %v", err) return nil } return cert } func getCerts(t *testing.T, pemData ...string) []*x509.Certificate { certs := []*x509.Certificate{} for _, pemData := range pemData { certs = append(certs, getCert(t, pemData)) } return certs } func TestCertificateIdentifier(t *testing.T) { tt := []struct { name string cert *x509.Certificate expectedIdentifier string }{ { name: "client cert", cert: getCert(t, clientCNCert), expectedIdentifier: "SN=1, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B", }, { name: "nil serial", cert: func() *x509.Certificate { c := getCert(t, clientCNCert) c.SerialNumber = nil return c }(), expectedIdentifier: "SN=, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B", }, { name: "empty SKID", cert: func() *x509.Certificate { c := getCert(t, clientCNCert) c.SubjectKeyId = nil return c }(), expectedIdentifier: "SN=1, SKID=, AKID=D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B", }, { name: "empty AKID", cert: func() *x509.Certificate { c := getCert(t, clientCNCert) c.AuthorityKeyId = nil return c }(), expectedIdentifier: "SN=1, SKID=FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F, AKID=", }, { name: "self-signed", cert: getCert(t, selfSignedCert), expectedIdentifier: "SN=654708847004117259890317394342561449606220871090, SKID=56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16, AKID=56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16", }, } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { got := certificateIdentifier(tc.cert) if got != tc.expectedIdentifier { t.Errorf("expected %q, got %q", tc.expectedIdentifier, got) } }) } }