You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by sm...@apache.org on 2006/05/30 11:34:25 UTC

svn commit: r410233 - in /incubator/harmony/enhanced/classlib/trunk/modules/security/src: main/java/common/org/apache/harmony/security/asn1/ test/java/common/org/apache/harmony/security/asn1/der/

Author: smishura
Date: Tue May 30 02:34:24 2006
New Revision: 410233

URL: http://svn.apache.org/viewvc?rev=410233&view=rev
Log:
Improved verification of provided identifiers for choice type. Adding regression tests.

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Choice.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Set.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Type.java
    incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java   (contents, props changed)

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Choice.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Choice.java?rev=410233&r1=410232&r2=410233&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Choice.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Choice.java Tue May 30 02:34:24 2006
@@ -21,6 +21,10 @@
 package org.apache.harmony.security.asn1;
 
 import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.TreeMap;
 
 
 /**
@@ -206,11 +210,18 @@
 
     public final ASN1Type[] type;
 
+    // identifiers table: [2][number of distinct identifiers]
+    // identifiers[0]: stores identifiers (includes nested choices)
+    // identifiers[1]: stores identifiers' indexes in array of types
+    private final int[][] identifiers;
+
     /**
      * Constructs ASN.1 choice type.
      * 
-     * @param type - an array of one or more ASN.1 type alternatives. 
-     * @throws IllegalArgumentException - type parameter is invalid
+     * @param type -
+     *            an array of one or more ASN.1 type alternatives.
+     * @throws IllegalArgumentException -
+     *             type parameter is invalid
      */
     public ASN1Choice(ASN1Type[] type) {
         super(TAG_CHOICE); // has not tag number
@@ -221,15 +232,61 @@
                     + " MUST have at least one alternative");
         }
 
-        if (!hasDistinctTags(type)) {
-            throw new RuntimeException("ASN.1 choice type: "
-                    + getClass().getName()
-                    + " MUST have alternatives with distinct tags");
+        // create map of all identifiers
+        TreeMap map = new TreeMap();
+        for (int index = 0; index < type.length; index++) {
+
+            ASN1Type t = type[index];
+
+            if (t instanceof ASN1Any) {
+                // ASN.1 ANY is not allowed,
+                // even it is a single component (not good for nested choices)
+                throw new IllegalArgumentException("ASN.1 choice type: "
+                        + getClass().getName() // FIXME name
+                        + " MUST have alternatives with distinct tags");
+            } else if (t instanceof ASN1Choice) {
+
+                // add all choice's identifiers
+                int[][] choiceToAdd = ((ASN1Choice) t).identifiers;
+                for (int j = 0; j < choiceToAdd[0].length; j++) {
+                    addIdentifier(map, choiceToAdd[0][j], index);
+                }
+                continue;
+            }
+
+            // add primitive identifier
+            if (t.checkTag(t.id)) {
+                addIdentifier(map, t.id, index);
+            }
+
+            // add constructed identifier
+            if (t.checkTag(t.constrId)) {
+                addIdentifier(map, t.constrId, index);
+            }
+        }
+
+        // fill identifiers array
+        int size = map.size();
+        identifiers = new int[2][size];
+        Iterator it = map.keySet().iterator();
+        for (int i = 0; i < size; i++) {
+            BigInteger identifier = (BigInteger) it.next();
+
+            identifiers[0][i] = identifier.intValue();
+            identifiers[1][i] = ((BigInteger) map.get(identifier)).intValue();
         }
 
         this.type = type;
     }
 
+    private void addIdentifier(TreeMap map, int identifier, int index){
+        if (map.put(BigInteger.valueOf(identifier), BigInteger.valueOf(index)) != null) {
+            throw new IllegalArgumentException("ASN.1 choice type: "
+                    + getClass().getName() // FIXME name
+                    + " MUST have alternatives with distinct tags");
+        }
+    }
+    
     //
     //
     // DECODE
