From 2efef8fd1214261d09879e6c62d1f8a9bdd67fff Mon Sep 17 00:00:00 2001 From: ZhenLian Date: Thu, 3 Dec 2020 09:52:30 -0800 Subject: [PATCH] advancedtls: fix default host name check issue (#4069) * advancedtls: fix default hostname check issue --- security/advancedtls/advancedtls.go | 8 +- security/advancedtls/advancedtls_test.go | 23 +++- .../internal/testutils/testutils.go | 7 + security/advancedtls/testdata/README.md | 8 +- .../testdata/localhost-openssl.cnf | 24 ++++ security/advancedtls/testdata/openssl-ca.cnf | 87 ++++++++++++ .../testdata/server_cert_localhost_1.pem | 124 ++++++++++++++++++ .../testdata/server_key_localhost_1.pem | 51 +++++++ 8 files changed, 326 insertions(+), 6 deletions(-) create mode 100644 security/advancedtls/testdata/localhost-openssl.cnf create mode 100644 security/advancedtls/testdata/openssl-ca.cnf create mode 100644 security/advancedtls/testdata/server_cert_localhost_1.pem create mode 100644 security/advancedtls/testdata/server_key_localhost_1.pem diff --git a/security/advancedtls/advancedtls.go b/security/advancedtls/advancedtls.go index ea93d6406..534a3ed41 100644 --- a/security/advancedtls/advancedtls.go +++ b/security/advancedtls/advancedtls.go @@ -492,7 +492,13 @@ func buildVerifyFunc(c *advancedTLSCreds, } // Perform default hostname check if specified. if c.isClient && c.vType == CertAndHostVerification && serverName != "" { - opts.DNSName = serverName + parsedName, _, err := net.SplitHostPort(serverName) + if err != nil { + // If the serverName had no host port or if the serverName cannot be + // parsed, use it as-is. + parsedName = serverName + } + opts.DNSName = parsedName } var err error chains, err = certs[0].Verify(opts) diff --git a/security/advancedtls/advancedtls_test.go b/security/advancedtls/advancedtls_test.go index 2d6ec47b7..4cb4748c6 100644 --- a/security/advancedtls/advancedtls_test.go +++ b/security/advancedtls/advancedtls_test.go @@ -377,8 +377,8 @@ func (s) TestClientServerHandshake(t *testing.T) { // Server: only set serverCert with mutual TLS off // Expected Behavior: server side failure and client handshake failure // Reason: client side sets vType to CertAndHostVerification, and will do - // default hostname check. All the default hostname checks will fail in - // this test suites. + // default hostname check. Server uses a cert without "localhost" or + // "127.0.0.1" as common name or SAN names, and will hence fail. { desc: "Client has root cert; server sends peer cert", clientRoot: cs.ClientTrust1, @@ -392,8 +392,8 @@ func (s) TestClientServerHandshake(t *testing.T) { // Server: only set serverCert with mutual TLS off // Expected Behavior: server side failure and client handshake failure // Reason: client side sets vType to CertAndHostVerification, and will do - // default hostname check. All the default hostname checks will fail in - // this test suites. + // default hostname check. Server uses a cert without "localhost" or + // "127.0.0.1" as common name or SAN names, and will hence fail. { desc: "Client sets reload root function; server sends peer cert", clientGetRoot: getRootCAsForClient, @@ -403,6 +403,21 @@ func (s) TestClientServerHandshake(t *testing.T) { serverVType: CertAndHostVerification, serverExpectError: true, }, + // Client: only set clientGetRoot and CertAndHostVerification + // Server: only set serverCert with mutual TLS off + // Expected Behavior: success + // Reason: client side sets vType to CertAndHostVerification, and will do + // default hostname check. Server uses a certificate with "localhost" as + // common name, and will hence pass the default hostname check. + { + desc: "Client sets CertAndHostVerification; server uses localhost certs", + clientRoot: cs.ClientTrust1, + clientVType: CertAndHostVerification, + clientExpectHandshakeError: false, + serverCert: []tls.Certificate{cs.ServerPeerLocalhost1}, + serverVType: CertAndHostVerification, + serverExpectError: false, + }, // Client: set clientGetRoot and clientVerifyFunc // Server: only set serverCert with mutual TLS off // Expected Behavior: success diff --git a/security/advancedtls/internal/testutils/testutils.go b/security/advancedtls/internal/testutils/testutils.go index 665cc6026..a2c048882 100644 --- a/security/advancedtls/internal/testutils/testutils.go +++ b/security/advancedtls/internal/testutils/testutils.go @@ -43,6 +43,10 @@ type CertStore struct { ServerCert2 tls.Certificate // ServerPeer3 is the certificate sent by server to prove its identity. ServerPeer3 tls.Certificate + // ServerPeerLocalhost1 is the certificate sent by server to prove its + // identity. It has "localhost" as its common name, and is trusted by + // ClientTrust1. + ServerPeerLocalhost1 tls.Certificate // ClientTrust1 is the root certificate used on the client side. ClientTrust1 *x509.CertPool // ClientTrust2 is the root certificate used on the client side. @@ -84,6 +88,9 @@ func (cs *CertStore) LoadCerts() error { if cs.ServerPeer3, err = tls.LoadX509KeyPair(testdata.Path("server_cert_3.pem"), testdata.Path("server_key_3.pem")); err != nil { return err } + if cs.ServerPeerLocalhost1, err = tls.LoadX509KeyPair(testdata.Path("server_cert_localhost_1.pem"), testdata.Path("server_key_localhost_1.pem")); err != nil { + return err + } if cs.ClientTrust1, err = readTrustCert(testdata.Path("client_trust_cert_1.pem")); err != nil { return err } diff --git a/security/advancedtls/testdata/README.md b/security/advancedtls/testdata/README.md index 48a1c135c..3e4057ef3 100644 --- a/security/advancedtls/testdata/README.md +++ b/security/advancedtls/testdata/README.md @@ -19,6 +19,11 @@ commands we run: ``` $ openssl req -new -key subject_key.pem -out csr.pem ``` + For some cases, we might want to add some extra SAN fields in `subject_cert.pem`. + In those cases, we can create a configuration file(for example, localhost-openssl.cnf), and do the following: + ``` + $ openssl req -new -key subject_key.pem -out csr.pem -config $CONFIG_FILE_NAME + ``` 3. Generate a private key `subject_key.pem` for the subject: @@ -28,11 +33,12 @@ commands we run: 4. Use `ca_key.pem` and `ca_cert.pem` to sign `csr.pem`, and get a certificate, `subject_cert.pem`, for the subject: - This step requires some additional files and please check out [this answer from StackOverflow](https://stackoverflow.com/a/21340898) for more. + This step requires some additional configuration steps and please check out [this answer from StackOverflow](https://stackoverflow.com/a/21340898) for more. ``` $ openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out subject_cert.pem -in csr.pem -keyfile ca_key.pem -cert ca_cert.pem ``` + Please see an example configuration template at `openssl-ca.cnf`. 5. Verify the `subject_cert.pem` is trusted by `ca_cert.pem`: diff --git a/security/advancedtls/testdata/localhost-openssl.cnf b/security/advancedtls/testdata/localhost-openssl.cnf new file mode 100644 index 000000000..b415cef6a --- /dev/null +++ b/security/advancedtls/testdata/localhost-openssl.cnf @@ -0,0 +1,24 @@ +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req + +[req_distinguished_name] +countryName = Country Name (2 letter code) +countryName_default = US +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Illinois +localityName = Locality Name (eg, city) +localityName_default = Chicago +organizationName = Organization Name (eg, company) +organizationName_default = Example, Co. +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +[v3_req] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = localhost +IP.1 = "127.0.0.1" diff --git a/security/advancedtls/testdata/openssl-ca.cnf b/security/advancedtls/testdata/openssl-ca.cnf new file mode 100644 index 000000000..196a50c26 --- /dev/null +++ b/security/advancedtls/testdata/openssl-ca.cnf @@ -0,0 +1,87 @@ +base_dir = . +certificate = $base_dir/cacert.pem # The CA certifcate +private_key = $base_dir/cakey.pem # The CA private key +new_certs_dir = $base_dir # Location for new certs after signing +database = $base_dir/index.txt # Database index file +serial = $base_dir/serial.txt # The current serial number + +unique_subject = no # Set to 'no' to allow creation of + # several certificates with same subject. + +HOME = . +RANDFILE = $ENV::HOME/.rnd + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +[ CA_default ] + +default_days = 10000 # How long to certify for +default_crl_days = 30 # How long before next CRL +default_md = sha256 # Use public key default MD +preserve = no # Keep passed DN ordering + +x509_extensions = ca_extensions # The extensions to add to the cert + +email_in_dn = no # Don't concat the email in the DN +copy_extensions = copy # Required to copy SANs from CSR to cert + +#################################################################### +[ req ] +default_bits = 4096 +default_keyfile = cakey.pem +distinguished_name = ca_distinguished_name +x509_extensions = ca_extensions +string_mask = utf8only + +#################################################################### +[ ca_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Maryland + +localityName = Locality Name (eg, city) +localityName_default = Baltimore + +organizationName = Organization Name (eg, company) +organizationName_default = Test CA, Limited + +organizationalUnitName = Organizational Unit (eg, division) +organizationalUnitName_default = Server Research Department + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_default = Test CA + +emailAddress = Email Address +emailAddress_default = test@example.com + +#################################################################### +[ ca_extensions ] + +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always, issuer +basicConstraints = critical, CA:true +keyUsage = keyCertSign, cRLSign + + + + +#################################################################### +[ signing_policy ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ signing_req ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment diff --git a/security/advancedtls/testdata/server_cert_localhost_1.pem b/security/advancedtls/testdata/server_cert_localhost_1.pem new file mode 100644 index 000000000..798656198 --- /dev/null +++ b/security/advancedtls/testdata/server_cert_localhost_1.pem @@ -0,0 +1,124 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=CA, L=SVL, O=Internet Widgits Pty Ltd + Validity + Not Before: Dec 2 21:51:53 2020 GMT + Not After : Apr 19 21:51:53 2048 GMT + Subject: C=US, ST=Illinois, L=Chicago, O=Example, Co., CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:a0:a1:5e:05:53:c5:a7:71:fb:ff:22:d5:d2:49: + da:14:8b:54:9b:fb:40:3d:33:38:7d:3e:69:16:1c: + 1f:c1:88:42:99:d2:ac:8e:3e:60:ca:ac:63:e2:5b: + e8:90:e5:4d:1b:e5:0b:40:6d:7d:90:6a:de:7f:ad: + 97:81:ae:38:2c:07:44:ca:ac:54:d7:dd:41:99:36: + ca:38:44:9e:cc:e0:34:c2:44:71:2e:59:60:bf:45: + e5:57:af:7d:d2:ca:c5:53:ff:8a:ab:5f:68:cf:74: + 88:29:99:59:fc:25:8c:06:47:26:77:14:1e:10:c1: + 78:d6:a1:a5:7f:0d:8d:4a:be:c8:fd:6f:a1:60:3d: + e8:0a:27:f9:fe:e1:45:81:7c:e6:be:65:b8:62:ed: + ca:1f:fb:7f:08:c0:b4:a6:57:f1:56:32:53:bf:d6: + 43:75:57:1c:e2:69:8d:96:41:a6:46:a0:49:1d:e8: + ab:0a:92:7b:b8:33:b2:c3:7b:6e:2b:53:13:be:91: + 34:71:e3:d9:52:e4:d5:63:64:f8:a7:b0:a0:23:5c: + 07:3d:82:9a:6e:bc:0a:95:f1:51:ff:08:75:1c:32: + 38:67:9a:98:5c:94:08:90:c2:23:cd:bb:ad:86:10: + 4f:34:b2:28:f8:83:0f:c3:cb:3a:80:a9:2e:9a:3e: + 45:bf:2c:55:ee:22:d7:e4:a3:d7:b4:0b:7c:fb:30: + fa:a7:02:24:04:ba:60:79:2d:1d:01:6c:b1:17:b9: + b9:f3:4f:c7:20:26:6d:48:31:b2:6d:27:b8:5d:fc: + 8a:20:be:29:30:26:18:a4:51:45:3c:47:06:22:fa: + 9e:c7:43:ac:34:5b:6e:23:08:c9:ea:93:b7:de:5e: + 36:9a:85:51:8a:01:86:c0:47:52:4f:9b:d6:16:ce: + ff:3a:5f:33:ff:f5:24:20:5d:ef:f9:ea:21:fd:05: + 04:b9:c6:b5:75:67:67:d5:48:70:d0:e8:53:f2:ff: + f7:a0:8b:1c:09:bf:5d:08:b2:5d:08:34:00:a3:f1: + fc:6d:44:e5:73:eb:6d:24:a2:0f:aa:4a:d1:8f:fe: + 40:a4:77:94:63:99:82:26:d0:66:a4:a2:97:59:2b: + 30:18:4b:d1:22:a9:99:02:4c:06:50:ff:12:6e:83: + 11:ff:08:7f:c2:8e:ae:83:0f:a9:b6:99:3e:cc:8e: + c7:a6:17:65:65:0e:9f:7d:48:28:6d:e7:b6:e5:7a: + b1:36:04:fe:db:0e:62:3a:e2:a1:bf:b9:76:23:bf: + b8:4f:a4:68:bf:03:1c:53:34:55:d0:28:2d:89:10: + 28:2d:2c:ca:8b:b9:5a:82:f4:5f:b9:eb:ef:aa:f2: + 31:f0:d5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + B2:87:7F:58:33:AD:24:C6:F2:07:5D:8E:88:18:BE:61:08:20:29:D1 + X509v3 Authority Key Identifier: + keyid:5A:A5:DA:B1:99:D4:E5:0E:E6:1E:94:EA:FF:FC:62:E2:ED:09:F1:06 + + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Key Encipherment + X509v3 Subject Alternative Name: + DNS:localhost, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + bd:79:29:a5:d1:35:3d:34:61:3e:88:d7:37:66:c0:48:2e:ba: + 8f:ed:56:b6:48:3f:1b:7d:eb:b7:91:0f:13:c3:96:d3:bd:82: + 0c:00:49:3f:1a:44:12:4c:27:f5:48:39:04:bd:66:d8:64:e1: + 5f:c7:01:43:82:38:1e:7f:94:6c:96:00:97:06:b7:d6:d1:0d: + 0a:34:a9:f1:3d:ac:0b:4f:0c:2e:ff:69:3d:53:63:9b:c1:22: + e8:5a:b9:cd:00:92:a0:b6:cd:c0:21:b2:fc:2e:70:8e:2d:e3: + ed:4a:f0:84:24:3f:7e:b9:a7:cf:05:1d:15:cc:a3:8a:6e:0d: + 44:28:02:bf:03:31:02:00:eb:1d:6c:60:8e:9c:73:0a:b6:f7: + ad:61:c4:a5:60:dc:4e:44:79:3e:95:40:44:5a:9b:58:61:3d: + b6:5f:68:8f:c0:98:3d:a4:b1:41:fb:b4:ad:d3:b6:8b:72:f0: + c2:ec:8a:65:ac:a7:2e:ea:f7:e5:2c:8d:3a:18:36:d2:48:36: + 5d:a2:1a:52:22:40:a6:da:7d:52:e5:ba:d7:fd:75:63:8b:9b: + ff:ad:20:bf:a0:f9:d4:e7:f1:b2:cb:a7:09:c7:d0:36:bc:ea: + be:f1:29:08:22:25:2a:16:3f:22:3b:2b:53:47:73:01:68:d2: + 1e:3d:87:07:6f:ec:c4:33:3e:44:ec:a3:de:32:7e:12:57:15: + 30:d4:6d:be:16:e7:ba:28:0e:8a:79:8a:ab:84:f8:1d:8c:d9: + da:06:1b:7e:37:10:3f:24:7c:1f:74:bc:0e:44:cf:a6:56:97: + 02:19:b7:a7:f3:5d:46:c8:56:7b:19:b3:42:17:f2:97:cf:15: + d6:78:8d:90:f9:88:f7:28:71:7d:8d:ff:50:bb:d1:71:bb:23: + da:53:63:92:7c:d4:a8:be:45:17:d4:6a:e7:e3:75:93:b5:bb: + fd:38:30:11:ab:ec:f5:7b:6e:f5:17:0b:cc:69:44:79:3f:95: + 85:e8:6b:da:e7:af:b3:f6:e8:73:22:db:75:f8:40:20:fd:cb: + 24:b6:49:b6:69:79:12:8e:73:05:75:a0:de:67:5c:29:05:11: + 3a:b2:8d:f8:ec:2f:fa:99:5e:3a:2b:df:3b:69:1a:c3:05:6c: + 44:3c:a1:12:ab:3c:5b:87:52:a5:44:54:6c:c8:e5:f6:50:dd: + d7:d4:93:15:67:31:66:58:10:c1:23:98:35:08:6b:56:34:5a: + 71:db:67:e5:41:a8:60:77:c3:30:2a:09:78:37:83:32:37:b1: + c5:34:b6:54:79:fd:e0:13:a3:16:f5:5f:25:87:8e:5e:c3:93: + f9:1f:4c:79:51:0f:23:e6 +-----BEGIN CERTIFICATE----- +MIIFmTCCA4GgAwIBAgIBAzANBgkqhkiG9w0BAQsFADBLMQswCQYDVQQGEwJVUzEL +MAkGA1UECAwCQ0ExDDAKBgNVBAcMA1NWTDEhMB8GA1UECgwYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMB4XDTIwMTIwMjIxNTE1M1oXDTQ4MDQxOTIxNTE1M1owXTEL +MAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdv +MRUwEwYDVQQKDAxFeGFtcGxlLCBDby4xEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKChXgVTxadx+/8i1dJJ2hSLVJv7 +QD0zOH0+aRYcH8GIQpnSrI4+YMqsY+Jb6JDlTRvlC0BtfZBq3n+tl4GuOCwHRMqs +VNfdQZk2yjhEnszgNMJEcS5ZYL9F5VevfdLKxVP/iqtfaM90iCmZWfwljAZHJncU +HhDBeNahpX8NjUq+yP1voWA96Aon+f7hRYF85r5luGLtyh/7fwjAtKZX8VYyU7/W +Q3VXHOJpjZZBpkagSR3oqwqSe7gzssN7bitTE76RNHHj2VLk1WNk+KewoCNcBz2C +mm68CpXxUf8IdRwyOGeamFyUCJDCI827rYYQTzSyKPiDD8PLOoCpLpo+Rb8sVe4i +1+Sj17QLfPsw+qcCJAS6YHktHQFssRe5ufNPxyAmbUgxsm0nuF38iiC+KTAmGKRR +RTxHBiL6nsdDrDRbbiMIyeqTt95eNpqFUYoBhsBHUk+b1hbO/zpfM//1JCBd7/nq +If0FBLnGtXVnZ9VIcNDoU/L/96CLHAm/XQiyXQg0AKPx/G1E5XPrbSSiD6pK0Y/+ +QKR3lGOZgibQZqSil1krMBhL0SKpmQJMBlD/Em6DEf8If8KOroMPqbaZPsyOx6YX +ZWUOn31IKG3ntuV6sTYE/tsOYjriob+5diO/uE+kaL8DHFM0VdAoLYkQKC0syou5 +WoL0X7nr76ryMfDVAgMBAAGjdjB0MB0GA1UdDgQWBBSyh39YM60kxvIHXY6IGL5h +CCAp0TAfBgNVHSMEGDAWgBRapdqxmdTlDuYelOr//GLi7QnxBjAJBgNVHRMEAjAA +MAsGA1UdDwQEAwIFoDAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZI +hvcNAQELBQADggIBAL15KaXRNT00YT6I1zdmwEguuo/tVrZIPxt967eRDxPDltO9 +ggwAST8aRBJMJ/VIOQS9Zthk4V/HAUOCOB5/lGyWAJcGt9bRDQo0qfE9rAtPDC7/ +aT1TY5vBIuhauc0AkqC2zcAhsvwucI4t4+1K8IQkP365p88FHRXMo4puDUQoAr8D +MQIA6x1sYI6ccwq2961hxKVg3E5EeT6VQERam1hhPbZfaI/AmD2ksUH7tK3Ttoty +8MLsimWspy7q9+UsjToYNtJINl2iGlIiQKbafVLlutf9dWOLm/+tIL+g+dTn8bLL +pwnH0Da86r7xKQgiJSoWPyI7K1NHcwFo0h49hwdv7MQzPkTso94yfhJXFTDUbb4W +57ooDop5iquE+B2M2doGG343ED8kfB90vA5Ez6ZWlwIZt6fzXUbIVnsZs0IX8pfP +FdZ4jZD5iPcocX2N/1C70XG7I9pTY5J81Ki+RRfUaufjdZO1u/04MBGr7PV7bvUX +C8xpRHk/lYXoa9rnr7P26HMi23X4QCD9yyS2SbZpeRKOcwV1oN5nXCkFETqyjfjs +L/qZXjor3ztpGsMFbEQ8oRKrPFuHUqVEVGzI5fZQ3dfUkxVnMWZYEMEjmDUIa1Y0 +WnHbZ+VBqGB3wzAqCXg3gzI3scU0tlR5/eAToxb1XyWHjl7Dk/kfTHlRDyPm +-----END CERTIFICATE----- diff --git a/security/advancedtls/testdata/server_key_localhost_1.pem b/security/advancedtls/testdata/server_key_localhost_1.pem new file mode 100644 index 000000000..17d9f9815 --- /dev/null +++ b/security/advancedtls/testdata/server_key_localhost_1.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY-----