Home | History | Annotate | Download | only in asn1
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  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,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 /**
     19 * @author Stepan M. Mishura
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.asn1;
     24 
     25 import java.util.Arrays;
     26 
     27 /**
     28  * Instance of this class represents ObjectIdentifier (OID).
     29  *
     30  * According to X.690:
     31  * OID is represented as a sequence of subidentifier.
     32  * Each subidentifier is represented as non negative integer value.
     33  * There are at least 2 subidentifiers in the sequence.
     34  *
     35  * Valid values for first subidentifier are 0, 1 and 2.
     36  * If the first subidentifier has 0 or 1 value the second
     37  * subidentifier must be less then 40.
     38  *
     39  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     40  */
     41 
     42 public final class ObjectIdentifier {
     43 
     44     // OID as array of integers
     45     private final int[] oid;
     46 
     47     // OID as string
     48     private String soid;
     49 
     50     /**
     51      * Creates ObjectIdentifier(OID) from array of integers.
     52      *
     53      * @param oid - array of integers
     54      * @throws IllegalArgumentException - if oid is invalid or null
     55      */
     56     public ObjectIdentifier(int[] oid) {
     57         validate(oid);
     58         this.oid = oid;
     59     }
     60 
     61     /**
     62      * Creates ObjectIdentifier(OID) from string representation.
     63      *
     64      * @param strOid - oid string
     65      * @throws IllegalArgumentException - if oid string is invalid or null
     66      */
     67     public ObjectIdentifier(String strOid) {
     68         this.oid = toIntArray(strOid);
     69         this.soid = strOid;
     70     }
     71 
     72     /**
     73      * Returns array of integers.
     74      *
     75      * @return array of integers
     76      */
     77     public int[] getOid() {
     78         return oid;
     79     }
     80 
     81     /**
     82      * Compares object with OID for equality.
     83      *
     84      * @return true if object is ObjectIdentifier and it has the same
     85      *         representation as array of integers, otherwise false
     86      */
     87     public boolean equals(Object o) {
     88         if (this == o) {
     89             return true;
     90         }
     91         if (o == null || this.getClass() != o.getClass()) {
     92             return false;
     93         }
     94         return Arrays.equals(oid, ((ObjectIdentifier) o).oid);
     95     }
     96 
     97     /**
     98      * @see java.lang.Object#toString()
     99      */
    100     public String toString() {
    101         if (soid == null) {
    102             soid = toString(oid);
    103         }
    104         return soid;
    105     }
    106 
    107     /**
    108      * @see java.lang.Object#hashCode()
    109      */
    110     public int hashCode() {
    111         // FIXME change me to Arrays.hashCode(int[])
    112         int intHash = 0;
    113         for (int i = 0; i < oid.length && i < 4; i++) {
    114             intHash += oid[i] << (8 * i); //TODO what about to find better one?
    115         }
    116         return intHash & 0x7FFFFFFF; // only positive
    117     }
    118 
    119     /**
    120      * Validates ObjectIdentifier (OID).
    121      *
    122      * @param oid - oid as array of integers
    123      * @throws IllegalArgumentException - if oid is invalid or null
    124      */
    125     public static void validate(int[] oid) {
    126 
    127         if (oid == null) {
    128             throw new IllegalArgumentException("oid == null");
    129         }
    130 
    131         if (oid.length < 2) {
    132             throw new IllegalArgumentException("OID MUST have at least 2 subidentifiers");
    133         }
    134 
    135         if (oid[0] > 2) {
    136             throw new IllegalArgumentException("Valid values for first subidentifier are 0, 1 and 2");
    137         } else if (oid[0] != 2 && oid[1] > 39) {
    138             throw new IllegalArgumentException("If the first subidentifier has 0 or 1 value the second subidentifier value MUST be less than 40");
    139         }
    140 
    141         for (int i = 0; i < oid.length; i++) {
    142             if (oid[i] < 0) {
    143                 throw new IllegalArgumentException("Subidentifier MUST have positive value");
    144             }
    145         }
    146     }
    147 
    148     // FIXME: implement me
    149     //    /**
    150     //     * Validates ObjectIdentifier (OID).
    151     //     *
    152     //     * @param oid - oid as string
    153     //     * @throws IllegalArgumentException - if oid string  is invalid or null
    154     //     */
    155     //    public static void validate(String oid) {
    156     //
    157     //        if (oid == null) {
    158     //            throw new NullPointerException();
    159     //        }
    160     //
    161     //        int length = oid.length();
    162     //        if (length < 3 || oid.charAt(1) != '.') {
    163     //            throw new IllegalArgumentException("Invalid oid string");
    164     //        }
    165     //
    166     //        int pos = 2;
    167     //        int subidentifier = 0;
    168     //        switch (oid.charAt(0)) {
    169     //        case '0':
    170     //        case '1':
    171     //            for (char c = oid.charAt(pos);;) {
    172     //                if (c < '0' || c > '9') {
    173     //                    throw new IllegalArgumentException("Invalid oid string");
    174     //                } else {
    175     //                    subidentifier = subidentifier * 10 + c - '0';
    176     //                }
    177     //
    178     //                pos++;
    179     //                if (pos == length) {
    180     //                    break;
    181     //                }
    182     //
    183     //                c = oid.charAt(pos);
    184     //                if (c == '.') {
    185     //                    pos++;
    186     //                    if (pos == length) {
    187     //                        throw new IllegalArgumentException("Invalid oid string");
    188     //                    }
    189     //                    break;
    190     //                }
    191     //            }
    192     //
    193     //            if (subidentifier > 39) {
    194     //                throw new IllegalArgumentException(
    195     //                        "If the first subidentifier has 0 or 1 value the second "
    196     //                                + "subidentifier value MUST be less then 40.");
    197     //            }
    198     //            break;
    199     //        case '2':
    200     //            break;
    201     //        default:
    202     //            throw new IllegalArgumentException(
    203     //                    "Valid values for first subidentifier are 0, 1 and 2");
    204     //        }
    205     //
    206     //        if (pos == length) {
    207     //            return;
    208     //        }
    209     //
    210     //        for (char c = oid.charAt(pos);;) {
    211     //            if (c < '0' || c > '9') {
    212     //                throw new IllegalArgumentException("Invalid oid string");
    213     //            }
    214     //
    215     //            pos++;
    216     //            if (pos == length) {
    217     //                return;
    218     //            }
    219     //
    220     //            c = oid.charAt(pos);
    221     //            if (c == '.') {
    222     //                pos++;
    223     //                if (pos == length) {
    224     //                    throw new IllegalArgumentException("Invalid oid string");
    225     //                }
    226     //            }
    227     //        }
    228     //    }
    229 
    230     /**
    231      * Returns string representation of OID.
    232      *
    233      * Note: it is supposed that passed array of integers
    234      * contains valid OID value, so no checks are performed.
    235      *
    236      * @param oid - oid as array of integers
    237      * @return oid string representation
    238      */
    239     public static String toString(int[] oid) {
    240         StringBuilder sb = new StringBuilder(3 * oid.length);
    241 
    242         for (int i = 0; i < oid.length - 1; ++i) {
    243             sb.append(oid[i]);
    244             sb.append('.');
    245         }
    246         sb.append(oid[oid.length - 1]);
    247         return sb.toString();
    248     }
    249 
    250     // BEGIN android-changed
    251     /**
    252      * Gets ObjectIdentifier (OID) from string representation.
    253      *
    254      * String representation is defined by the following syntax:
    255      *     OID = subidentifier 1*("." subidentifier)
    256      *     subidentifier = 1*(digit)
    257      *
    258      * @param oidString -  string representation of OID
    259      * @return - oid as array of integers
    260      * @throws IllegalArgumentException - if oid string is invalid or null
    261      */
    262     public static int[] toIntArray(String str) {
    263         return toIntArray(str, true);
    264     }
    265 
    266     /**
    267      * Returns whether the given string is a valid ObjectIdentifier
    268      * (OID) representation.
    269      *
    270      * String representation is defined as for {@link #toIntArray}.
    271      *
    272      * @param oidString -  string representation of OID
    273      * @return true if oidString has valid syntax or false if not
    274      */
    275     public static boolean isOID(String str) {
    276         return toIntArray(str, false) != null;
    277     }
    278 
    279     /**
    280      * Gets ObjectIdentifier (OID) from string representation.
    281      *
    282      * String representation is defined by the following syntax:
    283      *     OID = subidentifier 1*("." subidentifier)
    284      *     subidentifier = 1*(digit)
    285      *
    286      * @param oidString -  string representation of OID
    287      * @return - oid as array of integers or null if the oid string is
    288      * invalid or null and shouldThrow is false
    289      * @throws IllegalArgumentException - if oid string is invalid or null and
    290      * shouldThrow is true
    291      */
    292     private static int[] toIntArray(String str, boolean shouldThrow) {
    293         if (str == null) {
    294             if (! shouldThrow) {
    295                 return null;
    296             }
    297             throw new IllegalArgumentException();
    298         }
    299 
    300         int length = str.length();
    301         if (length == 0) {
    302             if (! shouldThrow) {
    303                 return null;
    304             }
    305             throw new IllegalArgumentException("Incorrect syntax");
    306         }
    307 
    308         int count = 1; // number of subidentifiers
    309         boolean wasDot = true; // indicates whether char before was dot or not.
    310         char c; // current char
    311         for (int i = 0; i < length; i++) {
    312             c = str.charAt(i);
    313             if (c == '.') {
    314                 if (wasDot) {
    315                     if (! shouldThrow) {
    316                         return null;
    317                     }
    318                     throw new IllegalArgumentException("Incorrect syntax");
    319                 }
    320                 wasDot = true;
    321                 count++;
    322             } else if (c >= '0' && c <= '9') {
    323                 wasDot = false;
    324             } else {
    325                 if (! shouldThrow) {
    326                     return null;
    327                 }
    328                 throw new IllegalArgumentException("Incorrect syntax");
    329             }
    330         }
    331 
    332         if (wasDot) {
    333             // the last char is dot
    334             if (! shouldThrow) {
    335                 return null;
    336             }
    337             throw new IllegalArgumentException("Incorrect syntax");
    338         }
    339 
    340         if (count < 2) {
    341             if (! shouldThrow) {
    342                 return null;
    343             }
    344             throw new IllegalArgumentException("Incorrect syntax");
    345         }
    346 
    347         int[] oid = new int[count];
    348         for (int i = 0, j = 0; i < length; i++) {
    349             c = str.charAt(i);
    350             if (c == '.') {
    351                 j++;
    352             } else {
    353                 oid[j] = oid[j] * 10 + c - 48; // '0' = 48
    354             }
    355         }
    356 
    357         if (oid[0] > 2) {
    358             if (! shouldThrow) {
    359                 return null;
    360             }
    361             throw new IllegalArgumentException("Incorrect syntax");
    362         } else if (oid[0] != 2 && oid[1] > 39) {
    363             if (! shouldThrow) {
    364                 return null;
    365             }
    366             throw new IllegalArgumentException("Incorrect syntax");
    367         }
    368 
    369         return oid;
    370     }
    371     // END android-changed
    372 }
    373