k8s.io/apiserver@v0.31.1/pkg/authentication/request/x509/x509_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package x509 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "encoding/pem" 23 "errors" 24 "io/ioutil" 25 "net/http" 26 "reflect" 27 "sort" 28 "testing" 29 "time" 30 31 "k8s.io/apimachinery/pkg/util/sets" 32 "k8s.io/apiserver/pkg/authentication/authenticator" 33 "k8s.io/apiserver/pkg/authentication/user" 34 ) 35 36 const ( 37 38 /* 39 40 > rootCACert 41 42 openssl genrsa -out root.key 1024 && \ 43 openssl rsa -in ./root.key -outform PEM -pubout -out ./root.pub && \ 44 CONFIG="[ v3_req ]\n" && \ 45 CONFIG="${CONFIG}subjectKeyIdentifier=hash\n" && \ 46 CONFIG="${CONFIG}authorityKeyIdentifier=keyid:always,issuer\n" && \ 47 CONFIG="${CONFIG}basicConstraints=CA:TRUE\n" && \ 48 CONFIG="${CONFIG}keyUsage=keyCertSign,cRLSign\n" && \ 49 openssl req -new -x509 -days 36500 \ 50 -sha1 -key root.key \ 51 -out root.crt \ 52 -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=ROOT CA" \ 53 -config <(printf "${CONFIG}") \ 54 -extensions v3_req \ 55 && \ 56 openssl x509 -in root.crt -text 57 58 59 > output 60 61 Certificate: 62 Data: 63 Version: 3 (0x2) 64 Serial Number: 65 2d:73:1a:2e:d7:8b:89:20:83:9c:42:9a:6e:f7:f5:f6:a1:ec:af:8c 66 Signature Algorithm: sha1WithRSAEncryption 67 Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA 68 Validity 69 Not Before: May 2 05:43:51 2024 GMT 70 Not After : Apr 8 05:43:51 2124 GMT 71 Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA 72 Subject Public Key Info: 73 Public Key Algorithm: rsaEncryption 74 Public-Key: (1024 bit) 75 Modulus: 76 00:a8:c3:dc:de:1a:f6:3e:95:97:2a:d5:bf:8b:72: 77 93:06:85:72:4b:36:2a:d9:63:a8:9c:fb:80:3e:9b: 78 2f:84:c6:57:d2:ff:33:13:bf:32:e9:90:66:db:0a: 79 9a:05:c1:e3:c1:09:bb:25:75:b2:d7:fc:9c:09:86: 80 80:15:b0:6c:67:c5:1a:e9:76:01:32:40:22:58:ec: 81 4e:a1:b7:c5:05:01:49:55:d8:4f:4b:88:1d:bf:66: 82 d3:de:58:4a:e7:26:b6:bf:af:33:d8:57:42:f1:bc: 83 34:67:44:88:b4:31:f6:4a:4a:b3:1e:c2:ca:6b:4b: 84 2e:5a:32:23:9b:1b:3f:97:35 85 Exponent: 65537 (0x10001) 86 X509v3 extensions: 87 X509v3 Subject Key Identifier: 88 D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B 89 X509v3 Authority Key Identifier: 90 D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B 91 X509v3 Basic Constraints: 92 CA:TRUE 93 X509v3 Key Usage: 94 Certificate Sign, CRL Sign 95 Signature Algorithm: sha1WithRSAEncryption 96 Signature Value: 97 4a:54:07:46:71:c1:b2:a2:d3:32:e7:df:49:8c:af:87:46:ab: 98 81:11:c6:c5:4b:be:0b:0c:ea:7e:5f:38:14:79:43:92:f9:bb: 99 82:6f:f6:06:a6:43:19:e2:7c:52:66:36:13:6f:0f:73:16:3d: 100 79:5f:f9:a6:c8:4c:18:f9:ff:20:2b:de:7f:15:e0:ab:ae:44: 101 fa:65:7a:86:8a:df:d0:63:82:b1:5c:f3:f8:5c:05:97:4e:1f: 102 09:d6:d9:55:e7:36:fc:08:3e:3f:66:99:68:b6:31:44:0f:63: 103 20:6a:b2:81:50:39:19:d0:47:de:20:94:f0:a2:2c:eb:69:93: 104 93:a3 105 -----BEGIN CERTIFICATE----- 106 MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF 107 BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN 108 eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV 109 BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx 110 CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0 111 eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS 112 T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L 113 cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV 114 sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0 115 MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY 116 6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD 117 VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB 118 sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9 119 eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ 120 aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M= 121 -----END CERTIFICATE----- 122 123 124 */ 125 126 rootCACert = `-----BEGIN CERTIFICATE----- 127 MIICtjCCAh+gAwIBAgIULXMaLteLiSCDnEKabvf19qHsr4wwDQYJKoZIhvcNAQEF 128 BQAwZzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN 129 eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAsMB015IFVuaXQxEDAOBgNV 130 BAMMB1JPT1QgQ0EwIBcNMjQwNTAyMDU0MzUxWhgPMjEyNDA0MDgwNTQzNTFaMGcx 131 CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHTXkgQ2l0 132 eTEPMA0GA1UECgwGTXkgT3JnMRAwDgYDVQQLDAdNeSBVbml0MRAwDgYDVQQDDAdS 133 T09UIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCow9zeGvY+lZcq1b+L 134 cpMGhXJLNirZY6ic+4A+my+ExlfS/zMTvzLpkGbbCpoFwePBCbsldbLX/JwJhoAV 135 sGxnxRrpdgEyQCJY7E6ht8UFAUlV2E9LiB2/ZtPeWErnJra/rzPYV0LxvDRnRIi0 136 MfZKSrMewsprSy5aMiObGz+XNQIDAQABo10wWzAdBgNVHQ4EFgQU0wfNcua+ClrY 137 6WAgr8LyNn4zYgswHwYDVR0jBBgwFoAU0wfNcua+ClrY6WAgr8LyNn4zYgswDAYD 138 VR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEFBQADgYEASlQHRnHB 139 sqLTMuffSYyvh0argRHGxUu+Cwzqfl84FHlDkvm7gm/2BqZDGeJ8UmY2E28PcxY9 140 eV/5pshMGPn/ICvefxXgq65E+mV6horf0GOCsVzz+FwFl04fCdbZVec2/Ag+P2aZ 141 aLYxRA9jIGqygVA5GdBH3iCU8KIs62mTk6M= 142 -----END CERTIFICATE----- 143 ` 144 145 /* 146 147 > selfSignedCert 148 149 openssl genrsa -out selfsign.key 1024 && \ 150 openssl req -new -x509 -days 36500 \ 151 -sha1 -key selfsign.key \ 152 -out selfsign.crt \ 153 -subj "/C=US/ST=My State/L=My City/O=My Org/O=My Unit/CN=self1" \ 154 && \ 155 openssl x509 -in selfsign.crt -text 156 157 158 > output 159 160 Certificate: 161 Data: 162 Version: 3 (0x2) 163 Serial Number: 164 72:ae:28:f9:b7:7f:16:0a:89:a7:9c:a1:a3:88:15:4b:20:eb:f5:b2 165 Signature Algorithm: sha1WithRSAEncryption 166 Issuer: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1 167 Validity 168 Not Before: May 2 00:25:12 2024 GMT 169 Not After : Apr 8 00:25:12 2124 GMT 170 Subject: C = US, ST = My State, L = My City, O = My Org, O = My Unit, CN = self1 171 Subject Public Key Info: 172 Public Key Algorithm: rsaEncryption 173 Public-Key: (1024 bit) 174 Modulus: 175 00:94:91:e3:8a:4d:dd:f6:27:e9:71:9c:d2:f2:64: 176 b9:af:ce:05:9d:82:a2:98:a9:15:40:8b:ff:a2:5c: 177 72:53:e8:d0:af:73:c6:76:4d:c7:6a:6e:9f:5d:a7: 178 e2:f6:aa:6a:18:2b:c3:ee:3b:64:19:16:5d:94:0b: 179 f2:f7:90:43:9a:5d:ce:7e:07:4d:b9:df:be:f0:39: 180 98:a4:41:eb:d3:17:90:12:d9:bc:d7:7f:a4:66:98: 181 c3:91:17:30:5d:7b:c4:12:2b:a9:a9:48:ca:a3:14: 182 3a:36:ad:23:58:cf:88:b9:30:9a:b4:e6:8a:35:a1: 183 ce:80:02:4a:aa:24:2b:7b:79 184 Exponent: 65537 (0x10001) 185 X509v3 extensions: 186 X509v3 Subject Key Identifier: 187 56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16 188 X509v3 Authority Key Identifier: 189 56:A5:55:02:8C:97:FD:1E:A0:B8:DE:EF:5E:95:F0:AC:A6:23:6F:16 190 X509v3 Basic Constraints: critical 191 CA:TRUE 192 Signature Algorithm: sha1WithRSAEncryption 193 Signature Value: 194 5e:84:19:68:a2:f3:41:c5:f5:57:2f:1b:e5:14:4d:8c:50:ee: 195 5f:f4:aa:ec:4f:6a:06:4b:af:f3:2a:14:cc:0f:7b:a1:17:de: 196 cc:da:f8:fb:c3:04:c7:a7:60:98:76:5c:32:82:5c:ec:95:a0: 197 51:74:12:12:c0:7a:8b:68:bc:8b:47:47:db:95:20:34:be:69: 198 d2:fc:d5:d7:e7:4b:7c:e1:f3:bc:72:3c:b1:f5:d4:db:71:ad: 199 d8:a7:ad:ab:91:68:c9:16:0a:e9:76:ed:87:0f:83:24:cd:ab: 200 c7:a4:16:3f:c6:7c:99:18:bb:b1:12:11:a4:a5:99:af:17:11: 201 e7:b1 202 -----BEGIN CERTIFICATE----- 203 MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF 204 BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN 205 eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV 206 BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw 207 CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx 208 DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs 209 ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O 210 BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd 211 zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw 212 mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e 213 lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB 214 Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0 215 quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV 216 IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY 217 u7ESEaSlma8XEeex 218 -----END CERTIFICATE----- 219 220 221 */ 222 223 selfSignedCert = `-----BEGIN CERTIFICATE----- 224 MIICqDCCAhGgAwIBAgIUcq4o+bd/FgqJp5yho4gVSyDr9bIwDQYJKoZIhvcNAQEF 225 BQAwZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE15IFN0YXRlMRAwDgYDVQQHDAdN 226 eSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcxEDAOBgNVBAoMB015IFVuaXQxDjAMBgNV 227 BAMMBXNlbGYxMCAXDTI0MDUwMjAwMjUxMloYDzIxMjQwNDA4MDAyNTEyWjBlMQsw 228 CQYDVQQGEwJVUzERMA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkx 229 DzANBgNVBAoMBk15IE9yZzEQMA4GA1UECgwHTXkgVW5pdDEOMAwGA1UEAwwFc2Vs 230 ZjEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJSR44pN3fYn6XGc0vJkua/O 231 BZ2CopipFUCL/6JcclPo0K9zxnZNx2pun12n4vaqahgrw+47ZBkWXZQL8veQQ5pd 232 zn4HTbnfvvA5mKRB69MXkBLZvNd/pGaYw5EXMF17xBIrqalIyqMUOjatI1jPiLkw 233 mrTmijWhzoACSqokK3t5AgMBAAGjUzBRMB0GA1UdDgQWBBRWpVUCjJf9HqC43u9e 234 lfCspiNvFjAfBgNVHSMEGDAWgBRWpVUCjJf9HqC43u9elfCspiNvFjAPBgNVHRMB 235 Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAF6EGWii80HF9VcvG+UUTYxQ7l/0 236 quxPagZLr/MqFMwPe6EX3sza+PvDBMenYJh2XDKCXOyVoFF0EhLAeotovItHR9uV 237 IDS+adL81dfnS3zh87xyPLH11NtxrdinrauRaMkWCul27YcPgyTNq8ekFj/GfJkY 238 u7ESEaSlma8XEeex 239 -----END CERTIFICATE----- 240 ` 241 242 /* 243 244 > clientCNCert 245 246 openssl genrsa -out client.key 1024 && \ 247 openssl rsa -in ./client.key -outform PEM \ 248 -pubout -out ./client.pub && \ 249 openssl req -key ./client.key -new\ 250 -sha1 -out ./client.csr \ 251 -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=client_cn" \ 252 && \ 253 EXTFILE="subjectKeyIdentifier=hash\n" && \ 254 EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \ 255 EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \ 256 EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \ 257 EXTFILE="${EXTFILE}extendedKeyUsage=clientAuth\n" && \ 258 openssl x509 -req -days 36500 \ 259 -in ./client.csr \ 260 -extfile <(printf "${EXTFILE}") \ 261 -CA ./root.crt \ 262 -CAkey ./root.key \ 263 -set_serial 1 \ 264 -sha256 \ 265 -out ./client.crt \ 266 && \ 267 openssl x509 -in client.crt -text 268 269 > output 270 271 is below 272 273 */ 274 275 clientCNCert = `Certificate: 276 Data: 277 Version: 3 (0x2) 278 Serial Number: 1 (0x1) 279 Signature Algorithm: sha256WithRSAEncryption 280 Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA 281 Validity 282 Not Before: May 2 05:46:24 2024 GMT 283 Not After : Apr 8 05:46:24 2124 GMT 284 Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = client_cn 285 Subject Public Key Info: 286 Public Key Algorithm: rsaEncryption 287 Public-Key: (1024 bit) 288 Modulus: 289 00:bd:3f:2d:d1:86:73:6d:b5:09:9c:ff:42:fb:27: 290 8e:07:69:a3:b6:d1:c7:72:d1:de:98:14:a5:61:9b: 291 83:03:1d:da:54:d1:d4:0d:7f:de:98:2e:cc:db:6f: 292 e4:19:c7:41:43:59:ff:34:7b:82:06:80:01:ab:79: 293 b3:40:d3:45:1f:52:2d:10:f9:55:40:a7:7a:61:f7: 294 fd:9c:41:eb:d1:ec:7e:30:ca:1a:fa:0e:9e:0f:1e: 295 50:93:9a:ca:55:ea:64:80:6e:bb:49:7d:12:15:d8: 296 6f:a8:aa:3f:b9:10:24:6f:72:22:e9:4f:f3:a4:29: 297 1e:4e:71:a6:82:af:39:78:a9 298 Exponent: 65537 (0x10001) 299 X509v3 extensions: 300 X509v3 Subject Key Identifier: 301 FB:77:D6:D0:84:A8:10:DF:FA:4E:A4:E0:F1:2A:BB:B4:80:FD:4F:3F 302 X509v3 Authority Key Identifier: 303 D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B 304 X509v3 Basic Constraints: 305 CA:FALSE 306 X509v3 Subject Alternative Name: 307 <EMPTY> 308 309 X509v3 Extended Key Usage: 310 TLS Web Client Authentication 311 Signature Algorithm: sha256WithRSAEncryption 312 Signature Value: 313 6b:24:0f:2f:81:46:32:c4:c1:57:09:cd:64:6d:9f:50:ee:29: 314 4d:a7:14:d0:a0:0c:ea:a6:dc:e5:15:52:9a:42:08:eb:a2:91: 315 3c:ce:94:0e:f0:82:bc:fd:d7:23:d1:ad:d1:98:07:94:05:fa: 316 ca:37:45:d7:f0:7d:aa:d2:ec:94:2b:8b:03:85:00:fb:af:1d: 317 35:28:53:a8:1d:f8:44:e1:ea:48:3f:a4:2a:46:3b:f6:19:bf: 318 30:df:b2:0e:8d:79:b0:0a:f5:34:c7:8a:6d:bf:58:39:9d:5d: 319 a1:f5:35:a0:54:87:98:c6:5d:bf:ea:4e:46:f9:47:6d:d7:e6: 320 5a:f3 321 -----BEGIN CERTIFICATE----- 322 MIICtTCCAh6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER 323 MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15 324 IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1 325 MDIwNTQ2MjRaGA8yMTI0MDQwODA1NDYyNFowaTELMAkGA1UEBhMCVVMxETAPBgNV 326 BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx 327 EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCWNsaWVudF9jbjCBnzANBgkqhkiG 328 9w0BAQEFAAOBjQAwgYkCgYEAvT8t0YZzbbUJnP9C+yeOB2mjttHHctHemBSlYZuD 329 Ax3aVNHUDX/emC7M22/kGcdBQ1n/NHuCBoABq3mzQNNFH1ItEPlVQKd6Yff9nEHr 330 0ex+MMoa+g6eDx5Qk5rKVepkgG67SX0SFdhvqKo/uRAkb3Ii6U/zpCkeTnGmgq85 331 eKkCAwEAAaNtMGswHQYDVR0OBBYEFPt31tCEqBDf+k6k4PEqu7SA/U8/MB8GA1Ud 332 IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw 333 ADATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQBrJA8vgUYy 334 xMFXCc1kbZ9Q7ilNpxTQoAzqptzlFVKaQgjropE8zpQO8IK8/dcj0a3RmAeUBfrK 335 N0XX8H2q0uyUK4sDhQD7rx01KFOoHfhE4epIP6QqRjv2Gb8w37IOjXmwCvU0x4pt 336 v1g5nV2h9TWgVIeYxl2/6k5G+Udt1+Za8w== 337 -----END CERTIFICATE-----` 338 339 /* 340 341 > serverCert 342 343 openssl genrsa -out server.key 1024 && \ 344 openssl rsa -in ./server.key -outform PEM \ 345 -pubout -out ./server.pub && \ 346 openssl req -key ./server.key -new\ 347 -sha1 -out ./server.csr \ 348 -subj "/C=US/ST=My State/L=My City/O=My Org/OU=My Unit/CN=127.0.0.1" \ 349 && \ 350 EXTFILE="subjectKeyIdentifier=hash\n" && \ 351 EXTFILE="${EXTFILE}authorityKeyIdentifier=keyid,issuer\n" && \ 352 EXTFILE="${EXTFILE}basicConstraints=CA:FALSE\n" && \ 353 EXTFILE="${EXTFILE}subjectAltName=email:copy\n" && \ 354 EXTFILE="${EXTFILE}extendedKeyUsage=serverAuth\n" && \ 355 openssl x509 -req -days 36500 \ 356 -in ./server.csr \ 357 -extfile <(printf "${EXTFILE}") \ 358 -CA ./root.crt \ 359 -CAkey ./root.key \ 360 -set_serial 7 \ 361 -sha256 \ 362 -out ./server.crt \ 363 && \ 364 openssl x509 -in server.crt -text 365 366 > output 367 368 is below 369 370 */ 371 372 serverCert = `Certificate: 373 Data: 374 Version: 3 (0x2) 375 Serial Number: 7 (0x7) 376 Signature Algorithm: sha256WithRSAEncryption 377 Issuer: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = ROOT CA 378 Validity 379 Not Before: May 2 05:47:31 2024 GMT 380 Not After : Apr 8 05:47:31 2124 GMT 381 Subject: C = US, ST = My State, L = My City, O = My Org, OU = My Unit, CN = 127.0.0.1 382 Subject Public Key Info: 383 Public Key Algorithm: rsaEncryption 384 Public-Key: (1024 bit) 385 Modulus: 386 00:9d:1f:c3:9e:ac:51:92:27:df:2a:3a:48:b7:59: 387 40:23:a5:c3:a1:61:71:7a:00:df:d5:8b:a2:8a:7c: 388 54:f0:19:69:fe:ae:19:a3:e1:eb:1e:1b:39:2c:61: 389 fb:7b:21:10:81:b2:ef:29:94:b6:14:6f:ca:eb:4d: 390 f3:f6:84:93:5f:51:2c:7a:ab:9f:34:05:15:62:c4: 391 55:54:2e:75:b9:26:d1:0e:c5:63:41:e5:36:02:3f: 392 1c:5f:fc:1b:07:20:d2:1c:70:a5:a1:e8:08:1d:8f: 393 4c:c3:57:e0:54:72:a6:c9:24:1b:b0:fa:0d:86:f5: 394 26:1f:20:e5:1c:1c:c3:8f:d3 395 Exponent: 65537 (0x10001) 396 X509v3 extensions: 397 X509v3 Subject Key Identifier: 398 F2:AE:B7:50:D5:02:C1:E9:8D:38:0E:76:A5:D8:24:0B:1C:DB:08:0E 399 X509v3 Authority Key Identifier: 400 D3:07:CD:72:E6:BE:0A:5A:D8:E9:60:20:AF:C2:F2:36:7E:33:62:0B 401 X509v3 Basic Constraints: 402 CA:FALSE 403 X509v3 Subject Alternative Name: 404 <EMPTY> 405 406 X509v3 Extended Key Usage: 407 TLS Web Server Authentication 408 Signature Algorithm: sha256WithRSAEncryption 409 Signature Value: 410 3f:3d:d1:5d:d5:9f:c1:ab:6e:ba:c1:c2:1b:63:1a:a8:4f:d9: 411 df:03:13:ff:6d:a8:ed:c9:8d:19:a6:8f:a6:e2:a8:23:a0:f7: 412 5d:5e:22:01:d1:29:9b:d0:95:75:66:46:f2:51:a7:08:1c:8c: 413 aa:ca:4a:57:d8:ab:ed:1b:b3:77:25:58:38:1f:89:e0:a4:13: 414 0a:f2:99:d5:3d:24:00:08:06:7e:b3:1a:b0:0b:07:33:a7:c7: 415 ff:f8:ef:bc:7c:c9:2e:aa:3f:7a:3e:8e:8a:49:cf:a4:5a:b5: 416 41:07:57:f1:36:f4:57:dc:6e:3f:70:38:0d:4e:71:9c:24:20: 417 b4:36 418 -----BEGIN CERTIFICATE----- 419 MIICtTCCAh6gAwIBAgIBBzANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJVUzER 420 MA8GA1UECAwITXkgU3RhdGUxEDAOBgNVBAcMB015IENpdHkxDzANBgNVBAoMBk15 421 IE9yZzEQMA4GA1UECwwHTXkgVW5pdDEQMA4GA1UEAwwHUk9PVCBDQTAgFw0yNDA1 422 MDIwNTQ3MzFaGA8yMTI0MDQwODA1NDczMVowaTELMAkGA1UEBhMCVVMxETAPBgNV 423 BAgMCE15IFN0YXRlMRAwDgYDVQQHDAdNeSBDaXR5MQ8wDQYDVQQKDAZNeSBPcmcx 424 EDAOBgNVBAsMB015IFVuaXQxEjAQBgNVBAMMCTEyNy4wLjAuMTCBnzANBgkqhkiG 425 9w0BAQEFAAOBjQAwgYkCgYEAnR/DnqxRkiffKjpIt1lAI6XDoWFxegDf1YuiinxU 426 8Blp/q4Zo+HrHhs5LGH7eyEQgbLvKZS2FG/K603z9oSTX1EsequfNAUVYsRVVC51 427 uSbRDsVjQeU2Aj8cX/wbByDSHHCloegIHY9Mw1fgVHKmySQbsPoNhvUmHyDlHBzD 428 j9MCAwEAAaNtMGswHQYDVR0OBBYEFPKut1DVAsHpjTgOdqXYJAsc2wgOMB8GA1Ud 429 IwQYMBaAFNMHzXLmvgpa2OlgIK/C8jZ+M2ILMAkGA1UdEwQCMAAwCQYDVR0RBAIw 430 ADATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOBgQA/PdFd1Z/B 431 q266wcIbYxqoT9nfAxP/bajtyY0Zpo+m4qgjoPddXiIB0Smb0JV1ZkbyUacIHIyq 432 ykpX2KvtG7N3JVg4H4ngpBMK8pnVPSQACAZ+sxqwCwczp8f/+O+8fMkuqj96Po6K 433 Sc+kWrVBB1fxNvRX3G4/cDgNTnGcJCC0Ng== 434 -----END CERTIFICATE----- 435 ` 436 437 /* 438 openssl genrsa -out ca.key 4096 439 openssl req -new -x509 -days 36500 \ 440 -sha256 -key ca.key -extensions v3_ca \ 441 -out ca.crt \ 442 -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" 443 openssl x509 -in ca.crt -text 444 */ 445 446 // A certificate with multiple organizations. 447 caWithGroups = `Certificate: 448 Data: 449 Version: 3 (0x2) 450 Serial Number: 451 bc:57:6d:0b:7c:ff:cb:52 452 Signature Algorithm: sha256WithRSAEncryption 453 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 454 Validity 455 Not Before: Aug 10 19:22:03 2016 GMT 456 Not After : Jul 17 19:22:03 2116 GMT 457 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 458 Subject Public Key Info: 459 Public Key Algorithm: rsaEncryption 460 Public-Key: (4096 bit) 461 Modulus: 462 00:ba:3a:40:34:1a:ba:13:87:0d:c9:c7:bf:e5:8e: 463 6a:c7:d5:0f:8f:e3:e1:ac:9e:a5:fd:35:e1:39:52: 464 1d:22:77:c1:d2:3f:74:02:2e:23:c6:c1:fc:cd:30: 465 b4:33:e7:12:04:6f:90:27:e1:be:8e:ec:c8:dc:87: 466 91:da:7d:5b:8a:1f:41:fb:62:24:d0:26:98:c6:f7: 467 f8:ca:8a:56:15:c4:b3:5f:43:86:28:f6:4d:fc:e4: 468 03:52:1d:2b:25:f7:19:5c:13:c3:0e:04:91:06:f3: 469 29:b6:3f:8b:86:6d:b5:8e:43:2d:69:4e:60:53:5b: 470 75:8f:e7:d2:57:8c:db:bb:a1:0b:d7:c7:62:41:bc: 471 f2:87:be:66:bb:b9:bf:8b:85:97:19:98:18:50:7b: 472 ee:31:88:47:99:c1:04:e4:12:d2:a6:e2:bf:61:33: 473 82:11:79:c3:d5:39:7c:1c:15:9e:d2:61:f7:16:9f: 474 97:f1:39:05:8f:b9:f8:e0:5b:16:ca:da:bf:10:45: 475 10:0f:14:f9:67:10:66:77:05:f3:fe:21:d6:69:fb: 476 1e:dc:fd:f7:97:40:db:0d:59:99:8a:9d:e4:31:a3: 477 b9:c2:4d:ff:85:ae:ea:da:18:d8:c7:a5:b7:ea:f3: 478 a8:38:a5:44:1f:3b:23:71:fc:4c:5b:bd:36:6f:e0: 479 28:6d:f3:be:e8:c9:74:64:af:89:54:b3:12:c8:2d: 480 27:2d:1c:22:23:81:bd:69:b7:8b:76:63:e1:bf:80: 481 a1:ba:d6:c6:fc:aa:37:2e:44:94:4b:4c:3f:c4:f2: 482 c3:f8:25:54:ab:1f:0f:4c:19:2f:9c:b6:46:09:db: 483 26:52:b4:03:0a:35:75:53:94:33:5d:22:29:48:4a: 484 61:9c:d0:5a:6d:91:f5:18:bb:93:99:30:02:5c:6d: 485 7c:3f:4d:5a:ea:6f:ee:f7:7a:f9:07:9d:fe:e0:6f: 486 75:02:4a:ef:1e:25:c2:d5:8d:2c:57:a2:95:a7:df: 487 37:4f:32:60:94:09:85:4d:a7:67:05:e9:29:db:45: 488 a8:89:ec:1e:e9:3a:49:92:23:17:5b:4a:9c:b8:0d: 489 6f:2a:54:ba:47:45:f8:d3:34:30:e8:db:48:6d:c7: 490 82:08:01:d5:93:6a:08:7c:4b:43:78:04:df:57:b7: 491 fe:e3:d7:4c:ec:9c:dc:2d:0b:8c:e4:6f:aa:e2:30: 492 66:74:16:10:b9:44:c9:1e:73:53:86:25:25:cc:60: 493 3a:94:79:18:f1:c9:31:b0:e1:ca:b9:21:44:75:0a: 494 6c:e4:58:c1:37:ee:69:28:d1:d4:b8:78:21:64:ea: 495 27:d3:67:25:cf:3a:82:8d:de:27:51:b4:33:a2:85: 496 db:07:89 497 Exponent: 65537 (0x10001) 498 X509v3 extensions: 499 X509v3 Subject Key Identifier: 500 AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4 501 X509v3 Authority Key Identifier: 502 keyid:AB:3A:46:07:46:0C:68:F0:64:C7:73:A8:7C:8A:20:66:A8:DA:1C:E4 503 504 X509v3 Basic Constraints: 505 CA:TRUE 506 Signature Algorithm: sha256WithRSAEncryption 507 1c:af:04:c9:10:f2:43:03:b6:24:2e:20:2e:47:46:4d:7f:b9: 508 fa:1c:ea:8d:f0:30:a5:42:93:fe:e0:55:4a:b5:8b:4d:30:f4: 509 e1:04:1f:20:ec:a1:27:ab:1f:b2:9d:da:58:2e:04:5c:b6:7c: 510 69:8c:00:59:42:4f:cc:c7:3c:d4:f7:30:84:2a:14:8e:5d:3a: 511 20:91:63:5c:ac:5c:e7:0c:78:fc:28:f3:f9:24:de:3d:30:e3: 512 64:ca:5d:a6:86:30:76:5e:53:a4:99:77:a4:7a:c5:52:62:cd: 513 f9:79:42:69:57:1b:79:25:c5:51:45:42:ed:ae:9c:bc:f2:4c: 514 4d:9d:3a:17:73:b1:d2:94:ab:61:4a:90:fa:59:f1:96:c7:7c: 515 26:5b:0c:75:4b:94:6f:76:ac:6c:70:8f:68:5c:e3:e7:7b:b9: 516 38:c2:0f:f2:e3:2d:96:ec:79:fa:bf:df:33:02:f2:67:a1:19: 517 d1:7d:ed:c4:3b:14:b8:1f:53:c5:6a:52:ad:19:2d:4c:43:19: 518 c7:d3:14:75:7f:e7:18:40:38:79:b7:2c:ce:91:6f:cd:16:e3: 519 d9:8f:87:be:bc:c0:c0:53:1a:93:d6:ff:a9:17:c0:d9:6f:6a: 520 cc:0b:57:37:b8:da:30:98:4a:fc:e5:e9:dc:49:1a:33:35:f0: 521 e9:9a:a7:a2:fd:6a:13:9e:85:df:66:a8:15:3f:94:30:4b:ca: 522 61:72:7e:1a:b1:83:88:65:21:e8:f6:58:4a:22:48:b5:29:3d: 523 00:6c:3e:a2:e5:bd:a5:a3:d9:5a:4d:a9:cb:2a:f8:47:ca:72: 524 ea:9d:e1:87:e1:d1:75:5d:07:36:ba:ab:fd:7f:5f:d3:66:d0: 525 41:86:7c:6b:1e:a7:7c:9f:dc:26:7a:37:70:54:1e:7c:b3:66: 526 7f:f1:99:93:f4:8a:aa:81:02:e9:bf:5d:a5:90:94:82:6e:2a: 527 a6:c8:e1:77:df:66:59:d8:6c:b1:55:a0:77:d6:53:6b:78:aa: 528 4b:0d:fc:34:06:5c:52:4e:e6:5e:c7:94:13:19:70:e8:2b:00: 529 6d:ea:90:b9:f4:6f:74:3f:cc:e7:1d:3e:22:ec:66:cb:84:19: 530 7a:40:3c:7e:38:77:b4:4e:da:8c:4b:af:dc:c2:23:28:9d:60: 531 a5:4f:5a:c8:9e:17:df:b9:9d:92:bc:d3:c0:20:12:ec:22:d4: 532 e8:d4:97:9f:da:3c:35:a0:e9:a3:8c:d1:42:7c:c1:27:1f:8a: 533 9b:5b:03:3d:2b:9b:df:25:b6:a8:a7:5a:48:0f:e8:1f:26:4b: 534 0e:3c:a2:50:0a:cd:02:33:4c:e4:7a:c9:2d:b8:b8:bf:80:5a: 535 6e:07:49:c4:c3:23:a0:2e 536 -----BEGIN CERTIFICATE----- 537 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 568 PKJQCs0CM0zkesktuLi/gFpuB0nEwyOgLg== 569 -----END CERTIFICATE-----` 570 ) 571 572 func TestX509(t *testing.T) { 573 multilevelOpts := DefaultVerifyOptions() 574 multilevelOpts.Roots = x509.NewCertPool() 575 multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0]) 576 577 testCases := map[string]struct { 578 Insecure bool 579 Certs []*x509.Certificate 580 581 Opts x509.VerifyOptions 582 User UserConversion 583 584 ExpectUserName string 585 ExpectGroups []string 586 ExpectOK bool 587 ExpectErr bool 588 }{ 589 "non-tls": { 590 Insecure: true, 591 592 ExpectOK: false, 593 ExpectErr: false, 594 }, 595 596 "tls, no certs": { 597 ExpectOK: false, 598 ExpectErr: false, 599 }, 600 601 "self signed": { 602 Opts: getDefaultVerifyOptions(t), 603 Certs: getCerts(t, selfSignedCert), 604 User: CommonNameUserConversion, 605 606 ExpectErr: true, 607 }, 608 609 "server cert": { 610 Opts: getDefaultVerifyOptions(t), 611 Certs: getCerts(t, serverCert), 612 User: CommonNameUserConversion, 613 614 ExpectErr: true, 615 }, 616 "server cert allowing non-client cert usages": { 617 Opts: x509.VerifyOptions{Roots: getRootCertPool(t)}, 618 Certs: getCerts(t, serverCert), 619 User: CommonNameUserConversion, 620 621 ExpectUserName: "127.0.0.1", 622 ExpectGroups: []string{"My Org"}, 623 ExpectOK: true, 624 ExpectErr: false, 625 }, 626 627 "common name": { 628 Opts: getDefaultVerifyOptions(t), 629 Certs: getCerts(t, clientCNCert), 630 User: CommonNameUserConversion, 631 632 ExpectUserName: "client_cn", 633 ExpectGroups: []string{"My Org"}, 634 ExpectOK: true, 635 ExpectErr: false, 636 }, 637 "ca with multiple organizations": { 638 Opts: x509.VerifyOptions{ 639 Roots: getRootCertPoolFor(t, caWithGroups), 640 }, 641 Certs: getCerts(t, caWithGroups), 642 User: CommonNameUserConversion, 643 644 ExpectUserName: "ROOT CA WITH GROUPS", 645 ExpectGroups: []string{"My Org", "My Org 1", "My Org 2"}, 646 ExpectOK: true, 647 ExpectErr: false, 648 }, 649 650 "custom conversion error": { 651 Opts: getDefaultVerifyOptions(t), 652 Certs: getCerts(t, clientCNCert), 653 User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) { 654 return nil, false, errors.New("custom error") 655 }), 656 657 ExpectOK: false, 658 ExpectErr: true, 659 }, 660 "custom conversion success": { 661 Opts: getDefaultVerifyOptions(t), 662 Certs: getCerts(t, clientCNCert), 663 User: UserConversionFunc(func(chain []*x509.Certificate) (*authenticator.Response, bool, error) { 664 return &authenticator.Response{User: &user.DefaultInfo{Name: "custom"}}, true, nil 665 }), 666 667 ExpectUserName: "custom", 668 ExpectOK: true, 669 ExpectErr: false, 670 }, 671 672 "future cert": { 673 Opts: x509.VerifyOptions{ 674 CurrentTime: time.Now().Add(time.Duration(-100 * time.Hour * 24 * 365)), 675 Roots: getRootCertPool(t), 676 }, 677 Certs: getCerts(t, clientCNCert), 678 User: CommonNameUserConversion, 679 680 ExpectOK: false, 681 ExpectErr: true, 682 }, 683 "expired cert": { 684 Opts: x509.VerifyOptions{ 685 CurrentTime: time.Now().Add(time.Duration(100 * time.Hour * 24 * 365)), 686 Roots: getRootCertPool(t), 687 }, 688 Certs: getCerts(t, clientCNCert), 689 User: CommonNameUserConversion, 690 691 ExpectOK: false, 692 ExpectErr: true, 693 }, 694 695 "multi-level, valid": { 696 Opts: multilevelOpts, 697 Certs: getCertsFromFile(t, "client-valid", "intermediate"), 698 User: CommonNameUserConversion, 699 700 ExpectUserName: "My Client", 701 ExpectOK: true, 702 ExpectErr: false, 703 }, 704 "multi-level, expired": { 705 Opts: multilevelOpts, 706 Certs: getCertsFromFile(t, "client-expired", "intermediate"), 707 User: CommonNameUserConversion, 708 709 ExpectOK: false, 710 ExpectErr: true, 711 }, 712 } 713 714 for k, testCase := range testCases { 715 req, _ := http.NewRequest("GET", "/", nil) 716 if !testCase.Insecure { 717 req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs} 718 } 719 720 // this effectively tests the simple dynamic verify function. 721 a := New(testCase.Opts, testCase.User) 722 723 resp, ok, err := a.AuthenticateRequest(req) 724 725 if testCase.ExpectErr && err == nil { 726 t.Errorf("%s: Expected error, got none", k) 727 continue 728 } 729 if !testCase.ExpectErr && err != nil { 730 t.Errorf("%s: Got unexpected error: %v", k, err) 731 continue 732 } 733 734 if testCase.ExpectOK != ok { 735 t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok) 736 continue 737 } 738 739 if testCase.ExpectOK { 740 if testCase.ExpectUserName != resp.User.GetName() { 741 t.Errorf("%s: Expected user.name=%v, got %v", k, testCase.ExpectUserName, resp.User.GetName()) 742 } 743 744 groups := resp.User.GetGroups() 745 sort.Strings(testCase.ExpectGroups) 746 sort.Strings(groups) 747 if !reflect.DeepEqual(testCase.ExpectGroups, groups) { 748 t.Errorf("%s: Expected user.groups=%v, got %v", k, testCase.ExpectGroups, groups) 749 } 750 } 751 } 752 } 753 754 func TestX509Verifier(t *testing.T) { 755 multilevelOpts := DefaultVerifyOptions() 756 multilevelOpts.Roots = x509.NewCertPool() 757 multilevelOpts.Roots.AddCert(getCertsFromFile(t, "root")[0]) 758 759 testCases := map[string]struct { 760 Insecure bool 761 Certs []*x509.Certificate 762 763 Opts x509.VerifyOptions 764 765 AllowedCNs sets.String 766 767 ExpectOK bool 768 ExpectErr bool 769 }{ 770 "non-tls": { 771 Insecure: true, 772 773 ExpectOK: false, 774 ExpectErr: false, 775 }, 776 777 "tls, no certs": { 778 ExpectOK: false, 779 ExpectErr: false, 780 }, 781 782 "self signed": { 783 Opts: getDefaultVerifyOptions(t), 784 Certs: getCerts(t, selfSignedCert), 785 786 ExpectErr: true, 787 }, 788 789 "server cert disallowed": { 790 Opts: getDefaultVerifyOptions(t), 791 Certs: getCerts(t, serverCert), 792 793 ExpectErr: true, 794 }, 795 "server cert allowing non-client cert usages": { 796 Opts: x509.VerifyOptions{Roots: getRootCertPool(t)}, 797 Certs: getCerts(t, serverCert), 798 799 ExpectOK: true, 800 ExpectErr: false, 801 }, 802 803 "valid client cert": { 804 Opts: getDefaultVerifyOptions(t), 805 Certs: getCerts(t, clientCNCert), 806 807 ExpectOK: true, 808 ExpectErr: false, 809 }, 810 "valid client cert with wrong CN": { 811 Opts: getDefaultVerifyOptions(t), 812 AllowedCNs: sets.NewString("foo", "bar"), 813 Certs: getCerts(t, clientCNCert), 814 815 ExpectOK: false, 816 ExpectErr: true, 817 }, 818 "valid client cert with right CN": { 819 Opts: getDefaultVerifyOptions(t), 820 AllowedCNs: sets.NewString("client_cn"), 821 Certs: getCerts(t, clientCNCert), 822 823 ExpectOK: true, 824 ExpectErr: false, 825 }, 826 827 "future cert": { 828 Opts: x509.VerifyOptions{ 829 CurrentTime: time.Now().Add(-100 * time.Hour * 24 * 365), 830 Roots: getRootCertPool(t), 831 }, 832 Certs: getCerts(t, clientCNCert), 833 834 ExpectOK: false, 835 ExpectErr: true, 836 }, 837 "expired cert": { 838 Opts: x509.VerifyOptions{ 839 CurrentTime: time.Now().Add(100 * time.Hour * 24 * 365), 840 Roots: getRootCertPool(t), 841 }, 842 Certs: getCerts(t, clientCNCert), 843 844 ExpectOK: false, 845 ExpectErr: true, 846 }, 847 848 "multi-level, valid": { 849 Opts: multilevelOpts, 850 Certs: getCertsFromFile(t, "client-valid", "intermediate"), 851 852 ExpectOK: true, 853 ExpectErr: false, 854 }, 855 "multi-level, expired": { 856 Opts: multilevelOpts, 857 Certs: getCertsFromFile(t, "client-expired", "intermediate"), 858 859 ExpectOK: false, 860 ExpectErr: true, 861 }, 862 } 863 864 for k, testCase := range testCases { 865 req, _ := http.NewRequest("GET", "/", nil) 866 if !testCase.Insecure { 867 req.TLS = &tls.ConnectionState{PeerCertificates: testCase.Certs} 868 } 869 870 authCall := false 871 auth := authenticator.RequestFunc(func(req *http.Request) (*authenticator.Response, bool, error) { 872 authCall = true 873 return &authenticator.Response{User: &user.DefaultInfo{Name: "innerauth"}}, true, nil 874 }) 875 876 a := NewVerifier(testCase.Opts, auth, testCase.AllowedCNs) 877 878 resp, ok, err := a.AuthenticateRequest(req) 879 880 if testCase.ExpectErr && err == nil { 881 t.Errorf("%s: Expected error, got none", k) 882 continue 883 } 884 if !testCase.ExpectErr && err != nil { 885 t.Errorf("%s: Got unexpected error: %v", k, err) 886 continue 887 } 888 889 if testCase.ExpectOK != ok { 890 t.Errorf("%s: Expected ok=%v, got %v", k, testCase.ExpectOK, ok) 891 continue 892 } 893 894 if testCase.ExpectOK { 895 if !authCall { 896 t.Errorf("%s: Expected inner auth called, wasn't", k) 897 continue 898 } 899 if "innerauth" != resp.User.GetName() { 900 t.Errorf("%s: Expected user.name=%v, got %v", k, "innerauth", resp.User.GetName()) 901 continue 902 } 903 } else { 904 if authCall { 905 t.Errorf("%s: Expected inner auth not to be called, was", k) 906 continue 907 } 908 } 909 } 910 } 911 912 func getDefaultVerifyOptions(t *testing.T) x509.VerifyOptions { 913 options := DefaultVerifyOptions() 914 options.Roots = getRootCertPool(t) 915 return options 916 } 917 918 func getRootCertPool(t *testing.T) *x509.CertPool { 919 return getRootCertPoolFor(t, rootCACert) 920 } 921 922 func getRootCertPoolFor(t *testing.T, certs ...string) *x509.CertPool { 923 pool := x509.NewCertPool() 924 for _, cert := range certs { 925 pool.AddCert(getCert(t, cert)) 926 } 927 return pool 928 } 929 930 func getCertsFromFile(t *testing.T, names ...string) []*x509.Certificate { 931 certs := []*x509.Certificate{} 932 for _, name := range names { 933 filename := "testdata/" + name + ".pem" 934 data, err := ioutil.ReadFile(filename) 935 if err != nil { 936 t.Fatalf("error reading %s: %v", filename, err) 937 } 938 certs = append(certs, getCert(t, string(data))) 939 } 940 return certs 941 } 942 943 func getCert(t *testing.T, pemData string) *x509.Certificate { 944 t.Helper() 945 946 pemBlock, _ := pem.Decode([]byte(pemData)) 947 cert, err := x509.ParseCertificate(pemBlock.Bytes) 948 if err != nil { 949 t.Fatalf("Error parsing cert: %v", err) 950 return nil 951 } 952 return cert 953 } 954 955 func getCerts(t *testing.T, pemData ...string) []*x509.Certificate { 956 certs := []*x509.Certificate{} 957 for _, pemData := range pemData { 958 certs = append(certs, getCert(t, pemData)) 959 } 960 return certs 961 } 962 963 func TestCertificateIdentifier(t *testing.T) { 964 tt := []struct { 965 name string 966 cert *x509.Certificate 967 expectedIdentifier string 968 }{ 969 { 970 name: "client cert", 971 cert: getCert(t, clientCNCert), 972 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", 973 }, 974 { 975 name: "nil serial", 976 cert: func() *x509.Certificate { 977 c := getCert(t, clientCNCert) 978 c.SerialNumber = nil 979 return c 980 }(), 981 expectedIdentifier: "SN=<nil>, 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", 982 }, 983 { 984 name: "empty SKID", 985 cert: func() *x509.Certificate { 986 c := getCert(t, clientCNCert) 987 c.SubjectKeyId = nil 988 return c 989 }(), 990 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", 991 }, 992 { 993 name: "empty AKID", 994 cert: func() *x509.Certificate { 995 c := getCert(t, clientCNCert) 996 c.AuthorityKeyId = nil 997 return c 998 }(), 999 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=", 1000 }, 1001 { 1002 name: "self-signed", 1003 cert: getCert(t, selfSignedCert), 1004 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", 1005 }, 1006 } 1007 1008 for _, tc := range tt { 1009 t.Run(tc.name, func(t *testing.T) { 1010 got := certificateIdentifier(tc.cert) 1011 if got != tc.expectedIdentifier { 1012 t.Errorf("expected %q, got %q", tc.expectedIdentifier, got) 1013 } 1014 }) 1015 } 1016 }