diff options
Diffstat (limited to 'tests/AndroidTests')
9 files changed, 718 insertions, 0 deletions
diff --git a/tests/AndroidTests/res/raw/alt_ip_only.crt b/tests/AndroidTests/res/raw/alt_ip_only.crt new file mode 100644 index 0000000..3ac9f5a --- /dev/null +++ b/tests/AndroidTests/res/raw/alt_ip_only.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICsjCCAZqgAwIBAgIJALrC37YAXFIeMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV +BAYTAkpQMCAXDTEwMDExMjIxMzk0NloYDzIwNjQxMDE1MjEzOTQ2WjANMQswCQYD +VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr8s/4Abpby +IYks5YCJE2nbWH7kj6XbwnRzsVP9RVC33bPoQ1M+2ZY24HqkigjQS/HEXR0s0bYh +dewNUnTj1uGyGs6cYzsbu7x114vmVYqjxUo3hKjwfYiPeF6f3IE1vpLI7I2G32gq +Zwm9c1/vXNHIdWQxCpFcuPA8P3YGfoApFX4pQPFplBUNAQqnjdmA68cbxxMC+1F3 +mX42D7iIEVwyVpah5HjyxjIZQlf3X7QBj0bCmkL+ibIHTALrkNNwNM6i4xzYLz/5 +14GkN9ncHY87eSOk6r53ptER6mQMhCe9qPRjSHnpWTTyj6IXTaYe+dDQw657B80w +cSHL7Ed25zUCAwEAAaMTMBEwDwYDVR0RBAgwBocEwKgKATANBgkqhkiG9w0BAQUF +AAOCAQEAgrwrtOWZT3fbi1AafpGaAiOBWSJqYqRhtQy0AfiZBxv1U0XaYqmZmpnq +DVAqr0NkljowD28NBrxIFO5gBNum2ZOPDl2/5vjFn+IirUCJ9u9wS7zYkTCW2lQR +xE7Ic3mfWv7wUbKDfjlWqP1IDHUxwkrBTAl+HnwOPiaKKk1ttwcrgS8AHlqASe03 +mlwnvJ+Stk54IneRaegL0L93sNAy63RZqnPCTxGz7eHcFwX8Jdr4sbxTxQqV6pIc +WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik +sAyifp8agkYdzaSh55fFmKXlFnRsQw== +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/res/raw/subject_alt_only.crt b/tests/AndroidTests/res/raw/subject_alt_only.crt new file mode 100644 index 0000000..d5808fb --- /dev/null +++ b/tests/AndroidTests/res/raw/subject_alt_only.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICvTCCAaWgAwIBAgIJALbA0TZk2YmNMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV +BAYTAkpQMCAXDTEwMDExMjIwNTg1NFoYDzIwNjQxMDE1MjA1ODU0WjANMQswCQYD +VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg6acVC9V4 +xNGoLNVLPbqBc8IvMvcsc88dF6MW3d9VagX3aeWU8c79tI/KOV/1AOakH7WYxw/w +yD8aOX7+9BK1Hu0qKKKbSM+ycqaMthXd6xytrNDsIx5WiGUz8zTko0Gk3orIR7p7 +rPcNzB/zwtESkscqPv85aEn7S/yClNkzLfEzm3CtaYOc0tfhBMyzi/ipXzGMxUmx +PvOLr3v/Oz5pZEQw7Kxlm4+tAtn7bJlHziQ1UW4WPIy+T3hySBEpODFiqZi7Ok3X +Zjxdii62fgo5B2Ee7q5Amo0mUIwcQTDjJ2CLAqzYnSh3tpiPJGjEIjmRyCoMQ1bx +7D+y7nSPIq8CAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0G +CSqGSIb3DQEBBQUAA4IBAQBsGEh+nHc0l9FJTzWqvG3qs7i6XoJZdtThCDx4HjKJ +8GMrJtreNN4JvIxn7KC+alVbnILjzCRO+c3rsnpxKBi5cp2imjuw5Kf/x2Seimb9 +UvZbaJvBVOzy4Q1IGef9bLy3wZzy2/WfBFyvPTAkgkRaX7LN2jnYOYVhNoNFrwqe +EWxkA6fzrpyseUEFeGFFjGxRSRCDcQ25Eq6d9rkC1x21zNtt4QwZBO0wHrTy155M +JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT +9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/res/raw/subject_only.crt b/tests/AndroidTests/res/raw/subject_only.crt new file mode 100644 index 0000000..11b34e7 --- /dev/null +++ b/tests/AndroidTests/res/raw/subject_only.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC0TCCAbmgAwIBAgIJANCQbJPPw31SMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV +BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1ODE4 +WhgPMjA2NDEwMTUyMDU4MThaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu +ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsdUJk +4KxADA3vlDHxNbyC27Ozw4yiSVzPTHUct471YmdDRW3orO2P5a5hRnUGV70gjH9X +MU4oeOdWYAgXB9pxfLyr6621k1+uNrmaZtzp0ECH9twcwxNJJFDZsN7o9vt7V6Ej +NN9weeqDr/aeQXo07a12vyVfR6jWO8jHB0e4aemwZNoYjNvM69fivQTse2ZoRVfj +eSHhjRTX6I8ry4a31Hwt+fT1QiWWNN6o7+WOtpJAhX3eg4smhSD1svi2kOT8tdUe +NS4hWlmXmumU9G4tI8PBurcLNTm7PB2lUlbn/IV18WavqKE/Uy/1WgAx+a1EJNdp +i07AG1PsqaONKkf1AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAJrNsuL7fZZNC8gL +BdePJ7DYW2e7mXANU3bCBe2BZqmXKQxKwibZnEsqA+yMLqcSd8uxISlyHY2tw9wT +4wB9KPIttfNLbwn/rk+MbOTHpvyF60d9WhJJVUkPBl8D4VuPSl+VnlA54kU9dtZN ++ZYdxYbNtSsI/Flz9SCoOV79W9GhN+uYJhv6RwyIMIHeMpZpyX1xSUVx5dZlmerQ +WAUvghDH3fFRt2ZdnA4OXoKkTAaM3Pv7PUMsnah8bux6MQi0AuLMWFWOI1H34koH +rs2oQLwOLnuifH52ey9+tJguabo+brlYYigAuWWFEzJfBzikDkIwnE/L7wlrypIk +taXDWI4= +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/res/raw/subject_with_alt_names.crt b/tests/AndroidTests/res/raw/subject_with_alt_names.crt new file mode 100644 index 0000000..6963c7e --- /dev/null +++ b/tests/AndroidTests/res/raw/subject_with_alt_names.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBDCCAeygAwIBAgIJALv14qjcuhw9MA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV +BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjA1OTM4 +WhgPMjA2NDEwMTUyMDU5MzhaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu +ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiTVgU +kBO9KNYZZLmiPR0eBrk8u61CLnm35BGKW8EFpDaINLbbIFIQvqOMekURON/N+xFY +D8roo7aFZVuHWAUqFcOJ4e6NmviK5qocLihtzAexsw4f4AzZxM3A8kcLlWLyAt7e +EVLxhcMHogY7GaF6q+33Z8p+zp6x3tj07mwyPrriCLse2PeRsRunZl/fp/VvRlr6 +YbC7CbRrhnIv5nqohs8BsbBiiFpxQftsMQmiXhY2LUzqY2RXUIOw24fHjoQkHTL2 +4z5nUM3b6ueQe+CBnobUS6fzK/36Nct4dRpev9i/ORdRLuIDKJ+QR16G1V/BJYBR +dAK+3iXvg6z8vP1XAgMBAAGjMTAvMC0GA1UdEQQmMCSCEHd3dzIuZXhhbXBsZS5j +b22CEHd3dzMuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAJQNf38uXm3h +0vsF+Yd6/HqM48Su7tWnTDAfTXnQZZkzjzITq3JXzquMXICktAVN2cLnT9zPfRAE +8V8A3BNO5zXiR5W3o/mJP5HQ3/WxpzBGM2N+YmDCJyBoQrIVaAZaXAZUaBBvn5A+ +kEVfGWquwIFuvA67xegbJOCRLD4eUzRdNsn5+NFiakWO1tkFqEzqyQ0PNPviRjgu +z9NxdPvd1JQOhydkucsPKJzlEBbGyL5QL/Jkot3Qy+FOeuNzgQUfAGtQgzRrsZDK +hrTVypLSoRXuTB2aWilu4p6aNh84xTdyqo2avtNr2MiQMZIcdamBq8LdBIAShFXI +h5G2eVGXH/Y= +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt b/tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt new file mode 100644 index 0000000..19b1174 --- /dev/null +++ b/tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC8DCCAdigAwIBAgIJAL/oWJ64VAdXMA0GCSqGSIb3DQEBBQUAMCcxCzAJBgNV +BAYTAkpQMRgwFgYDVQQDEw93d3cuZXhhbXBsZS5jb20wIBcNMTAwMTEyMjEwMDAx +WhgPMjA2NDEwMTUyMTAwMDFaMCcxCzAJBgNVBAYTAkpQMRgwFgYDVQQDEw93d3cu +ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbx1QB +92iea7VybLYICA4MX4LWipYrRsgXUXQrcIQ3YLTQ9rH0VwScrHL4O4JDxgXCQnR+ +4VOzD42q1KXHJAqzqGUYCNPyvZEzkGCnQ4FBIUEmxZd5SNEefJVH3Z6GizYJomTh +p78yDcoqymD9umxRC2cWFu8GscfFGMVyhsqLlOofu7UWOs22mkXPo43jDx+VOAoV +n48YP3P57a2Eo0gcd4zVL00y62VegqBO/1LW38aTS7teiCBFc1TkNYa5I40yN9lP +rB9ICHYQWyzf/7OxU9iauEK2w6DmSsQoLs9JzEhgeNZddkcc77ciSUCo2Hx0VpOJ +BFyf2rbryJeAk+FDAgMBAAGjHTAbMBkGA1UdEQQSMBCCDiouZXhhbXBsZTIuY29t +MA0GCSqGSIb3DQEBBQUAA4IBAQA2a14pRL+4laJ8sscQlucaDB/oSdb0cwhk4IkE +kKl/ZKr6rKwPZ81sJRgzvI4imLbUAKt4AJHdpI9cIQUq1gw9bzil7LKwmFtFSPmC +MYb1iadaYrvp7RE4yXrWCcSbU0hup9JQLHTrHLlqLtRuU48NHMvWYThBcS9Q/hQp +nJ/JxYy3am99MHALWLAfuRxQXhE4C5utDmBwI2KD6A8SA30s+CnuegmkYScuSqBu +Y3R0HZvKzNIU3pwAm69HCJoG+/9MZEIDJb0WJc5UygxDT45XE9zQMQe4dBOTaNXT ++ntgaB62kE10HzrzpqXAgoAWxWK4RzFcUpBWw9qYq9xOCewJ +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/res/raw/wild_alt_name_only.crt b/tests/AndroidTests/res/raw/wild_alt_name_only.crt new file mode 100644 index 0000000..fafdebf --- /dev/null +++ b/tests/AndroidTests/res/raw/wild_alt_name_only.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICuzCCAaOgAwIBAgIJAP82tgcvmAGxMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV +BAYTAkpQMCAXDTEwMDExMjIxMDAyN1oYDzIwNjQxMDE1MjEwMDI3WjANMQswCQYD +VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALs528EQbcB1 +x4BwxthQBZrgDJzoO7KPV3dhGYoeP8EnRjapZm+T/sj9P/O4HvfxjnB+fsjYSdmE +WWUtnFrP7wtG9DUC748Ea2PMV8WFhOG58dqBNIko5XzkHB7SxkNZD5S/0KQYMGLr +rchDsDlmsEf2Qb6qiqpNEU70aSkExZJcH+B9nWdeBpsVFu7wtezwSWEc2NUa2bhW +gcXQ/aafwHZ4o2PyGwy0sgS/UifqO9tEllC2tPleSNJOmYsVudv5Bz4Q0GG38BSz +Pc0IcOoln0ZWpXbGr03V2vlXWCwzaFAl3I1T3O7YVqDiaSWoP+d0tHZzmw8aJLXd +B+KaUUGxRPsCAwEAAaMcMBowGAYDVR0RBBEwD4INKi5leGFtcGxlLmNvbTANBgkq +hkiG9w0BAQUFAAOCAQEAJbVan4QgJ0cvpJnK9UWIVJNC+UbP87RC5go2fQiTnmGv +prOrIuMqz1+vGcpIheLTLctJRHPoadXq0+UbQEIaU3pQbY6C4nNdfl+hcvmJeqrt +kOCcvmIamO68iNvTSeszuHuu4O38PefrW2Xd0nn7bjFZrzBzHFhTudmnqNliP3ue +KKQpqkUt5lCytnH8V/u/UCWdvVx5LnUa2XFGVLi3ongBIojW5fvF+yxn9ADqxdrI +va++ow5r1VxQXFJc0ZPzsDo+6TlktoDHaRQJGMqQomqHWT4i7F5UZgf6BHGfEUPU +qep+GsF3QRHSBtpObWkVDZNFvky3a1iZ2q25+hFIqQ== +-----END CERTIFICATE----- diff --git a/tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java b/tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java new file mode 100644 index 0000000..61d0b42 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.unit_tests; + +import com.android.internal.net.DNParser; + +import javax.security.auth.x500.X500Principal; + +import junit.framework.TestCase; + +public class DNParserTest extends TestCase { + public void testFind() { + checkFind("", "cn", null); + checkFind("ou=xxx", "cn", null); + checkFind("ou=xxx,cn=xxx", "cn", "xxx"); + checkFind("ou=xxx+cn=yyy,cn=zzz+cn=abc", "cn", "yyy"); + checkFind("2.5.4.3=a,ou=xxx", "cn", "a"); // OID + checkFind("cn=a,cn=b", "cn", "a"); + checkFind("ou=Cc,ou=Bb,ou=Aa", "ou", "Cc"); + checkFind("cn=imap.gmail.com", "cn", "imap.gmail.com"); + + // Quoted string (see http://www.ietf.org/rfc/rfc2253.txt) + checkFind("o=\"\\\" a ,=<>#;\"", "o", "\" a ,=<>#;"); + checkFind("o=abc\\,def", "o", "abc,def"); + + // UTF-8 (example in rfc 2253) + checkFind("cn=Lu\\C4\\8Di\\C4\\87", "cn", "\u004c\u0075\u010d\u0069\u0107"); + + // whitespaces + checkFind("ou=a, o= a b ,cn=x", "o", "a b"); + checkFind("o=\" a b \" ,cn=x", "o", " a b "); + } + + private void checkFind(String dn, String attrType, String expected) { + String actual = new DNParser(new X500Principal(dn)).find(attrType); + assertEquals("dn:" + dn + " attr:" + attrType, expected, actual); + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java b/tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java new file mode 100644 index 0000000..1754dbe --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.unit_tests; + +import com.android.internal.net.DomainNameValidator; + +import android.test.AndroidTestCase; + +import java.io.InputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +public class DomainNameValidatorTest extends AndroidTestCase { + private static final int ALT_UNKNOWN = 0; + private static final int ALT_DNS_NAME = 2; + private static final int ALT_IPA_NAME = 7; + + /** + * Tests {@link DomainNameValidator#match}, using a simple {@link X509Certificate} + * implementation. + */ + public void testMatch() { + checkMatch("11", new StubX509Certificate("cn=imap.g.com"), "imap.g.com", true); + checkMatch("12", new StubX509Certificate("cn=imap2.g.com"), "imap.g.com", false); + checkMatch("13", new StubX509Certificate("cn=sub.imap.g.com"), "imap.g.com", false); + + // If a subjectAltName extension of type dNSName is present, that MUST + // be used as the identity + checkMatch("21", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com") + , "imap.g.com", false); + checkMatch("22", new StubX509Certificate("cn=imap.g.com") // This cn should be ignored + .addSubjectAlternativeName(ALT_DNS_NAME, "a.y.com") + , "imap.g.com", false); + checkMatch("23", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") + , "imap.g.com", true); + + // With wildcards + checkMatch("24", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_DNS_NAME, "*.g.com") + , "imap.g.com", true); + + // host name is ip address + checkMatch("31", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4") + , "1.2.3.4", true); + checkMatch("32", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4") + , "1.2.3.5", false); + checkMatch("32", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_IPA_NAME, "1.2.3.4") + .addSubjectAlternativeName(ALT_IPA_NAME, "192.168.100.1") + , "192.168.100.1", true); + + // Has unknown subject alternative names + checkMatch("41", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") + .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") + .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") + .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") + .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3") + , "imap.g.com", true); + + checkMatch("42", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") + .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") + .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") + .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") + .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3") + , "2.33.44.55", true); + + checkMatch("43", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") + .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") + .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") + .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") + .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3") + , "g.com", false); + + checkMatch("44", new StubX509Certificate("") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 1") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 2") + .addSubjectAlternativeName(ALT_DNS_NAME, "a.b.c.d") + .addSubjectAlternativeName(ALT_DNS_NAME, "*.google.com") + .addSubjectAlternativeName(ALT_DNS_NAME, "imap.g.com") + .addSubjectAlternativeName(ALT_IPA_NAME, "2.33.44.55") + .addSubjectAlternativeName(ALT_UNKNOWN, "random string 3") + , "2.33.44.1", false); + } + + private void checkMatch(String message, X509Certificate certificate, String thisDomain, + boolean expected) { + Boolean actual = DomainNameValidator.match(certificate, thisDomain); + assertEquals(message, (Object) expected, (Object) actual); + } + + /** + * Tests {@link DomainNameValidator#matchDns} + */ + public void testMatchDns() { + checkMatchDns("11", "a.b.c.d", "a.b.c.d", true); + checkMatchDns("12", "a.b.c.d", "*.b.c.d", true); + checkMatchDns("13", "b.c.d", "*.b.c.d", true); + checkMatchDns("14", "b.c.d", "b*.c.d", true); + + checkMatchDns("15", "a.b.c.d", "*.*.c.d", false); + checkMatchDns("16", "a.b.c.d", "*.c.d", false); + + checkMatchDns("21", "imap.google.com", "imap.google.com", true); + checkMatchDns("22", "imap2.google.com", "imap.google.com", false); + checkMatchDns("23", "imap.google.com", "*.google.com", true); + checkMatchDns("24", "imap2.google.com", "*.google.com", true); + checkMatchDns("25", "imap.google.com", "*.googl.com", false); + checkMatchDns("26", "imap2.google2.com", "*.google3.com", false); + checkMatchDns("27", "imap.google.com", "ima*.google.com", true); + checkMatchDns("28", "imap.google.com", "imap*.google.com", true); + checkMatchDns("29", "imap.google.com", "*.imap.google.com", true); + + checkMatchDns("41", "imap.google.com", "a*.google.com", false); + checkMatchDns("42", "imap.google.com", "ix*.google.com", false); + + checkMatchDns("51", "imap.google.com", "iMap.Google.Com", true); + } + + private void checkMatchDns(String message, String thisDomain, String thatDomain, + boolean expected) { + boolean actual = DomainNameValidator.matchDns(thisDomain, thatDomain); + assertEquals(message, expected, actual); + } + + /** + * Test {@link DomainNameValidator#match} with actual certificates. + */ + public void testWithActualCert() throws Exception { + // subject_only + // + // subject: C=JP, CN=www.example.com + // subject alt names: n/a + checkWithActualCert("11", R.raw.subject_only, "www.example.com", true); + checkWithActualCert("12", R.raw.subject_only, "www2.example.com", false); + + // subject_alt_only + // + // subject: C=JP (no CN) + // subject alt names: DNS:www.example.com + checkWithActualCert("21", R.raw.subject_alt_only, "www.example.com", true); + checkWithActualCert("22", R.raw.subject_alt_only, "www2.example.com", false); + + // subject_with_alt_names + // + // subject: C=JP, CN=www.example.com + // subject alt names: DNS:www2.example.com, DNS:www3.example.com + // * Subject should be ignored, because it has subject alt names. + checkWithActualCert("31", R.raw.subject_with_alt_names, "www.example.com", false); + checkWithActualCert("32", R.raw.subject_with_alt_names, "www2.example.com", true); + checkWithActualCert("33", R.raw.subject_with_alt_names, "www3.example.com", true); + checkWithActualCert("34", R.raw.subject_with_alt_names, "www4.example.com", false); + + // subject_with_wild_alt_name + // + // subject: C=JP, CN=www.example.com + // subject alt names: DNS:*.example2.com + // * Subject should be ignored, because it has subject alt names. + checkWithActualCert("41", R.raw.subject_with_wild_alt_name, "www.example.com", false); + checkWithActualCert("42", R.raw.subject_with_wild_alt_name, "www2.example.com", false); + checkWithActualCert("43", R.raw.subject_with_wild_alt_name, "www.example2.com", true); + checkWithActualCert("44", R.raw.subject_with_wild_alt_name, "abc.example2.com", true); + checkWithActualCert("45", R.raw.subject_with_wild_alt_name, "www.example3.com", false); + + // wild_alt_name_only + // + // subject: C=JP + // subject alt names: DNS:*.example.com + checkWithActualCert("51", R.raw.wild_alt_name_only, "www.example.com", true); + checkWithActualCert("52", R.raw.wild_alt_name_only, "www2.example.com", true); + checkWithActualCert("53", R.raw.wild_alt_name_only, "www.example2.com", false); + + // wild_alt_name_only + // + // subject: C=JP + // subject alt names: IP Address:192.168.10.1 + checkWithActualCert("61", R.raw.alt_ip_only, "192.168.10.1", true); + checkWithActualCert("61", R.raw.alt_ip_only, "192.168.10.2", false); + } + + private void checkWithActualCert(String message, int resId, String domain, + boolean expected) throws Exception { + CertificateFactory factory = CertificateFactory.getInstance("X509"); + InputStream certStream = getContext().getResources().openRawResource(resId); + X509Certificate certificate = (X509Certificate) factory.generateCertificate(certStream); + + checkMatch(message, certificate, domain, expected); + } + + /** + * Minimal {@link X509Certificate} implementation for {@link DomainNameValidator}. + */ + private static class StubX509Certificate extends X509Certificate { + private final X500Principal subjectX500Principal; + private Collection<List<?>> subjectAlternativeNames; + + public StubX509Certificate(String subjectDn) { + subjectX500Principal = new X500Principal(subjectDn); + subjectAlternativeNames = null; + } + + public StubX509Certificate addSubjectAlternativeName(int type, String name) { + if (subjectAlternativeNames == null) { + subjectAlternativeNames = new ArrayList<List<?>>(); + } + LinkedList<Object> entry = new LinkedList<Object>(); + entry.add(type); + entry.add(name); + subjectAlternativeNames.add(entry); + return this; + } + + @Override + public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException { + return subjectAlternativeNames; + } + + @Override + public X500Principal getSubjectX500Principal() { + return subjectX500Principal; + } + + @Override + public void checkValidity() throws CertificateExpiredException, + CertificateNotYetValidException { + throw new RuntimeException("Method not implemented"); + } + + @Override + public void checkValidity(Date date) throws CertificateExpiredException, + CertificateNotYetValidException { + throw new RuntimeException("Method not implemented"); + } + + @Override + public int getBasicConstraints() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public Principal getIssuerDN() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public boolean[] getIssuerUniqueID() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public boolean[] getKeyUsage() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public Date getNotAfter() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public Date getNotBefore() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public BigInteger getSerialNumber() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public String getSigAlgName() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public String getSigAlgOID() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public byte[] getSigAlgParams() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public byte[] getSignature() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public Principal getSubjectDN() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public boolean[] getSubjectUniqueID() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + throw new RuntimeException("Method not implemented"); + } + + @Override + public int getVersion() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + throw new RuntimeException("Method not implemented"); + } + + @Override + public PublicKey getPublicKey() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public String toString() { + throw new RuntimeException("Method not implemented"); + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + throw new RuntimeException("Method not implemented"); + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, + NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, + SignatureException { + throw new RuntimeException("Method not implemented"); + } + + public Set<String> getCriticalExtensionOIDs() { + throw new RuntimeException("Method not implemented"); + } + + public byte[] getExtensionValue(String oid) { + throw new RuntimeException("Method not implemented"); + } + + public Set<String> getNonCriticalExtensionOIDs() { + throw new RuntimeException("Method not implemented"); + } + + public boolean hasUnsupportedCriticalExtension() { + throw new RuntimeException("Method not implemented"); + } + } +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java b/tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java new file mode 100644 index 0000000..0edcd6d --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.unit_tests; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Patterns; + +import java.util.regex.Matcher; + +import junit.framework.TestCase; + +public class PatternsTest extends TestCase { + + @SmallTest + public void testTldPattern() throws Exception { + boolean t; + + t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches(); + assertTrue("Missed valid TLD", t); + + // One of the new top level domain. + t = Patterns.TOP_LEVEL_DOMAIN.matcher("me").matches(); + assertTrue("Missed valid TLD", t); + + // One of the new top level test domain. + t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches(); + assertTrue("Missed valid TLD", t); + + t = Patterns.TOP_LEVEL_DOMAIN.matcher("mem").matches(); + assertFalse("Matched invalid TLD!", t); + + t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn").matches(); + assertFalse("Matched invalid TLD!", t); + + t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches(); + assertFalse("Matched invalid TLD!", t); + } + + @SmallTest + public void testUrlPattern() throws Exception { + boolean t; + + t = Patterns.WEB_URL.matcher("http://www.google.com").matches(); + assertTrue("Valid URL", t); + + // Google in one of the new top level domain. + t = Patterns.WEB_URL.matcher("http://www.google.me").matches(); + assertTrue("Valid URL", t); + t = Patterns.WEB_URL.matcher("google.me").matches(); + assertTrue("Valid URL", t); + + // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d + t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches(); + assertTrue("Valid URL", t); + t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches(); + assertTrue("Valid URL", t); + + // Internationalized URL. + t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); + assertTrue("Valid URL", t); + t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); + assertTrue("Valid URL", t); + + t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches(); + assertFalse("Matched invalid protocol", t); + + t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches(); + assertTrue("Didn't match valid URL with port", t); + + t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches(); + assertTrue("Didn't match valid URL with port and query args", t); + + t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches(); + assertTrue("Didn't match valid URL with ~", t); + } + + @SmallTest + public void testIpPattern() throws Exception { + boolean t; + + t = Patterns.IP_ADDRESS.matcher("172.29.86.3").matches(); + assertTrue("Valid IP", t); + + t = Patterns.IP_ADDRESS.matcher("1234.4321.9.9").matches(); + assertFalse("Invalid IP", t); + } + + @SmallTest + public void testDomainPattern() throws Exception { + boolean t; + + t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches(); + assertTrue("Valid domain", t); + + t = Patterns.WEB_URL.matcher("google.me").matches(); + assertTrue("Valid domain", t); + + // Internationalized domains. + t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); + assertTrue("Valid domain", t); + + t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches(); + assertFalse("Invalid domain", t); + } + + @SmallTest + public void testPhonePattern() throws Exception { + boolean t; + + t = Patterns.PHONE.matcher("(919) 555-1212").matches(); + assertTrue("Valid phone", t); + + t = Patterns.PHONE.matcher("2334 9323/54321").matches(); + assertFalse("Invalid phone", t); + + String[] tests = { + "Me: 16505551212 this\n", + "Me: 6505551212 this\n", + "Me: 5551212 this\n", + + "Me: 1-650-555-1212 this\n", + "Me: (650) 555-1212 this\n", + "Me: +1 (650) 555-1212 this\n", + "Me: +1-650-555-1212 this\n", + "Me: 650-555-1212 this\n", + "Me: 555-1212 this\n", + + "Me: 1.650.555.1212 this\n", + "Me: (650) 555.1212 this\n", + "Me: +1 (650) 555.1212 this\n", + "Me: +1.650.555.1212 this\n", + "Me: 650.555.1212 this\n", + "Me: 555.1212 this\n", + + "Me: 1 650 555 1212 this\n", + "Me: (650) 555 1212 this\n", + "Me: +1 (650) 555 1212 this\n", + "Me: +1 650 555 1212 this\n", + "Me: 650 555 1212 this\n", + "Me: 555 1212 this\n", + }; + + for (String test : tests) { + Matcher m = Patterns.PHONE.matcher(test); + + assertTrue("Valid phone " + test, m.find()); + } + } +} |