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 public final class ObjectIdentifier {
     42 
     43     /** OID as array of integers */
     44     private final int[] oid;
     45 
     46     /** OID as string */
     47     private String soid;
     48 
     49     /**
     50      * Creates ObjectIdentifier(OID) from array of integers.
     51      *
     52      * @param oid array of integers
     53      * @throws IllegalArgumentException if oid is invalid or null
     54      */
     55     public ObjectIdentifier(int[] oid) {
     56         validate(oid);
     57         this.oid = oid;
     58     }
     59 
     60     /**
     61      * Creates ObjectIdentifier(OID) from string representation.
     62      *
     63      * @param strOid oid string
     64      * @throws IllegalArgumentException if oid string is invalid or null
     65      */
     66     public ObjectIdentifier(String strOid) {
     67         this.oid = toIntArray(strOid);
     68         this.soid = strOid;
     69     }
     70 
     71     @Override public boolean equals(Object o) {
     72         if (this == o) {
     73             return true;
     74         }
     75         if (o == null || this.getClass() != o.getClass()) {
     76             return false;
     77         }
     78         return Arrays.equals(oid, ((ObjectIdentifier) o).oid);
     79     }
     80 
     81     @Override public String toString() {
     82         if (soid == null) {
     83             soid = toString(oid);
     84         }
     85         return soid;
     86     }
     87 
     88     @Override public int hashCode() {
     89         // FIXME change me to Arrays.hashCode(int[])
     90         int intHash = 0;
     91         for (int i = 0; i < oid.length && i < 4; i++) {
     92             intHash += oid[i] << (8 * i); //TODO what about to find better one?
     93         }
     94         return intHash & 0x7FFFFFFF; // only positive
     95     }
     96 
     97     /**
     98      * Validates ObjectIdentifier (OID).
     99      *
    100      * @param oid oid as array of integers
    101      * @throws IllegalArgumentException if oid is invalid or null
    102      */
    103     public static void validate(int[] oid) {
    104         if (oid == null) {
    105             throw new IllegalArgumentException("oid == null");
    106         }
    107 
    108         if (oid.length < 2) {
    109             throw new IllegalArgumentException("OID MUST have at least 2 subidentifiers");
    110         }
    111 
    112         if (oid[0] > 2) {
    113             throw new IllegalArgumentException(
    114                     "Valid values for first subidentifier are 0, 1 and 2");
    115         } else if (oid[0] != 2 && oid[1] > 39) {
    116             throw new IllegalArgumentException("If the first subidentifier has 0 or 1 value the "
    117                     + "second subidentifier value MUST be less than 40");
    118         }
    119 
    120         for (int anOid : oid) {
    121             if (anOid < 0) {
    122                 throw new IllegalArgumentException("Subidentifier MUST have positive value");
    123             }
    124         }
    125     }
    126 
    127     /**
    128      * Returns string representation of OID.
    129      *
    130      * Note: it is supposed that passed array of integers
    131      * contains valid OID value, so no checks are performed.
    132      *
    133      * @param oid oid as array of integers
    134      * @return oid string representation
    135      */
    136     public static String toString(int[] oid) {
    137         StringBuilder sb = new StringBuilder(3 * oid.length);
    138 
    139         for (int i = 0; i < oid.length - 1; ++i) {
    140             sb.append(oid[i]);
    141             sb.append('.');
    142         }
    143         sb.append(oid[oid.length - 1]);
    144         return sb.toString();
    145     }
    146 
    147     /**
    148      * Gets ObjectIdentifier (OID) from string representation.
    149      *
    150      * String representation is defined by the following syntax:
    151      *     OID = subidentifier 1*("." subidentifier)
    152      *     subidentifier = 1*(digit)
    153      *
    154      * @param str string representation of OID
    155      * @return oid as array of integers
    156      * @throws IllegalArgumentException if oid string is invalid or null
    157      */
    158     public static int[] toIntArray(String str) {
    159         return toIntArray(str, true);
    160     }
    161 
    162     /**
    163      * Returns whether the given string is a valid ObjectIdentifier
    164      * (OID) representation.
    165      *
    166      * String representation is defined as for {@link #toIntArray}.
    167      *
    168      * @param str string representation of OID
    169      * @return true if oidString has valid syntax or false if not
    170      */
    171     public static boolean isOID(String str) {
    172         return toIntArray(str, false) != null;
    173     }
    174 
    175     /**
    176      * Gets ObjectIdentifier (OID) from string representation.
    177      *
    178      * String representation is defined by the following syntax:
    179      *     OID = subidentifier 1*("." subidentifier)
    180      *     subidentifier = 1*(digit)
    181      *
    182      * @param str string representation of OID
    183      * @return oid as array of integers or null if the oid string is
    184      * invalid or null and shouldThrow is false
    185      * @throws IllegalArgumentException if oid string is invalid or null and
    186      * shouldThrow is true
    187      */
    188     private static int[] toIntArray(String str, boolean shouldThrow) {
    189         if (str == null) {
    190             if (! shouldThrow) {
    191                 return null;
    192             }
    193             throw new IllegalArgumentException();
    194         }
    195 
    196         int length = str.length();
    197         if (length == 0) {
    198             if (! shouldThrow) {
    199                 return null;
    200             }
    201             throw new IllegalArgumentException("Incorrect syntax");
    202         }
    203 
    204         int count = 1; // number of subidentifiers
    205         boolean wasDot = true; // indicates whether char before was dot or not.
    206         char c; // current char
    207         for (int i = 0; i < length; i++) {
    208             c = str.charAt(i);
    209             if (c == '.') {
    210                 if (wasDot) {
    211                     if (! shouldThrow) {
    212                         return null;
    213                     }
    214                     throw new IllegalArgumentException("Incorrect syntax");
    215                 }
    216                 wasDot = true;
    217                 count++;
    218             } else if (c >= '0' && c <= '9') {
    219                 wasDot = false;
    220             } else {
    221                 if (! shouldThrow) {
    222                     return null;
    223                 }
    224                 throw new IllegalArgumentException("Incorrect syntax");
    225             }
    226         }
    227 
    228         if (wasDot) {
    229             // the last char is dot
    230             if (! shouldThrow) {
    231                 return null;
    232             }
    233             throw new IllegalArgumentException("Incorrect syntax");
    234         }
    235 
    236         if (count < 2) {
    237             if (! shouldThrow) {
    238                 return null;
    239             }
    240             throw new IllegalArgumentException("Incorrect syntax");
    241         }
    242 
    243         int[] oid = new int[count];
    244         for (int i = 0, j = 0; i < length; i++) {
    245             c = str.charAt(i);
    246             if (c == '.') {
    247                 j++;
    248             } else {
    249                 oid[j] = oid[j] * 10 + c - 48; // '0' = 48
    250             }
    251         }
    252 
    253         if (oid[0] > 2) {
    254             if (! shouldThrow) {
    255                 return null;
    256             }
    257             throw new IllegalArgumentException("Incorrect syntax");
    258         } else if (oid[0] != 2 && oid[1] > 39) {
    259             if (! shouldThrow) {
    260                 return null;
    261             }
    262             throw new IllegalArgumentException("Incorrect syntax");
    263         }
    264 
    265         return oid;
    266     }
    267 }
    268