@@ -238,40 +295,43 @@
 
     /**
      * Tests whether one of choice alternatives has the same identifier or not.
-     *
-     * @param identifier - ASN.1 identifier to be verified
+     * 
+     * @param identifier -
+     *            ASN.1 identifier to be verified
      * @return - true if one of choice alternatives has the same identifier,
-     *           otherwise false;
+     *         otherwise false;
      */
     public final boolean checkTag(int identifier) {
-        for (int i = 0; i < type.length; i++) {
-            if (type[i].checkTag(identifier)) {
-                return true;
-            }
-        }
-        return false;
+        return Arrays.binarySearch(identifiers[0], identifier) >= 0;
     }
 
     public Object decode(BerInputStream in) throws IOException {
-        
-        for (int index = 0; index < type.length; index++) {
-            if (type[index].checkTag(in.tag)) {
 
-                in.content = type[index].decode(in);
+        int index = Arrays.binarySearch(identifiers[0], in.tag);
+        if (index < 0) {
+            throw new ASN1Exception("Failed to decode ASN.1 choice type. " // FIXME
+                                                                            // message
+                    + " No alternatives were found for " + getClass().getName());
+        }
 
-                // set index for getDecodedObject method
-                in.choiceIndex = index;
+        index = identifiers[1][index];
 
-                return getDecodedObject(in);
-            }
+        in.content = type[index].decode(in);
+
+        // set index for getDecodedObject method
+        in.choiceIndex = index;
+
+        if (in.isVerify) {
+            return null;
         }
-        throw new ASN1Exception("Failed to decode ASN.1 choice type. "
-                + " No alternatives were found for " + getClass().getName());
+        return getDecodedObject(in);
     }
+    
     /**
      * Extracts chosen object from BER input stream.
-     *
-     * @param in - decoding input stream
+     * 
+     * @param in -
+     *            decoding input stream
      * @return object that represents this choice
      */
     public Object getDecodedObject(BerInputStream in) throws IOException {

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Set.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Set.java?rev=410233&r1=410232&r2=410233&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Set.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Set.java Tue May 30 02:34:24 2006
@@ -35,10 +35,11 @@
     public ASN1Set(ASN1Type[] type) {
         super(TAG_SET, type);
 
-        if (!hasDistinctTags(type)) {
-            throw new RuntimeException("ASN1 set type: " + getClass().getName()
-                    + " MUST have alternatives with distinct tags");
-        }
+        //FIXME implement check for distinct tags
+        //if (!hasDistinctTags(type)) {
+        //    throw new RuntimeException("ASN1 set type: " + getClass().getName()
+        //            + " MUST have alternatives with distinct tags");
+        //}
     }
 
     //

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Type.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Type.java?rev=410233&r1=410232&r2=410233&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Type.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/main/java/common/org/apache/harmony/security/asn1/ASN1Type.java Tue May 30 02:34:24 2006
@@ -85,41 +85,6 @@
         this.constrId = this.id + PC_CONSTRUCTED;
     }
 
-    /**
-     * Tests whether ASN.1 type alternatives in
-     * provided array have distinct tags ot not
-     *
-     * @param type - an array of ASN.1 types
-     * @return - true if alternatives have distinct tags, otherwise false
-     */
-    public static boolean hasDistinctTags(ASN1Type[] type) {
-
-        for (int i = 0; i < type.length; i++) {
-
-            if ((type[i] instanceof ASN1Choice) || (type[i] instanceof ASN1Any)) {
-                return false;
-            }
-
-            int curTag = type[i].id;
-            for (int j = i + 1; j < type.length; j++) {
-                if (type[j].checkTag(curTag)) {
-                    return false;
-                }
-            }
-        }
-
-        if (type[0] instanceof ASN1StringType) {
-            int curTag = type[0].constrId;
-            for (int j = 1; j < type.length; j++) {
-                if (type[j].checkTag(curTag)) {
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
     //
     //
     // Stubs for DER

Modified: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java?rev=410233&r1=410232&r2=410233&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java Tue May 30 02:34:24 2006
@@ -27,17 +27,21 @@
 import java.util.Collection;
 import java.util.List;
 
+import junit.framework.TestCase;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1BitString;
 import org.apache.harmony.security.asn1.ASN1Boolean;
 import org.apache.harmony.security.asn1.ASN1Choice;
 import org.apache.harmony.security.asn1.ASN1Explicit;
 import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Oid;
 import org.apache.harmony.security.asn1.ASN1SequenceOf;
 import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
 import org.apache.harmony.security.asn1.DerInputStream;
 import org.apache.harmony.security.asn1.DerOutputStream;
 
-import junit.framework.TestCase;
-
 
 /**
  * ASN.1 DER test for Choice type
@@ -84,17 +88,17 @@
     // Test Cases
     //
 
-    private static Object[][] testcases = new Object[][] {
+    private static Object[][] testcases = {
             // format: object to encode / byte array 
 
             // choice = Boolean (false)
-            new Object[] { Boolean.FALSE, new byte[] { 0x01, 0x01, 0x00 } },
+            { Boolean.FALSE, new byte[] { 0x01, 0x01, 0x00 } },
 
             // choice = Boolean (true)
-            new Object[] { Boolean.TRUE, new byte[] { 0x01, 0x01, (byte) 0xFF } },
+            { Boolean.TRUE, new byte[] { 0x01, 0x01, (byte) 0xFF } },
 
             // choice = SequenceOf (empty)
-            new Object[] { new ArrayList(), new byte[] { 0x30, 0x00 } },
+            { new ArrayList(), new byte[] { 0x30, 0x00 } },
 
     //TODO add testcase for another ASN.1 type` 
 
@@ -190,5 +194,144 @@
         encoded[4] = (byte) 0xFF;
 
         assertEquals("True: ", Boolean.TRUE, explicit.decode(encoded));
+    }
+    
+    /**
+     * TODO Put method description here
+     */
+    public void testChoiceOfChoice() throws Exception {
+
+        ASN1Choice choice1 = new ASN1Choice(new ASN1Type[] {
+                ASN1Oid.getInstance(), // first
+                ASN1Boolean.getInstance(),// second: decoded component
+                ASN1Integer.getInstance() // third
+                }) {
+
+            public Object getDecodedObject(BerInputStream in)
+                    throws IOException {
+
+                assertEquals("choice1", 1, in.choiceIndex);
+
+                return in.content;
+            }
+
+            public Object getObjectToEncode(Object obj) {
+                return obj;
+            }
+
+            public int getIndex(Object obj) {
+                return 0;
+            }
+        };
+
+        ASN1Choice choice2 = new ASN1Choice(new ASN1Type[] { choice1, // first: decoded component
+                ASN1BitString.getInstance() // second
+                }) {
+
+            public Object getDecodedObject(BerInputStream in)
+                    throws IOException {
+
+                assertEquals("choice2", 0, in.choiceIndex);
+
+                return in.content;
+            }
+
+            public Object getObjectToEncode(Object obj) {
+                return obj;
+            }
+
+            public int getIndex(Object obj) {
+                return 0;
+            }
+        };
+
+        Boolean b = (Boolean) choice2.decode(new byte[] { 0x01, 0x01, 0x00 });
+
+        assertTrue(b == Boolean.FALSE);
+    }
+
+    /**
+     * TODO Put method description here
+     */
+    public void testDistinctTags() throws Exception {
+
+        ASN1Choice choice1 = new ASN1Choice(new ASN1Type[] {
+                ASN1Boolean.getInstance(),// component to be checked
+                ASN1Oid.getInstance(), ASN1Integer.getInstance() }) {
+
+            public Object getObjectToEncode(Object obj) {
+                return obj;
+            }
+
+            public int getIndex(Object obj) {
+                return 0;
+            }
+        };
+
+        // two ASN.1 booleans
+        try {
+            new ASN1Choice(new ASN1Type[] { choice1, //
+                    ASN1Boolean.getInstance() // component to be checked
+                    }) {
+
+                public Object getObjectToEncode(Object obj) {
+                    return obj;
+                }
+
+                public int getIndex(Object obj) {
+                    return 0;
+                }
+            };
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+
+        // ASN.1 ANY
+        try {
+            new ASN1Choice(new ASN1Type[] { choice1,//
+                    ASN1Any.getInstance() // component to be checked
+                    }) {
+
+                public Object getObjectToEncode(Object obj) {
+                    return obj;
+                }
+
+                public int getIndex(Object obj) {
+                    return 0;
+                }
+            };
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+
+        // two choices
+        ASN1Choice choice2 = new ASN1Choice(new ASN1Type[] {
+                ASN1BitString.getInstance(), //
+                ASN1Boolean.getInstance() //component to be checked
+                }) {
+
+            public Object getObjectToEncode(Object obj) {
+                return obj;
+            }
+
+            public int getIndex(Object obj) {
+                return 0;
+            }
+        };
+
+        try {
+            new ASN1Choice(new ASN1Type[] { choice1, choice2 }) {
+
+                public Object getObjectToEncode(Object obj) {
+                    return obj;
+                }
+
+                public int getIndex(Object obj) {
+                    return 0;
+                }
+            };
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
     }
 }

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/security/src/test/java/common/org/apache/harmony/security/asn1/der/ChoiceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native