Return-Path: Delivered-To: apmail-incubator-harmony-commits-archive@www.apache.org Received: (qmail 23314 invoked from network); 10 Jul 2006 06:14:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 10 Jul 2006 06:14:39 -0000 Received: (qmail 44203 invoked by uid 500); 10 Jul 2006 06:14:38 -0000 Delivered-To: apmail-incubator-harmony-commits-archive@incubator.apache.org Received: (qmail 44178 invoked by uid 500); 10 Jul 2006 06:14:38 -0000 Mailing-List: contact harmony-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-commits@incubator.apache.org Received: (qmail 44167 invoked by uid 99); 10 Jul 2006 06:14:38 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 09 Jul 2006 23:14:38 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 09 Jul 2006 23:14:37 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id DB3311A981C; Sun, 9 Jul 2006 23:14:16 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r420433 - in /incubator/harmony/enhanced/classlib/trunk/modules/security/src: main/java/common/org/apache/harmony/security/x509/ test/api/java/org/apache/harmony/security/tests/java/security/cert/ test/impl/java/org/apache/harmony/security/... Date: Mon, 10 Jul 2006 06:14:16 -0000 To: harmony-commits@incubator.apache.org From: mloenko@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060710061416.DB3311A981C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: mloenko Date: Sun Jul 9 23:14:15 2006 New Revision: 420433 URL: http://svn.apache.org/viewvc?rev=420433&view=rev Log: fixes for HARMONY-727 [classlib][security] unexpected exceptions for X509CertSelector. addSubjectAlternativeName(<2,4,6,7,8>, String name) Added: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/api/java/org/apache/harmony/security/tests/java/security/cert/X509CertSelectorTest.java Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/GeneralName.java incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/x509/GeneralNameTest.java Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/GeneralName.java URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/GeneralName.java?rev=420433&r1=420432&r2=420433&view=diff ============================================================================== --- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/GeneralName.java (original) +++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/x509/GeneralName.java Sun Jul 9 23:14:15 2006 @@ -22,6 +22,8 @@ package org.apache.harmony.security.x509; import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -143,6 +145,9 @@ *
      */
     public GeneralName(int tag, String name) throws IOException {
+        if (name == null) {
+            throw new IOException("The name should not be null.");
+        }
         this.tag = tag;
         switch (tag) {
             case OTHER_NAME :
@@ -150,37 +155,36 @@
             case EDIP_NAME :
                 throw new IOException(
                         "Unknown string representation for type ["+tag+"]");
-            case RFC822_NAME :
             case DNS_NAME :
+                // according to RFC 3280 p.34 the DNS name should be 
+                // checked against the
+                // RFC 1034 p.10 (3.5. Preferred name syntax):
+                checkDNS(name);
+                this.name = name;
+                break;
             case UR_ID :
+                // check the uniformResourceIdentifier for correctness
+                // according to RFC 3280 p.34
+                checkURI(name);
+                this.name = name;
+                break;
+            case RFC822_NAME :
                 this.name = name;
                 break;
             case REG_ID:
-                this.name = ObjectIdentifier.toIntArray(name);
+                this.name = oidStrToInts(name);
                 break;
             case DIR_NAME :
-                try {
-                    this.name = new Name(name);
-                } catch (IOException e) {
-                    throw new IOException("The string " +
-                                "representation of directoryName " +
-                                "is not correct:" + name);
-                }
+                this.name = new Name(name);
                 break;
             case IP_ADDR :
                 this.name = ipStrToBytes(name);
-                int length = ((byte[])this.name).length;
-                if ((length != 4) && (length != 8) 
-                                    && (length != 16) && (length != 32)) {
-                    throw 
-                        new IOException("Specified iPAddress is not correct.");
-                }
                 break;
             default:
                 throw new IOException("Unknown type: ["+tag+"]");
         }
     }
