1/* 2 * Copyright (C) 2010 The Android Open Source Project 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 17package libcore.javax.net.ssl; 18 19import java.io.ByteArrayInputStream; 20import java.io.InputStream; 21import java.math.BigInteger; 22import java.nio.charset.StandardCharsets; 23import java.security.Principal; 24import java.security.PublicKey; 25import java.security.cert.Certificate; 26import java.security.cert.CertificateFactory; 27import java.security.cert.X509Certificate; 28import java.util.ArrayList; 29import java.util.Collection; 30import java.util.Date; 31import java.util.LinkedList; 32import java.util.List; 33import java.util.Set; 34import javax.net.ssl.HostnameVerifier; 35import javax.net.ssl.HttpsURLConnection; 36import javax.net.ssl.SSLPeerUnverifiedException; 37import javax.net.ssl.SSLSession; 38import javax.net.ssl.SSLSessionContext; 39import javax.security.auth.x500.X500Principal; 40import junit.framework.TestCase; 41 42/** 43 * Tests for the platform-default {@link HostnameVerifier} as provided by 44 * {@link HttpsURLConnection#getDefaultHostnameVerifier()}. 45 */ 46public final class DefaultHostnameVerifierTest extends TestCase { 47 private static final int ALT_UNKNOWN = 0; 48 private static final int ALT_DNS_NAME = 2; 49 private static final int ALT_IPA_NAME = 7; 50 51 private final HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); 52 53 public void testVerify() { 54 assertTrue(verifyWithServerCertificate( 55 "imap.g.com", new StubX509Certificate("cn=imap.g.com"))); 56 assertFalse(verifyWithServerCertificate( 57 "imap.g.com", new StubX509Certificate("cn=imap2.g.com"))); 58 assertFalse(verifyWithServerCertificate( 59 "imap.g.com", new StubX509Certificate("cn=sub.imap.g.com"))); 60 } 61 62 /** 63 * If a subjectAltName extension of type ALT_DNS_NAME is present, that MUST 64 * be used as the identity and the CN should be ignored. 65 */ 66 public void testSubjectAltNameAndCn() { 67 assertFalse(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("") 68 .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com"))); 69 assertFalse( 70 verifyWithServerCertificate("imap.g.com", new StubX509Certificate("cn=imap.g.com") 71 .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com"))); 72 assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("") 73 .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com"))); 74 } 75 76 public void testSubjectAltNameWithWildcard() { 77 assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("") 78 .addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com"))); 79 } 80 81 public void testSubjectAltNameWithIpAddress() { 82 assertTrue(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("") 83 .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4"))); 84 assertFalse(verifyWithServerCertificate("1.2.3.5", new StubX509Certificate("") 85 .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4"))); 86 assertTrue(verifyWithServerCertificate("192.168.100.1", new StubX509Certificate("") 87 .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4") 88 .addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1"))); 89 } 90 91 public void testUnknownSubjectAltName() { 92 // Has unknown subject alternative names 93 assertTrue(verifyWithServerCertificate("imap.g.com", new StubX509Certificate("") 94 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") 95 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") 96 .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") 97 .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") 98 .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") 99 .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") 100 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3"))); 101 assertTrue(verifyWithServerCertificate("2.33.44.55", new StubX509Certificate("") 102 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") 103 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") 104 .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") 105 .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") 106 .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") 107 .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") 108 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3"))); 109 assertFalse(verifyWithServerCertificate("g.com", new StubX509Certificate("") 110 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") 111 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") 112 .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") 113 .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") 114 .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") 115 .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") 116 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3"))); 117 assertFalse(verifyWithServerCertificate("2.33.44.1", new StubX509Certificate("") 118 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") 119 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") 120 .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") 121 .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") 122 .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") 123 .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") 124 .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3"))); 125 } 126 127 public void testWildcardsRejectedForIpAddress() { 128 assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4"))); 129 assertFalse(verifyWithServerCertificate("1.2.3.4", new StubX509Certificate("cn=*.2.3.4") 130 .addSubjectAlternativeName(ALT_IPA_NAME, "*.2.3.4") 131 .addSubjectAlternativeName(ALT_DNS_NAME, "*.2.3.4"))); 132 assertFalse(verifyWithServerCertificate( 133 "2001:1234::1", new StubX509Certificate("cn=*:1234::1"))); 134 assertFalse(verifyWithServerCertificate( 135 "2001:1234::1", new StubX509Certificate("cn=*:1234::1") 136 .addSubjectAlternativeName(ALT_IPA_NAME, "*:1234::1") 137 .addSubjectAlternativeName(ALT_DNS_NAME, "*:1234::1"))); 138 } 139 140 public void testNullParameters() { 141 // Confirm that neither of the parameters used later in the test cause the verifier to blow 142 // up 143 String hostname = "www.example.com"; 144 StubSSLSession session = new StubSSLSession(); 145 session.peerCertificates = 146 new Certificate[] {new StubX509Certificate("cn=www.example.com")}; 147 verifier.verify(hostname, session); 148 149 try { 150 verifier.verify(hostname, null); 151 fail(); 152 } catch (NullPointerException expected) { 153 } 154 155 try { 156 verifier.verify(null, session); 157 fail(); 158 } catch (NullPointerException expected) { 159 } 160 } 161 162 public void testInvalidDomainNames() { 163 assertFalse(verifyWithDomainNamePattern("", "")); 164 assertFalse(verifyWithDomainNamePattern(".test.example.com", ".test.example.com")); 165 assertFalse(verifyWithDomainNamePattern("ex*ample.com", "ex*ample.com")); 166 assertFalse(verifyWithDomainNamePattern("example.com..", "example.com.")); 167 assertFalse(verifyWithDomainNamePattern("example.com.", "example.com..")); 168 } 169 170 public void testWildcardCharacterMustBeLeftMostLabelOnly() { 171 assertFalse(verifyWithDomainNamePattern("test.www.example.com", "test.*.example.com")); 172 assertFalse(verifyWithDomainNamePattern("www.example.com", "www.*.com")); 173 assertFalse(verifyWithDomainNamePattern("www.example.com", "www.example.*")); 174 assertFalse(verifyWithDomainNamePattern("www.example.com", "*www.example.com")); 175 assertFalse(verifyWithDomainNamePattern("www.example.com", "*w.example.com")); 176 assertFalse(verifyWithDomainNamePattern("www.example.com", "w*w.example.com")); 177 assertFalse(verifyWithDomainNamePattern("www.example.com", "w*.example.com")); 178 assertFalse(verifyWithDomainNamePattern("www.example.com", "www*.example.com")); 179 } 180 181 public void testWildcardCannotMatchEmptyLabel() { 182 assertFalse(verifyWithDomainNamePattern("example.com", "*.example.com")); 183 assertFalse(verifyWithDomainNamePattern(".example.com", "*.example.com")); 184 } 185 186 public void testWildcardCannotMatchChildDomain() { 187 assertFalse(verifyWithDomainNamePattern("sub.www.example.com", "*.example.com")); 188 } 189 190 public void testWildcardRejectedForSingleLabelPatterns() { 191 assertFalse(verifyWithDomainNamePattern("d", "*")); 192 assertFalse(verifyWithDomainNamePattern("d.", "*.")); 193 assertFalse(verifyWithDomainNamePattern("d", "d*")); 194 assertFalse(verifyWithDomainNamePattern("d.", "d*.")); 195 assertFalse(verifyWithDomainNamePattern("d", "*d")); 196 assertFalse(verifyWithDomainNamePattern("d.", "*d.")); 197 assertFalse(verifyWithDomainNamePattern("ddd", "d*d")); 198 assertFalse(verifyWithDomainNamePattern("ddd.", "d*d.")); 199 } 200 201 public void testNoPrefixMatch() { 202 assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "imap.google.com")); 203 assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "*.google.com")); 204 } 205 206 public void testVerifyHostName() { 207 assertTrue(verifyWithDomainNamePattern("a.b.c.d", "a.b.c.d")); 208 assertTrue(verifyWithDomainNamePattern("a.b.c.d", "*.b.c.d")); 209 assertFalse(verifyWithDomainNamePattern("a.b.c.d", "*.*.c.d")); 210 assertTrue(verifyWithDomainNamePattern("imap.google.com", "imap.google.com")); 211 assertFalse(verifyWithDomainNamePattern("imap2.google.com", "imap.google.com")); 212 assertTrue(verifyWithDomainNamePattern("imap.google.com", "*.google.com")); 213 assertTrue(verifyWithDomainNamePattern("imap2.google.com", "*.google.com")); 214 assertFalse(verifyWithDomainNamePattern("imap.google.com", "*.googl.com")); 215 assertFalse(verifyWithDomainNamePattern("imap2.google2.com", "*.google3.com")); 216 assertFalse(verifyWithDomainNamePattern("imap.google.com", "a*.google.com")); 217 assertFalse(verifyWithDomainNamePattern("imap.google.com", "ix*.google.com")); 218 assertTrue(verifyWithDomainNamePattern("imap.google.com", "iMap.Google.Com")); 219 assertTrue(verifyWithDomainNamePattern("weird", "weird")); 220 assertTrue(verifyWithDomainNamePattern("weird", "weird.")); 221 222 // Wildcards rejected for domain names consisting of fewer than two labels (excluding root). 223 assertFalse(verifyWithDomainNamePattern("weird", "weird*")); 224 assertFalse(verifyWithDomainNamePattern("weird", "*weird")); 225 assertFalse(verifyWithDomainNamePattern("weird", "weird*.")); 226 assertFalse(verifyWithDomainNamePattern("weird", "weird.*")); 227 } 228 229 public void testVerifyAbsoluteHostName() { 230 assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "a.b.c.d")); 231 assertTrue(verifyWithDomainNamePattern("a.b.c.d.", "*.b.c.d")); 232 assertFalse(verifyWithDomainNamePattern("a.b.c.d.", "*.*.c.d")); 233 assertTrue(verifyWithDomainNamePattern("imap.google.com.", "imap.google.com")); 234 assertFalse(verifyWithDomainNamePattern("imap2.google.com.", "imap.google.com")); 235 assertTrue(verifyWithDomainNamePattern("imap.google.com.", "*.google.com")); 236 assertTrue(verifyWithDomainNamePattern("imap2.google.com.", "*.google.com")); 237 assertFalse(verifyWithDomainNamePattern("imap.google.com.", "*.googl.com")); 238 assertFalse(verifyWithDomainNamePattern("imap2.google2.com.", "*.google3.com")); 239 assertFalse(verifyWithDomainNamePattern("imap.google.com.", "a*.google.com")); 240 assertFalse(verifyWithDomainNamePattern("imap.google.com.", "ix*.google.com")); 241 assertTrue(verifyWithDomainNamePattern("imap.google.com.", "iMap.Google.Com")); 242 assertTrue(verifyWithDomainNamePattern("weird.", "weird")); 243 assertTrue(verifyWithDomainNamePattern("weird.", "weird.")); 244 245 // Wildcards rejected for domain names consisting of fewer than two labels (excluding root). 246 assertFalse(verifyWithDomainNamePattern("weird.", "*weird")); 247 assertFalse(verifyWithDomainNamePattern("weird.", "weird*")); 248 assertFalse(verifyWithDomainNamePattern("weird.", "weird*.")); 249 assertFalse(verifyWithDomainNamePattern("weird.", "weird.*")); 250 } 251 252 public void testSubjectOnlyCert() throws Exception { 253 // subject: C=JP, CN=www.example.com 254 // subject alt names: n/a 255 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 256 + "MIIC0TCCAbmgAwIBAgIJANCQbJPPw31SMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n" 257 + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1ODE4\n" 258 + "WhgPMjA2NDEwMTUyMDU4MThaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n" 259 + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsdUJk\n" 260 + "4KxADA3vlDHxNbyC27Ozw4yiSVzPTHUct471YmdDRW3orO2P5a5hRnUGV70gjH9X\n" 261 + "MU4oeOdWYAgXB9pxfLyr6621k1+uNrmaZtzp0ECH9twcwxNJJFDZsN7o9vt7V6Ej\n" 262 + "NN9weeqDr/aeQXo07a12vyVfR6jWO8jHB0e4aemwZNoYjNvM69fivQTse2ZoRVfj\n" 263 + "eSHhjRTX6I8ry4a31Hwt+fT1QiWWNN6o7+WOtpJAhX3eg4smhSD1svi2kOT8tdUe\n" 264 + "NS4hWlmXmumU9G4tI8PBurcLNTm7PB2lUlbn/IV18WavqKE/Uy/1WgAx+a1EJNdp\n" 265 + "i07AG1PsqaONKkf1AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAJrNsuL7fZZNC8gL\n" 266 + "BdePJ7DYW2e7mXANU3bCBe2BZqmXKQxKwibZnEsqA+yMLqcSd8uxISlyHY2tw9wT\n" 267 + "4wB9KPIttfNLbwn/rk+MbOTHpvyF60d9WhJJVUkPBl8D4VuPSl+VnlA54kU9dtZN\n" 268 + "+ZYdxYbNtSsI/Flz9SCoOV79W9GhN+uYJhv6RwyIMIHeMpZpyX1xSUVx5dZlmerQ\n" 269 + "WAUvghDH3fFRt2ZdnA4OXoKkTAaM3Pv7PUMsnah8bux6MQi0AuLMWFWOI1H34koH\n" 270 + "rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk\n" 271 + "taXDWI4=\n" 272 + "-----END CERTIFICATE-----"); 273 assertTrue(verifyWithServerCertificate("www.example.com", cert)); 274 assertFalse(verifyWithServerCertificate("www2.example.com", cert)); 275 } 276 277 public void testSubjectAltOnlyCert() throws Exception { 278 // subject: C=JP (no CN) 279 // subject alt names: DNS:www.example.com 280 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 281 + "MIICvTCCAaWgAwIBAgIJALbA0TZk2YmNMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n" 282 + "BAYTAkpQMCAXDTEwMDExMjIwNTg1NFoYDzIwNjQxMDE1MjA1ODU0WjANMQswCQYD\n" 283 + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg6acVC9V4\n" 284 + "xNGoLNVLPbqBc8IvMvcsc88dF6MW3d9VagX3aeWU8c79tI/KOV/1AOakH7WYxw/w\n" 285 + "yD8aOX7+9BK1Hu0qKKKbSM+ycqaMthXd6xytrNDsIx5WiGUz8zTko0Gk3orIR7p7\n" 286 + "rPcNzB/zwtESkscqPv85aEn7S/yClNkzLfEzm3CtaYOc0tfhBMyzi/ipXzGMxUmx\n" 287 + "PvOLr3v/Oz5pZEQw7Kxlm4+tAtn7bJlHziQ1UW4WPIy+T3hySBEpODFiqZi7Ok3X\n" 288 + "Zjxdii62fgo5B2Ee7q5Amo0mUIwcQTDjJ2CLAqzYnSh3tpiPJGjEIjmRyCoMQ1bx\n" 289 + "7D+y7nSPIq8CAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0G\n" 290 + "CSqGSIb3DQEBBQUAA4IBAQBsGEh+nHc0l9FJTzWqvG3qs7i6XoJZdtThCDx4HjKJ\n" 291 + "8GMrJtreNN4JvIxn7KC+alVbnILjzCRO+c3rsnpxKBi5cp2imjuw5Kf/x2Seimb9\n" 292 + "UvZbaJvBVOzy4Q1IGef9bLy3wZzy2/WfBFyvPTAkgkRaX7LN2jnYOYVhNoNFrwqe\n" 293 + "EWxkA6fzrpyseUEFeGFFjGxRSRCDcQ25Eq6d9rkC1x21zNtt4QwZBO0wHrTy155M\n" 294 + "JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT\n" 295 + "9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj\n" 296 + "-----END CERTIFICATE-----"); 297 assertTrue(verifyWithServerCertificate("www.example.com", cert)); 298 assertFalse(verifyWithServerCertificate("www2.example.com", cert)); 299 } 300 301 public void testSubjectWithAltNamesCert() throws Exception { 302 // subject: C=JP, CN=www.example.com 303 // subject alt names: DNS:www2.example.com, DNS:www3.example.com 304 // * Subject should be ignored, because it has subject alt names. 305 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 306 + "MIIDBDCCAeygAwIBAgIJALv14qjcuhw9MA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n" 307 + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1OTM4\n" 308 + "WhgPMjA2NDEwMTUyMDU5MzhaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n" 309 + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiTVgU\n" 310 + "kBO9KNYZZLmiPR0eBrk8u61CLnm35BGKW8EFpDaINLbbIFIQvqOMekURON/N+xFY\n" 311 + "D8roo7aFZVuHWAUqFcOJ4e6NmviK5qocLihtzAexsw4f4AzZxM3A8kcLlWLyAt7e\n" 312 + "EVLxhcMHogY7GaF6q+33Z8p+zp6x3tj07mwyPrriCLse2PeRsRunZl/fp/VvRlr6\n" 313 + "YbC7CbRrhnIv5nqohs8BsbBiiFpxQftsMQmiXhY2LUzqY2RXUIOw24fHjoQkHTL2\n" 314 + "4z5nUM3b6ueQe+CBnobUS6fzK/36Nct4dRpev9i/ORdRLuIDKJ+QR16G1V/BJYBR\n" 315 + "dAK+3iXvg6z8vP1XAgMBAAGjMTAvMC0GA1UdEQQmMCSCEHd3dzIuZXhhbXBsZS5j\n" 316 + "b22CEHd3dzMuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAJQNf38uXm3h\n" 317 + "0vsF+Yd6/HqM48Su7tWnTDAfTXnQZZkzjzITq3JXzquMXICktAVN2cLnT9zPfRAE\n" 318 + "8V8A3BNO5zXiR5W3o/mJP5HQ3/WxpzBGM2N+YmDCJyBoQrIVaAZaXAZUaBBvn5A+\n" 319 + "kEVfGWquwIFuvA67xegbJOCRLD4eUzRdNsn5+NFiakWO1tkFqEzqyQ0PNPviRjgu\n" 320 + "z9NxdPvd1JQOhydkucsPKJzlEBbGyL5QL/Jkot3Qy+FOeuNzgQUfAGtQgzRrsZDK\n" 321 + "hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI\n" 322 + "h5G2eVGXH/Y=\n" 323 + "-----END CERTIFICATE-----"); 324 assertFalse(verifyWithServerCertificate("www.example.com", cert)); 325 assertTrue(verifyWithServerCertificate("www2.example.com", cert)); 326 assertTrue(verifyWithServerCertificate("www3.example.com", cert)); 327 assertFalse(verifyWithServerCertificate("www4.example.com", cert)); 328 } 329 330 public void testSubjectWithWildAltNamesCert() throws Exception { 331 // subject: C=JP, CN=www.example.com 332 // subject alt names: DNS:*.example2.com 333 // * Subject should be ignored, because it has subject alt names. 334 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 335 + "MIIC8DCCAdigAwIBAgIJAL/oWJ64VAdXMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV\n" 336 + "BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjEwMDAx\n" 337 + "WhgPMjA2NDEwMTUyMTAwMDFaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu\n" 338 + "ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbx1QB\n" 339 + "92iea7VybLYICA4MX4LWipYrRsgXUXQrcIQ3YLTQ9rH0VwScrHL4O4JDxgXCQnR+\n" 340 + "4VOzD42q1KXHJAqzqGUYCNPyvZEzkGCnQ4FBIUEmxZd5SNEefJVH3Z6GizYJomTh\n" 341 + "p78yDcoqymD9umxRC2cWFu8GscfFGMVyhsqLlOofu7UWOs22mkXPo43jDx+VOAoV\n" 342 + "n48YP3P57a2Eo0gcd4zVL00y62VegqBO/1LW38aTS7teiCBFc1TkNYa5I40yN9lP\n" 343 + "rB9ICHYQWyzf/7OxU9iauEK2w6DmSsQoLs9JzEhgeNZddkcc77ciSUCo2Hx0VpOJ\n" 344 + "BFyf2rbryJeAk+FDAgMBAAGjHTAbMBkGA1UdEQQSMBCCDiouZXhhbXBsZTIuY29t\n" 345 + "MA0GCSqGSIb3DQEBBQUAA4IBAQA2a14pRL+4laJ8sscQlucaDB/oSdb0cwhk4IkE\n" 346 + "kKl/ZKr6rKwPZ81sJRgzvI4imLbUAKt4AJHdpI9cIQUq1gw9bzil7LKwmFtFSPmC\n" 347 + "MYb1iadaYrvp7RE4yXrWCcSbU0hup9JQLHTrHLlqLtRuU48NHMvWYThBcS9Q/hQp\n" 348 + "nJ/JxYy3am99MHALWLAfuRxQXhE4C5utDmBwI2KD6A8SA30s+CnuegmkYScuSqBu\n" 349 + "Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT\n" 350 + "+ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ\n" 351 + "-----END CERTIFICATE-----"); 352 assertFalse(verifyWithServerCertificate("www.example.com", cert)); 353 assertFalse(verifyWithServerCertificate("www2.example.com", cert)); 354 assertTrue(verifyWithServerCertificate("www.example2.com", cert)); 355 assertTrue(verifyWithServerCertificate("abc.example2.com", cert)); 356 assertFalse(verifyWithServerCertificate("www.example3.com", cert)); 357 } 358 359 public void testWildAltNameOnlyCert() throws Exception { 360 // subject: C=JP 361 // subject alt names: DNS:*.example.com 362 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 363 + "MIICuzCCAaOgAwIBAgIJAP82tgcvmAGxMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n" 364 + "BAYTAkpQMCAXDTEwMDExMjIxMDAyN1oYDzIwNjQxMDE1MjEwMDI3WjANMQswCQYD\n" 365 + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs528EQbcB1\n" 366 + "x4BwxthQBZrgDJzoO7KPV3dhGYoeP8EnRjapZm+T/sj9P/O4HvfxjnB+fsjYSdmE\n" 367 + "WWUtnFrP7wtG9DUC748Ea2PMV8WFhOG58dqBNIko5XzkHB7SxkNZD5S/0KQYMGLr\n" 368 + "rchDsDlmsEf2Qb6qiqpNEU70aSkExZJcH+B9nWdeBpsVFu7wtezwSWEc2NUa2bhW\n" 369 + "gcXQ/aafwHZ4o2PyGwy0sgS/UifqO9tEllC2tPleSNJOmYsVudv5Bz4Q0GG38BSz\n" 370 + "Pc0IcOoln0ZWpXbGr03V2vlXWCwzaFAl3I1T3O7YVqDiaSWoP+d0tHZzmw8aJLXd\n" 371 + "B+KaUUGxRPsCAwEAAaMcMBowGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTANBgkq\n" 372 + "hkiG9w0BAQUFAAOCAQEAJbVan4QgJ0cvpJnK9UWIVJNC+UbP87RC5go2fQiTnmGv\n" 373 + "prOrIuMqz1+vGcpIheLTLctJRHPoadXq0+UbQEIaU3pQbY6C4nNdfl+hcvmJeqrt\n" 374 + "kOCcvmIamO68iNvTSeszuHuu4O38PefrW2Xd0nn7bjFZrzBzHFhTudmnqNliP3ue\n" 375 + "KKQpqkUt5lCytnH8V/u/UCWdvVx5LnUa2XFGVLi3ongBIojW5fvF+yxn9ADqxdrI\n" 376 + "va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU\n" 377 + "qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ==\n" 378 + "-----END CERTIFICATE-----"); 379 assertTrue(verifyWithServerCertificate("www.example.com", cert)); 380 assertTrue(verifyWithServerCertificate("www2.example.com", cert)); 381 assertFalse(verifyWithServerCertificate("www.example2.com", cert)); 382 } 383 384 public void testAltIpOnlyCert() throws Exception { 385 // subject: C=JP 386 // subject alt names: IP Address:192.168.10.1 387 X509Certificate cert = parseCertificate("-----BEGIN CERTIFICATE-----\n" 388 + "MIICsjCCAZqgAwIBAgIJALrC37YAXFIeMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV\n" 389 + "BAYTAkpQMCAXDTEwMDExMjIxMzk0NloYDzIwNjQxMDE1MjEzOTQ2WjANMQswCQYD\n" 390 + "VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr8s/4Abpby\n" 391 + "IYks5YCJE2nbWH7kj6XbwnRzsVP9RVC33bPoQ1M+2ZY24HqkigjQS/HEXR0s0bYh\n" 392 + "dewNUnTj1uGyGs6cYzsbu7x114vmVYqjxUo3hKjwfYiPeF6f3IE1vpLI7I2G32gq\n" 393 + "Zwm9c1/vXNHIdWQxCpFcuPA8P3YGfoApFX4pQPFplBUNAQqnjdmA68cbxxMC+1F3\n" 394 + "mX42D7iIEVwyVpah5HjyxjIZQlf3X7QBj0bCmkL+ibIHTALrkNNwNM6i4xzYLz/5\n" 395 + "14GkN9ncHY87eSOk6r53ptER6mQMhCe9qPRjSHnpWTTyj6IXTaYe+dDQw657B80w\n" 396 + "cSHL7Ed25zUCAwEAAaMTMBEwDwYDVR0RBAgwBocEwKgKATANBgkqhkiG9w0BAQUF\n" 397 + "AAOCAQEAgrwrtOWZT3fbi1AafpGaAiOBWSJqYqRhtQy0AfiZBxv1U0XaYqmZmpnq\n" 398 + "DVAqr0NkljowD28NBrxIFO5gBNum2ZOPDl2/5vjFn+IirUCJ9u9wS7zYkTCW2lQR\n" 399 + "xE7Ic3mfWv7wUbKDfjlWqP1IDHUxwkrBTAl+HnwOPiaKKk1ttwcrgS8AHlqASe03\n" 400 + "mlwnvJ+Stk54IneRaegL0L93sNAy63RZqnPCTxGz7eHcFwX8Jdr4sbxTxQqV6pIc\n" 401 + "WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik\n" 402 + "sAyifp8agkYdzaSh55fFmKXlFnRsQw==\n" 403 + "-----END CERTIFICATE-----"); 404 assertTrue(verifyWithServerCertificate("192.168.10.1", cert)); 405 assertFalse(verifyWithServerCertificate("192.168.10.2", cert)); 406 } 407 408 /** 409 * Verifies the provided hostname against the provided domain name pattern from server 410 * certificate. 411 */ 412 private boolean verifyWithDomainNamePattern(String hostname, String pattern) { 413 StubSSLSession session = new StubSSLSession(); 414 415 // Verify using a certificate where the pattern is in the CN 416 session.peerCertificates = new Certificate[] { 417 new StubX509Certificate("cn=\"" + pattern + "\"") 418 }; 419 boolean resultWhenPatternInCn = verifier.verify(hostname, session); 420 421 // Verify using a certificate where the pattern is in a DNS SubjectAltName 422 session.peerCertificates = new Certificate[] { 423 new StubX509Certificate("ou=test") 424 .addSubjectAlternativeName(ALT_DNS_NAME, pattern) 425 }; 426 boolean resultWhenPatternInSubjectAltName = verifier.verify(hostname, session); 427 428 // Assert that in both cases the verifier gives the same result 429 if (resultWhenPatternInCn != resultWhenPatternInSubjectAltName) { 430 fail("Different results between pattern in CN and SubjectAltName." 431 + " hostname : " + hostname + ", pattern: " + pattern 432 + ", when pattern in CN: " + resultWhenPatternInCn 433 + ", when pattern in SubjectAltName: " + resultWhenPatternInSubjectAltName); 434 } 435 return resultWhenPatternInCn; 436 } 437 438 /** 439 * Verifies the provided hostname against the provided server certificate. 440 */ 441 private boolean verifyWithServerCertificate(String hostname, X509Certificate certificate) { 442 StubSSLSession session = new StubSSLSession(); 443 session.peerCertificates = 444 (certificate != null) ? new Certificate[] {certificate} : new Certificate[0]; 445 return verifier.verify(hostname, session); 446 } 447 448 X509Certificate parseCertificate(String encoded) throws Exception { 449 InputStream in = new ByteArrayInputStream(encoded.getBytes(StandardCharsets.US_ASCII)); 450 return (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(in); 451 } 452 453 private static class StubSSLSession implements SSLSession { 454 455 public Certificate[] peerCertificates = new Certificate[0]; 456 457 @Override 458 public int getApplicationBufferSize() { 459 throw new UnsupportedOperationException(); 460 } 461 462 @Override 463 public String getCipherSuite() { 464 throw new UnsupportedOperationException(); 465 } 466 467 @Override 468 public long getCreationTime() { 469 throw new UnsupportedOperationException(); 470 } 471 472 @Override 473 public byte[] getId() { 474 throw new UnsupportedOperationException(); 475 } 476 477 @Override 478 public long getLastAccessedTime() { 479 throw new UnsupportedOperationException(); 480 } 481 482 @Override 483 public Certificate[] getLocalCertificates() { 484 throw new UnsupportedOperationException(); 485 } 486 487 @Override 488 public Principal getLocalPrincipal() { 489 throw new UnsupportedOperationException(); 490 } 491 492 @Override 493 public int getPacketBufferSize() { 494 throw new UnsupportedOperationException(); 495 } 496 497 @Override 498 public javax.security.cert.X509Certificate[] getPeerCertificateChain() 499 throws SSLPeerUnverifiedException { 500 throw new UnsupportedOperationException(); 501 } 502 503 @Override 504 public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { 505 return peerCertificates; 506 } 507 508 @Override 509 public String getPeerHost() { 510 throw new UnsupportedOperationException(); 511 } 512 513 @Override 514 public int getPeerPort() { 515 throw new UnsupportedOperationException(); 516 } 517 518 @Override 519 public Principal getPeerPrincipal() throws SSLPeerUnverifiedException { 520 throw new UnsupportedOperationException(); 521 } 522 523 @Override 524 public String getProtocol() { 525 throw new UnsupportedOperationException(); 526 } 527 528 @Override 529 public SSLSessionContext getSessionContext() { 530 throw new UnsupportedOperationException(); 531 } 532 533 @Override 534 public Object getValue(String name) { 535 throw new UnsupportedOperationException(); 536 } 537 538 @Override 539 public String[] getValueNames() { 540 throw new UnsupportedOperationException(); 541 } 542 543 @Override 544 public void invalidate() { 545 throw new UnsupportedOperationException(); 546 } 547 548 @Override 549 public boolean isValid() { 550 return true; 551 } 552 553 @Override 554 public void putValue(String name, Object value) { 555 throw new UnsupportedOperationException(); 556 } 557 558 @Override 559 public void removeValue(String name) { 560 throw new UnsupportedOperationException(); 561 } 562 } 563 564 private static class StubX509Certificate extends X509Certificate { 565 private final X500Principal subjectX500Principal; 566 private Collection<List<?>> subjectAlternativeNames; 567 568 public StubX509Certificate(String subjectDn) { 569 subjectX500Principal = new X500Principal(subjectDn); 570 subjectAlternativeNames = null; 571 } 572 573 public StubX509Certificate addSubjectAlternativeName(int type, String name) { 574 if (subjectAlternativeNames == null) { 575 subjectAlternativeNames = new ArrayList<List<?>>(); 576 } 577 LinkedList<Object> entry = new LinkedList<Object>(); 578 entry.add(type); 579 entry.add(name); 580 subjectAlternativeNames.add(entry); 581 return this; 582 } 583 584 @Override public Collection<List<?>> getSubjectAlternativeNames() { 585 return subjectAlternativeNames; 586 } 587 588 @Override public X500Principal getSubjectX500Principal() { 589 return subjectX500Principal; 590 } 591 592 @Override public void checkValidity() { 593 throw new UnsupportedOperationException(); 594 } 595 596 @Override public void checkValidity(Date date) { 597 throw new UnsupportedOperationException(); 598 } 599 600 @Override public int getBasicConstraints() { 601 throw new UnsupportedOperationException(); 602 } 603 604 @Override public Principal getIssuerDN() { 605 throw new UnsupportedOperationException(); 606 } 607 608 @Override public boolean[] getIssuerUniqueID() { 609 throw new UnsupportedOperationException(); 610 } 611 612 @Override public boolean[] getKeyUsage() { 613 throw new UnsupportedOperationException(); 614 } 615 616 @Override public Date getNotAfter() { 617 throw new UnsupportedOperationException(); 618 } 619 620 @Override public Date getNotBefore() { 621 throw new UnsupportedOperationException(); 622 } 623 624 @Override public BigInteger getSerialNumber() { 625 throw new UnsupportedOperationException(); 626 } 627 628 @Override public String getSigAlgName() { 629 throw new UnsupportedOperationException(); 630 } 631 632 @Override public String getSigAlgOID() { 633 throw new UnsupportedOperationException(); 634 } 635 636 @Override public byte[] getSigAlgParams() { 637 throw new UnsupportedOperationException(); 638 } 639 640 @Override public byte[] getSignature() { 641 throw new UnsupportedOperationException(); 642 } 643 644 @Override public Principal getSubjectDN() { 645 throw new UnsupportedOperationException(); 646 } 647 648 @Override public boolean[] getSubjectUniqueID() { 649 throw new UnsupportedOperationException(); 650 } 651 652 @Override public byte[] getTBSCertificate() { 653 throw new UnsupportedOperationException(); 654 } 655 656 @Override public int getVersion() { 657 throw new UnsupportedOperationException(); 658 } 659 660 @Override public byte[] getEncoded() { 661 throw new UnsupportedOperationException(); 662 } 663 664 @Override public PublicKey getPublicKey() { 665 throw new UnsupportedOperationException(); 666 } 667 668 @Override public String toString() { 669 throw new UnsupportedOperationException(); 670 } 671 672 @Override public void verify(PublicKey key) { 673 throw new UnsupportedOperationException(); 674 } 675 676 @Override public void verify(PublicKey key, String sigProvider) { 677 throw new UnsupportedOperationException(); 678 } 679 680 @Override public Set<String> getCriticalExtensionOIDs() { 681 throw new UnsupportedOperationException(); 682 } 683 684 @Override public byte[] getExtensionValue(String oid) { 685 throw new UnsupportedOperationException(); 686 } 687 688 @Override public Set<String> getNonCriticalExtensionOIDs() { 689 throw new UnsupportedOperationException(); 690 } 691 692 @Override public boolean hasUnsupportedCriticalExtension() { 693 throw new UnsupportedOperationException(); 694 } 695 } 696} 697