Home | History | Annotate | Download | only in ssl
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements. See the NOTICE file distributed with this
      4  * work for additional information regarding copyright ownership. The ASF
      5  * licenses this file to You under the Apache License, Version 2.0 (the
      6  * "License"); you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  * http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     14  * License for the specific language governing permissions and limitations under
     15  * the License.
     16  */
     17 
     18 package tests.api.javax.net.ssl;
     19 
     20 import java.io.ByteArrayInputStream;
     21 import java.io.InputStream;
     22 import java.security.cert.CertificateFactory;
     23 import java.security.cert.X509Certificate;
     24 import javax.net.ssl.HostnameVerifier;
     25 import javax.net.ssl.HttpsURLConnection;
     26 import javax.security.auth.x500.X500Principal;
     27 import junit.framework.TestCase;
     28 import org.apache.harmony.xnet.tests.support.mySSLSession;
     29 
     30 public class HostnameVerifierTest extends TestCase implements
     31         CertificatesToPlayWith {
     32 
     33     /**
     34      * javax.net.ssl.HostnameVerifier#verify(String hostname, SSLSession
     35      *        session)
     36      */
     37     public final void test_verify() throws Exception {
     38         mySSLSession session = new mySSLSession("localhost", 1080, null);
     39         HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
     40         assertFalse(hv.verify("localhost", session));
     41     }
     42 
     43     // copied and modified from apache http client test suite.
     44     public void testVerify() throws Exception {
     45         CertificateFactory cf = CertificateFactory.getInstance("X.509");
     46         InputStream in;
     47         X509Certificate x509;
     48         in = new ByteArrayInputStream(X509_FOO);
     49         x509 = (X509Certificate) cf.generateCertificate(in);
     50         mySSLSession session = new mySSLSession(new X509Certificate[] {x509});
     51 
     52         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
     53         assertTrue(verifier.verify("foo.com", session));
     54         assertFalse(verifier.verify("a.foo.com", session));
     55         assertFalse(verifier.verify("bar.com", session));
     56 
     57         in = new ByteArrayInputStream(X509_HANAKO);
     58         x509 = (X509Certificate) cf.generateCertificate(in);
     59         session = new mySSLSession(new X509Certificate[] {x509});
     60         assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
     61         assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
     62 
     63         in = new ByteArrayInputStream(X509_FOO_BAR);
     64         x509 = (X509Certificate) cf.generateCertificate(in);
     65         session = new mySSLSession(new X509Certificate[] {x509});
     66         assertFalse(verifier.verify("foo.com", session));
     67         assertFalse(verifier.verify("a.foo.com", session));
     68         assertTrue(verifier.verify("bar.com", session));
     69         assertFalse(verifier.verify("a.bar.com", session));
     70 
     71         in = new ByteArrayInputStream(X509_FOO_BAR_HANAKO);
     72         x509 = (X509Certificate) cf.generateCertificate(in);
     73         session = new mySSLSession(new X509Certificate[] {x509});
     74         assertTrue(verifier.verify("foo.com", session));
     75         assertFalse(verifier.verify("a.foo.com", session));
     76         // these checks test alternative subjects. The test data contains an
     77         // alternative subject starting with a japanese kanji character. This is
     78         // not supported by Android because the underlying implementation from
     79         // harmony follows the definition from rfc 1034 page 10 for alternative
     80         // subject names. This causes the code to drop all alternative subjects.
     81         // assertTrue(verifier.verify("bar.com", session));
     82         // assertFalse(verifier.verify("a.bar.com", session));
     83         // assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
     84 
     85         in = new ByteArrayInputStream(X509_NO_CNS_FOO);
     86         x509 = (X509Certificate) cf.generateCertificate(in);
     87         session = new mySSLSession(new X509Certificate[] {x509});
     88         assertTrue(verifier.verify("foo.com", session));
     89         assertFalse(verifier.verify("a.foo.com", session));
     90 
     91         in = new ByteArrayInputStream(X509_NO_CNS_FOO);
     92         x509 = (X509Certificate) cf.generateCertificate(in);
     93         session = new mySSLSession(new X509Certificate[] {x509});
     94         assertTrue(verifier.verify("foo.com", session));
     95         assertFalse(verifier.verify("a.foo.com", session));
     96 
     97         in = new ByteArrayInputStream(X509_THREE_CNS_FOO_BAR_HANAKO);
     98         x509 = (X509Certificate) cf.generateCertificate(in);
     99         session = new mySSLSession(new X509Certificate[] {x509});
    100         assertFalse(verifier.verify("foo.com", session));
    101         assertFalse(verifier.verify("a.foo.com", session));
    102         assertFalse(verifier.verify("bar.com", session));
    103         assertFalse(verifier.verify("a.bar.com", session));
    104         assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
    105         assertFalse(verifier.verify("a.\u82b1\u5b50.co.jp", session));
    106 
    107         in = new ByteArrayInputStream(X509_WILD_FOO);
    108         x509 = (X509Certificate) cf.generateCertificate(in);
    109         session = new mySSLSession(new X509Certificate[] {x509});
    110         assertTrue(verifier.verify("foo.com", session));
    111         assertTrue(verifier.verify("www.foo.com", session));
    112         assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
    113         assertFalse(verifier.verify("a.b.foo.com", session));
    114 
    115         in = new ByteArrayInputStream(X509_WILD_CO_JP);
    116         x509 = (X509Certificate) cf.generateCertificate(in);
    117         session = new mySSLSession(new X509Certificate[] {x509});
    118         assertTrue(verifier.verify("foo.co.jp", session));
    119         assertTrue(verifier.verify("\u82b1\u5b50.co.jp", session));
    120 
    121         in = new ByteArrayInputStream(X509_WILD_FOO_BAR_HANAKO);
    122         x509 = (X509Certificate) cf.generateCertificate(in);
    123         session = new mySSLSession(new X509Certificate[] {x509});
    124         // try the foo.com variations
    125         assertTrue(verifier.verify("foo.com", session));
    126         assertTrue(verifier.verify("www.foo.com", session));
    127         assertTrue(verifier.verify("\u82b1\u5b50.foo.com", session));
    128         assertFalse(verifier.verify("a.b.foo.com", session));
    129         // these checks test alternative subjects. The test data contains an
    130         // alternative subject starting with a japanese kanji character. This is
    131         // not supported by Android because the underlying implementation from
    132         // harmony follows the definition from rfc 1034 page 10 for alternative
    133         // subject names. This causes the code to drop all alternative subjects.
    134         // assertFalse(verifier.verify("bar.com", session));
    135         // assertTrue(verifier.verify("www.bar.com", session));
    136         // assertTrue(verifier.verify("\u82b1\u5b50.bar.com", session));
    137         // assertTrue(verifier.verify("a.b.bar.com", session));
    138     }
    139 
    140     public void testSubjectAlt() throws Exception {
    141         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    142         InputStream in = new ByteArrayInputStream(X509_MULTIPLE_SUBJECT_ALT);
    143         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    144         mySSLSession session = new mySSLSession(new X509Certificate[] {x509});
    145 
    146         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    147         assertEquals(new X500Principal("CN=localhost"), x509.getSubjectX500Principal());
    148 
    149         assertTrue(verifier.verify("localhost", session));
    150         assertTrue(verifier.verify("localhost.localdomain", session));
    151         assertFalse(verifier.verify("local.host", session));
    152     }
    153 
    154     public void testVerifyIpAddress() throws Exception {
    155         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    156         InputStream in = new ByteArrayInputStream(X509_MULTIPLE_SUBJECT_ALT);
    157         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    158         mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
    159         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    160 
    161         assertTrue(verifier.verify("127.0.0.1", session));
    162         assertFalse(verifier.verify("127.0.0.2", session));
    163     }
    164 
    165     public void testWildcardsCannotMatchIpAddresses() throws Exception {
    166         // openssl req -x509 -nodes -days 36500 -subj '/CN=*.0.0.1' -newkey rsa:512 -out cert.pem
    167         String cert = "-----BEGIN CERTIFICATE-----\n"
    168                 + "MIIBkjCCATygAwIBAgIJAMdemqOwd/BEMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV\n"
    169                 + "BAMUByouMC4wLjEwIBcNMTAxMjIwMTY0NDI1WhgPMjExMDExMjYxNjQ0MjVaMBIx\n"
    170                 + "EDAOBgNVBAMUByouMC4wLjEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAqY8c9Qrt\n"
    171                 + "YPWCvb7lclI+aDHM6fgbJcHsS9Zg8nUOh5dWrS7AgeA25wyaokFl4plBbbHQe2j+\n"
    172                 + "cCjsRiJIcQo9HwIDAQABo3MwcTAdBgNVHQ4EFgQUJ436TZPJvwCBKklZZqIvt1Yt\n"
    173                 + "JjEwQgYDVR0jBDswOYAUJ436TZPJvwCBKklZZqIvt1YtJjGhFqQUMBIxEDAOBgNV\n"
    174                 + "BAMUByouMC4wLjGCCQDHXpqjsHfwRDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB\n"
    175                 + "BQUAA0EAk9i88xdjWoewqvE+iMC9tD2obMchgFDaHH0ogxxiRaIKeEly3g0uGxIt\n"
    176                 + "fl2WRY8hb4x+zRrwsFaLEpdEvqcjOQ==\n"
    177                 + "-----END CERTIFICATE-----";
    178         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    179         InputStream in = new ByteArrayInputStream(cert.getBytes("UTF-8"));
    180         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    181         mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
    182         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    183 
    184         assertFalse(verifier.verify("127.0.0.1", session));
    185     }
    186 
    187     /**
    188      * Earlier implementations of Android's hostname verifier required that
    189      * wildcard names wouldn't match "*.com" or similar. This was a nonstandard
    190      * check that we've since dropped. It is the CA's responsibility to not hand
    191      * out certificates that match so broadly.
    192      */
    193     public void testWildcardsDoesNotNeedTwoDots() throws Exception {
    194         // openssl req -x509 -nodes -days 36500 -subj '/CN=*.com' -newkey rsa:512 -out cert.pem
    195         String cert = "-----BEGIN CERTIFICATE-----\n"
    196                 + "MIIBjDCCATagAwIBAgIJAOVulXCSu6HuMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNV\n"
    197                 + "BAMUBSouY29tMCAXDTEwMTIyMDE2NDkzOFoYDzIxMTAxMTI2MTY0OTM4WjAQMQ4w\n"
    198                 + "DAYDVQQDFAUqLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDJd8xqni+h7Iaz\n"
    199                 + "ypItivs9kPuiJUqVz+SuJ1C05SFc3PmlRCvwSIfhyD67fHcbMdl+A/LrIjhhKZJe\n"
    200                 + "1joO0+pFAgMBAAGjcTBvMB0GA1UdDgQWBBS4Iuzf5w8JdCp+EtBfdFNudf6+YzBA\n"
    201                 + "BgNVHSMEOTA3gBS4Iuzf5w8JdCp+EtBfdFNudf6+Y6EUpBIwEDEOMAwGA1UEAxQF\n"
    202                 + "Ki5jb22CCQDlbpVwkruh7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA0EA\n"
    203                 + "U6LFxmZr31lFyis2/T68PpjAppc0DpNQuA2m/Y7oTHBDi55Fw6HVHCw3lucuWZ5d\n"
    204                 + "qUYo4ES548JdpQtcLrW2sA==\n"
    205                 + "-----END CERTIFICATE-----";
    206         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    207         InputStream in = new ByteArrayInputStream(cert.getBytes("UTF-8"));
    208         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    209         mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
    210         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    211 
    212         assertTrue(verifier.verify("google.com", session));
    213     }
    214 
    215     public void testSubjectAltName() throws Exception {
    216         /*
    217          * $ cat ./cert.cnf
    218          * [req]
    219          * distinguished_name=distinguished_name
    220          * req_extensions=req_extensions
    221          * x509_extensions=x509_extensions
    222          * [distinguished_name]
    223          * [req_extensions]
    224          * [x509_extensions]
    225          * subjectAltName=DNS:bar.com,DNS:baz.com
    226          *
    227          * $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \
    228          *     -newkey rsa:512 -out cert.pem
    229          */
    230         String cert = "-----BEGIN CERTIFICATE-----\n"
    231                 + "MIIBPTCB6KADAgECAgkA7zoHaaqNGHQwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE\n"
    232                 + "AxMHZm9vLmNvbTAgFw0xMDEyMjAxODM5MzZaGA8yMTEwMTEyNjE4MzkzNlowEjEQ\n"
    233                 + "MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC+gmoSxF+8\n"
    234                 + "hbV+rgRQqHIJd50216OWQJbU3BvdlPbca779NYO4+UZWTFdBM8BdQqs3H4B5Agvp\n"
    235                 + "y7HeSff1F7XRAgMBAAGjHzAdMBsGA1UdEQQUMBKCB2Jhci5jb22CB2Jhei5jb20w\n"
    236                 + "DQYJKoZIhvcNAQEFBQADQQBXpZZPOY2Dy1lGG81JTr8L4or9jpKacD7n51eS8iqI\n"
    237                 + "oTznPNuXHU5bFN0AAGX2ij47f/EahqTpo5RdS95P4sVm\n"
    238                 + "-----END CERTIFICATE-----";
    239         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    240         InputStream in = new ByteArrayInputStream(cert.getBytes("UTF-8"));
    241         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    242         mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
    243         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    244 
    245         assertFalse(verifier.verify("foo.com", session));
    246         assertTrue(verifier.verify("bar.com", session));
    247         assertTrue(verifier.verify("baz.com", session));
    248         assertFalse(verifier.verify("a.foo.com", session));
    249         assertFalse(verifier.verify("quux.com", session));
    250     }
    251 
    252     public void testSubjectAltNameWithWildcard() throws Exception {
    253         /*
    254          * $ cat ./cert.cnf
    255          * [req]
    256          * distinguished_name=distinguished_name
    257          * req_extensions=req_extensions
    258          * x509_extensions=x509_extensions
    259          * [distinguished_name]
    260          * [req_extensions]
    261          * [x509_extensions]
    262          * subjectAltName=DNS:bar.com,DNS:*.baz.com
    263          *
    264          * $ openssl req -x509 -nodes -days 36500 -subj '/CN=foo.com' -config ./cert.cnf \
    265          *     -newkey rsa:512 -out cert.pem
    266          */
    267         String cert = "-----BEGIN CERTIFICATE-----\n"
    268                 + "MIIBPzCB6qADAgECAgkAnv/7Jv5r7pMwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UE\n"
    269                 + "AxMHZm9vLmNvbTAgFw0xMDEyMjAxODQ2MDFaGA8yMTEwMTEyNjE4NDYwMVowEjEQ\n"
    270                 + "MA4GA1UEAxMHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDAz2YXnyog\n"
    271                 + "YdYLSFr/OEgSumtwqtZKJTB4wqTW/eKbBCEzxnyUMxWZIqUGu353PzwfOuWp2re3\n"
    272                 + "nvVV+QDYQlh9AgMBAAGjITAfMB0GA1UdEQQWMBSCB2Jhci5jb22CCSouYmF6LmNv\n"
    273                 + "bTANBgkqhkiG9w0BAQUFAANBAB8yrSl8zqy07i0SNYx2B/FnvQY734pxioaqFWfO\n"
    274                 + "Bqo1ZZl/9aPHEWIwBrxYNVB0SGu/kkbt/vxqOjzzrkXukmI=\n"
    275                 + "-----END CERTIFICATE-----";
    276         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    277         InputStream in = new ByteArrayInputStream(cert.getBytes("UTF-8"));
    278         X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
    279         mySSLSession session = new mySSLSession(new X509Certificate[] { x509 });
    280         HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
    281 
    282         assertFalse(verifier.verify("foo.com", session));
    283         assertTrue(verifier.verify("bar.com", session));
    284         assertTrue(verifier.verify("a.baz.com", session));
    285         assertTrue(verifier.verify("baz.com", session));
    286         assertFalse(verifier.verify("a.foo.com", session));
    287         assertFalse(verifier.verify("a.bar.com", session));
    288         assertFalse(verifier.verify("quux.com", session));
    289     }
    290 }
    291