-    
+
     /**
      * TODO
      * @param   name:   OtherName
@@ -245,6 +249,9 @@
      */
     public GeneralName(int tag, byte[] name) 
                                     throws IOException {
+        if (name == null) {
+            throw new IOException("The name should not be null.");
+        }
         if ((tag < 0) || (tag > 8)) {
             throw new IOException("GeneralName: unknown tag: " + tag);
         }
@@ -294,30 +301,25 @@
         if (!(_gname instanceof GeneralName)) {
             return false;
         }
-        //System.out.println("COMP: "+this+" <> "+_gname);
         GeneralName gname = (GeneralName) _gname;
         if (this.tag != gname.tag) {
-            //System.out.println(false);
             return false;
         }
         switch(tag) {
             case RFC822_NAME:
             case DNS_NAME:
             case UR_ID:
-                //System.out.println(((String) name).equals(gname.getName()));
-                return ((String) name).equals(gname.getName());
+                return ((String) name).equalsIgnoreCase(
+                        (String) gname.getName());
             case REG_ID:
-                //System.out.println(Arrays.equals((int[]) name, (int[]) gname.name));
                 return Arrays.equals((int[]) name, (int[]) gname.name);
             case IP_ADDR: 
                 // iPAddress [7], check by using ranges.
-                //System.out.println(Arrays.equals((byte[]) name, (byte[]) gname.name));
                 return Arrays.equals((byte[]) name, (byte[]) gname.name);
             case DIR_NAME: 
             case X400_ADDR:
             case OTHER_NAME:
             case EDIP_NAME:
-                //System.out.println(Arrays.equals(getEncoded(), gname.getEncoded()));
                 return Arrays.equals(getEncoded(), gname.getEncoded());
             default:
                 // should never happen
@@ -349,17 +351,18 @@
                 // Mail address [1]: 
                 // a@b.c - particular address is acceptable by the same address,
                 // or by b.c - host name.
-                return ((String) gname.getName()).endsWith((String) name);
+                return ((String) gname.getName()).toLowerCase()
+                    .endsWith(((String) name).toLowerCase());
             case DNS_NAME:
                 // DNS name [2] that can be constructed by simply adding 
                 // to the left hand side of the name satisfies the name 
                 // constraint: aaa.aa.aa satisfies to aaa.aa.aa, aa.aa, ..
                 String dns = (String) name;
                 String _dns = (String) gname.getName();
-                if (dns.equals(_dns)) {
+                if (dns.equalsIgnoreCase(_dns)) {
                     return true;
                 } else {
-                    return _dns.endsWith("."+dns);
+                    return _dns.toLowerCase().endsWith("." + dns.toLowerCase());
                 }
             case UR_ID:
                 // For URIs the constraint ".xyz.com" is satisfied by both 
@@ -381,9 +384,9 @@
                                 ? uri.substring(begin)
                                 : uri.substring(begin, end);
                 if (host.startsWith(".")) {
-                    return _host.endsWith(host);
+                    return _host.toLowerCase().endsWith(host.toLowerCase());
                 } else {
-                    return host.equals(_host);
+                    return host.equalsIgnoreCase(_host);
                 }
             case IP_ADDR: 
                 // iPAddress [7], check by using ranges.
@@ -558,28 +561,272 @@
     }
 
     /**
-     * Helper method. Converts the String representation of ip address
-     * to array of bytes.
-     * @param   address :   String representation of ip address
-     * @return  byte representation of ip address
-     */
-    public static byte[] ipStrToBytes(String address) {
-        StringTokenizer st = new StringTokenizer(address, ".:/");
-        boolean is_ipv6 = address.indexOf(':') > 0;
-        int length = (is_ipv6) ? st.countTokens() * 2: st.countTokens();
-        byte[] ip = new byte[length];
-        int k = 0;
-        while (st.hasMoreElements()) {
-            if (is_ipv6) {
-                String token = st.nextToken();
-                ip[k++] = (byte) Integer.parseInt(token.substring(0, 2), 16);
-                ip[k++] = (byte) Integer.parseInt(token.substring(2), 16);
-            } else {
-                ip[k++] = (byte) Integer.parseInt(st.nextToken());
+     * Checks the correctness of the string representation of DNS name.
+     * The correctness is checked as specified in RFC 1034 p. 10.
+     */
+    public static void checkDNS(String dns) throws IOException {
+        byte[] bytes = dns.toLowerCase().getBytes();
+        // indicates if it is a first letter of the label
+        boolean first_letter = true;
+        for (int i=0; i 'z' || ch < 'a') {
+                    throw new IOException("DNS name must start with a letter: "
+                            + "'" + (char)ch + "' " + dns);
+                }
+                first_letter = false;
+                continue;
+            }
+            if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
+                    || (ch == '-') || (ch == '.'))) {
+                throw new IOException("Incorrect DNS name: " + dns);
+            }
+            if (ch == '.') {
+                // check the end of the previous label, it should not
+                // be '-' sign
+                if (bytes[i-i] == '-') {
+                    throw new IOException(
+                            "Incorrect DNS name: label ends with '-': " + dns);
+                }
+                first_letter = true;
+            }
+        }
+    }
+
+    /**
+     * Checks the correctness of the string representation of URI name.
+     * The correctness is checked as pointed out in RFC 3280 p. 34.
+     */
+    public static void checkURI(String uri) throws IOException {
+        try {
+            URI ur = new URI(uri);
+            if ((ur.getScheme() == null) 
+                    || (ur.getRawSchemeSpecificPart().length() == 0)) {
+                throw new IOException(
+                    "Bad representation of uniformResourceIdentifier. "
+                    + "It must include the scheme and a scheme-specific-part: "
+                    + uri);
+            }
+            if (!ur.isAbsolute()) {
+                throw new IOException(
+                    "Bad representation of uniformResourceIdentifier."
+                    + " It should not be relative: " + uri);
+            }
+        } catch (URISyntaxException e) {
+            throw (IOException) new IOException(
+                    "Bad representation of uniformResourceIdentifier."
+                    + uri).initCause(e);
+        }
+    }
+
+    /**
+     * Converts OID into array of bytes.
+     */
+    public static int[] oidStrToInts(String oid) throws IOException {
+        byte[] bytes = oid.getBytes();
+        if (bytes[bytes.length-1] == '.') {
+            throw new IOException("Incorrect OID: " + oid);
+        }
+        int[] result = new int[bytes.length/2+1]; // best case: a.b.c.d.e
+        int number = 0; // the number of OID's components
+        for (int i=0; i= '0')
+                        && (bytes[i] <= '9')) {
+                value = 10 * value + (bytes[i++] - 48);
+            }
+            if (i == pos) {
+                // the number was not read
+                throw new IOException("Incorrect OID: " + oid);
+            }
+            result[number++] = value;
+            if (i >= bytes.length) {
+                break;
+            }
+            if (bytes[i] != '.') {
+                throw new IOException("Incorrect OID: " + oid);
+            }
+        }
+        if (number < 2) {
+            throw new IOException("OID should consist of "
+                    + "no less than 2 components:" + oid);
+        }
+        int[] res = new int[number];
+        for (int i=0; i
+     * IPv4 - in dot-decimal notation
+ * IPv6 - in colon hexadecimal notation
+ * Also method works with the ranges of the addresses represented + * as 2 addresses separated by '/' character. + * @param address : String representation of IP address + * @return byte representation of IP address + */ + public static byte[] ipStrToBytes(String ip) throws IOException { + boolean isIPv4 = (ip.indexOf('.') > 0); + // number of components (should be 4 or 8) + int num_components = (isIPv4) ? 4 : 16; + if (ip.indexOf('/') > 0) { + num_components *= 2; // this is a range of addresses + } + // the resulting array + byte[] result = new byte[num_components]; + byte[] ip_bytes = ip.getBytes(); + // number of address component to be read + int component = 0; + // if it is reading the second bound of a range + boolean reading_second_bound = false; + if (isIPv4) { + // IPv4 address is expected in the form of dot-decimal notation: + // 1.100.2.200 + // or in the range form: + // 1.100.2.200/1.100.3.300 + int i = 0; + while (i < ip_bytes.length) { + int digits = 0; + // the value of the address component + int value = 0; + while ((i < ip_bytes.length) && (ip_bytes[i] >= '0') + && (ip_bytes[i] <= '9')) { + digits++; + if (digits > 3) { + throw new IOException("Component of IPv4 address should" + + "consist of no more than 3 decimal numbers: " + + ip); + } + value = 10 * value + (ip_bytes[i] - 48); + i++; + } + if (digits == 0) { + // ip_bytes[i] is not a number + throw new IOException("Incorrect IP representation: " + + ip); + } + result[component] = (byte) value; + component++; + if (i >= ip_bytes.length) { + // no more bytes + break; + } + // check the reached delimiter + if ((ip_bytes[i] != '.' && ip_bytes[i] != '/')) { + throw new IOException("Incorrect IP representation: " + + ip); + } + // check the correctness of the range + if (ip_bytes[i] == '/') { + if (reading_second_bound) { + // more than 2 bounds in the range + throw new IOException("Incorrect IP representation: " + + ip); + } + if (component != 4) { + throw new IOException("IPv4 address should consist " + + "of 4 decimal numbers: " + ip); + } + reading_second_bound = true; + } + // check the number of the components + if (component > ((reading_second_bound) ? 7 : 3)) { + throw new IOException("IPv4 address should consist " + + "of 4 decimal numbers: " + ip); + } + i++; + } + // check the number of read components + if (component != num_components) { + throw new IOException("IPv4 address should consist " + + "of 4 decimal numbers: " + ip); + } + } else { + // IPv6 address is expected in the form of + // colon hexadecimal notation: + // 010a:020b:3337:1000:FFFA:ABCD:9999:0000 + // or in a range form: + // 010a:020b:3337:1000:FFFA:ABCD:9999:0000/010a:020b:3337:1000:FFFA:ABCD:9999:1111 + if (ip_bytes.length != 39 && ip_bytes.length != 79) { + // incorrect length of the string representation + throw new IOException("Incorrect IPv6 representation: '" + + ip + "'"); + } + int value = 0; + // indicates the reading of the second half of byte + boolean second_hex = false; + // if the delimiter (':' or '/') is expected + boolean expect_delimiter = false; + for (int i=0; i= '0') && (bytik <= '9')) { + value = (bytik - 48); // '0':0, '1':1, ... , '9':9 + } else if ((bytik >= 'A') && (bytik <= 'F')) { + value = (bytik - 55); // 'A':10, 'B':11, ... , 'F':15 + } else if ((bytik >= 'a') && (bytik <= 'f')) { + value = (bytik - 87); // 'a':10, 'b':11, ... , 'f':15 + } else if (second_hex) { + // second hex value of a byte is expected but was not read + // (it is the situation like: ...ABCD:A:ABCD...) + throw new IOException("Incorrect IPv6 representation: '" + + ip + "'"); + } else if ((bytik == ':') || (bytik == '/')) { + if (component % 2 == 1) { + // second byte of the component is omitted + // (it is the situation like: ... ABDC:AB:ABCD ...) + throw new IOException("Incorrect IPv6 representation: '" + + ip + "'"); + } + if (bytik == '/') { + if (reading_second_bound) { + // more than 2 bounds in the range + throw new IOException( + "Incorrect IPv6 representation: " + ip); + } + if (component != 16) { + // check the number of read components + throw new IOException("IPv6 address should consist " + + "of 8 hexadecimal numbers: " + ip); + } + reading_second_bound = true; + } + expect_delimiter = false; + continue; + } else { + throw new IOException("Incorrect IPv6 representation: '" + + ip + "'"); + } + if (expect_delimiter) { // delimiter is expected but was not read + throw new IOException("Incorrect IPv6 representation: '" + + ip + "'"); + } + if (!second_hex) { + // first half of byte has been read + result[component] = (byte) (value << 4); + second_hex = true; + } else { + // second half of byte has been read + result[component] = (byte) + ((result[component] & 0xFF) | value); + // delimiter is expected if 2 bytes were read + expect_delimiter = (component % 2 == 1); + second_hex = false; + component++; + } + } + // check the correctness of the read address: + if (second_hex || (component % 2 == 1)) { + throw new IOException("Incorrect IPv6 representation: " + ip); } } - return ip; + return result; } + /** * Helper method. Converts the byte array representation of ip address Added: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/api/java/org/apache/harmony/security/tests/java/security/cert/X509CertSelectorTest.java URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/api/java/org/apache/harmony/security/tests/java/security/cert/X509CertSelectorTest.java?rev=420433&view=auto ============================================================================== --- incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/api/java/org/apache/harmony/security/tests/java/security/cert/X509CertSelectorTest.java (added) +++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/api/java/org/apache/harmony/security/tests/java/security/cert/X509CertSelectorTest.java Sun Jul 9 23:14:15 2006 @@ -0,0 +1,44 @@ +/* + * Copyright 2006 The Apache Software Foundation or its licensors, as applicable. + * + * 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 org.apache.harmony.security.tests.java.security.cert; + +import java.io.IOException; +import java.security.cert.X509CertSelector; + +import junit.framework.TestCase; + +/** + * X509CertSelectorTest + */ +public class X509CertSelectorTest extends TestCase { + + /** + * @tests addSubjectAlternativeName(int type, String name) + */ + public void testAddSubjectAlternativeName() { + // Regression for HARMONY-727 + int[] types = { 0, 2, 3, 4, 5, 6, 7, 8 }; + for (int i = 0; i < types.length; i++) { + try { + new X509CertSelector().addSubjectAlternativeName(types[i], + "0xDFRF"); + fail("IOException expected"); + } catch (IOException e) { + } + } + } +} Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/x509/GeneralNameTest.java URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/x509/GeneralNameTest.java?rev=420433&r1=420432&r2=420433&view=diff ============================================================================== --- incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/x509/GeneralNameTest.java (original) +++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/impl/java/org/apache/harmony/security/tests/x509/GeneralNameTest.java Sun Jul 9 23:14:15 2006 @@ -21,9 +21,9 @@ package org.apache.harmony.security.tests.x509; -import junit.framework.Test; +import java.io.IOException; + import junit.framework.TestCase; -import junit.framework.TestSuite; import org.apache.harmony.security.x501.Name; import org.apache.harmony.security.x509.EDIPartyName; @@ -40,13 +40,13 @@ public void testGeneralName() { try { - GeneralName san0 = + GeneralName san0 = new GeneralName(new OtherName("1.2.3.4.5", new byte[] {1, 2, 0, 1})); GeneralName san1 = new GeneralName(1, "rfc@822.Name"); GeneralName san2 = new GeneralName(2, "dNSName"); GeneralName san3 = new GeneralName(new ORAddress()); GeneralName san4 = new GeneralName(new Name("O=Organization")); - GeneralName san5 = + GeneralName san5 = new GeneralName(new EDIPartyName("assigner", "party")); GeneralName san6 = new GeneralName(6, "http://uniform.Resource.Id"); GeneralName san7 = new GeneralName(7, "1.1.1.1"); @@ -66,15 +66,15 @@ byte[] encoding = GeneralNames.ASN1.encode(sans_1); GeneralNames.ASN1.decode(encoding); } catch (Exception e) { - // should not be thrown: + // should not be thrown: // provided string representations are correct e.printStackTrace(); } } - + public void testGeneralName1() { try { - OtherName on = + OtherName on = new OtherName("1.2.3.4.5", new byte[] {1, 2, 0, 1}); byte[] encoding = OtherName.ASN1.encode(on); new GeneralName(0, encoding); @@ -87,14 +87,119 @@ fail(e.getMessage()); } } - - - public static Test suite() { - return new TestSuite(GeneralNameTest.class); + + /** + * ipStrToBytes method testing. + */ + public void testIpStrToBytes() throws Exception { + // Regression for HARMONY-727 + Object[][] positives = { + {"010a:020b:3337:1000:FFFA:ABCD:9999:0000", + new int[] {0x01, 0x0a, 0x02, 0x0b, 0x33, 0x37, 0x10, 0x00, 0xFF, + 0xFA, 0xAB, 0xCD, 0x99, 0x99, 0x00, 0x00}}, + {"010a:020b:3337:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + new int[] {0x01, 0x0a, 0x02, 0x0b, 0x33, 0x37, 0x10, 0x00, 0xFF, + 0xFA, 0xAB, 0xCD, 0x99, 0x99, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0b, 0x0c, 0x0D, + 0x0e, 0x0f, 0x10}}, + {"010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + new int[] {0x01, 0x0a, 0x02, 0x0b, 0x11, 0x33, 0x10, 0x00, 0xFF, + 0xFA, 0xAB, 0xCD, 0x99, 0x99, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0b, 0x0c, 0x0D, + 0x0e, 0x0f, 0x10}}, + {"010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + new int[] {0x01, 0x0a, 0x02, 0x0b, 0x11, 0x33, 0x10, 0x00, 0xFF, + 0xFA, 0xAB, 0xCD, 0x99, 0x99, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0b, 0x0c, 0x0D, + 0x0e, 0x0f, 0x10}}, + {"100.2.35.244", + new int[] {100, 2, 35, 244}}, + {"100.2.35.244/51.6.79.118", + new int[] {100, 2, 35, 244, 51, 6, 79, 118}}, + }; + String[] negatives = { + "010a:0000:3333:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0", + "010a:020b:3:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:33:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:333:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:1133:10V0:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:1133:1000-FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:1133:1000:FFFA:ABCD:9999", + "010a:020b:1133:1000:FFFA:ABCD:9999/0000:0102:0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000:0102/0304:0506:0708:090A:0b0c:0D0e:0f10", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e:0f10:1234", + "100.2.35.244/51.6.79.118.119", + "100.2.35.244.115/79.118.119", + "100.2.35.244/79.118.119.1167", + "100.2.35.244/79.118.119.116.7", + "100.2.35.244.79/118.119.116.7", + "100.2.35/79/118.119.116.7", + "100.2.35.79/118/119.116.7", + "100.2..35.79/118/119.116.7", + "100.2.a.35.79/118/119.116.7", + "100.2.35.79/119.116.7-1", + "100.2.35.244.111", + "100.2.35.244/111", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e0f10", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102:0304:0506:0708:090A:0b0c:0D0e0f:10", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102/0304:0506:0708:090A:0b0c:0D0e0f:10", + "010a:020b:1133:1000:FFFA:ABCD:9999:0000/0102030405060708090A0b0c:0D0e:0f10:ffff", + "010a:020b:1133:1000:FFFA:ABCD:9999:00000102030405060708090A/0b0c:0D0e:0f10:ffff", + }; + for (int i=0; i