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 Vladimir N. Molotkov, Stepan M. Mishura
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.asn1;
     24 
     25 import java.io.IOException;
     26 
     27 
     28 /**
     29  * This class represents ASN.1 Object Identifier type.
     30  *
     31  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     32  */
     33 
     34 public class ASN1Oid extends ASN1Primitive {
     35 
     36     // default implementation
     37     private static final ASN1Oid ASN1 = new ASN1Oid();
     38 
     39     /**
     40      * Constructs ASN.1 Object Identifier type
     41      *
     42      * The constructor is provided for inheritance purposes
     43      * when there is a need to create a custom ASN.1 Object Identifier type.
     44      * To get a default implementation it is recommended to use
     45      * getInstance() method.
     46      */
     47     public ASN1Oid() {
     48         super(TAG_OID);
     49     }
     50 
     51     /**
     52      * Returns ASN.1 Object Identifier type default implementation
     53      *
     54      * The default implementation works with encoding
     55      * that is represented as array of integers.
     56      *
     57      * @return ASN.1 Object Identifier type default implementation
     58      */
     59     public static ASN1Oid getInstance() {
     60         return ASN1;
     61     }
     62 
     63     //
     64     //
     65     // Decode
     66     //
     67     //
     68 
     69     public Object decode(BerInputStream in) throws IOException {
     70         in.readOID();
     71 
     72         if (in.isVerify) {
     73             return null;
     74         }
     75         return getDecodedObject(in);
     76     }
     77 
     78     /**
     79      * Extracts array of integers from BER input stream.
     80      *
     81      * @param in - BER input stream
     82      * @return array of integers
     83      */
     84     public Object getDecodedObject(BerInputStream in) throws IOException {
     85         // Allocate and decode
     86         int oidElement = in.oidElement;
     87         int[] oid = new int[oidElement];
     88         for (int id = 1, i = 0; id < oid.length; id++, i++) {
     89             int octet = in.buffer[in.contentOffset + i];
     90             oidElement = octet & 0x7F;
     91             while ((octet & 0x80) != 0) {
     92                 i++;
     93                 octet = in.buffer[in.contentOffset + i];
     94                 oidElement = oidElement << 7 | (octet & 0x7f);
     95             }
     96             oid[id] = oidElement;
     97         }
     98         // Special handling for the first packed OID element
     99         if (oid[1] > 79) {
    100             oid[0] = 2;
    101             oid[1] = oid[1] - 80;
    102         } else {
    103             oid[0] = oid[1] / 40;
    104             oid[1] = oid[1] % 40;
    105         }
    106         return oid;
    107     }
    108 
    109     //
    110     //
    111     // Encode
    112     //
    113     //
    114 
    115     public void encodeContent(BerOutputStream out) {
    116         out.encodeOID();
    117     }
    118 
    119     public void setEncodingContent(BerOutputStream out) {
    120         int[] oid = (int[]) out.content;
    121 
    122         int length = 0;
    123 
    124         // first subidentifier
    125         int elem = oid[0] * 40 + oid[1];
    126         if (elem == 0) {
    127             length = 1;
    128         } else {
    129             for (; elem > 0; elem = elem >> 7) {
    130                 length++;
    131             }
    132         }
    133 
    134         // the rest of subidentifiers
    135         for (int i = 2; i < oid.length; i++) {
    136             if (oid[i] == 0) {
    137                 length++;
    138                 continue;
    139             }
    140             for (elem = oid[i]; elem > 0; elem = elem >> 7) {
    141                 length++;
    142             }
    143         }
    144         out.length = length;
    145     }
    146 
    147     //
    148     //
    149     // OID encoder/decoder for mapping to string
    150     //
    151     //
    152 
    153     private final static ASN1Oid STRING_OID = new ASN1Oid() {
    154 
    155         public Object getDecodedObject(BerInputStream in) throws IOException {
    156 
    157             StringBuilder buf = new StringBuilder();
    158 
    159             int element;
    160 
    161             //Special handling for the first packed OID element
    162             int octet = in.buffer[in.contentOffset];
    163             element = octet & 0x7F;
    164 
    165             int index = 0;
    166             while ((octet & 0x80) != 0) {
    167                 index++;
    168                 octet = in.buffer[in.contentOffset + index];
    169                 element = element << 7 | (octet & 0x7F);
    170             }
    171 
    172             if (element > 79) {
    173                 buf.append('2');
    174                 buf.append('.');
    175                 buf.append(element - 80);
    176             } else {
    177                 buf.append(element / 40);
    178                 buf.append('.');
    179                 buf.append(element % 40);
    180             }
    181 
    182             // the rest of subidentifiers
    183             for (int j = 2; j < in.oidElement; j++) {
    184                 buf.append('.');
    185 
    186                 index++;
    187                 octet = in.buffer[in.contentOffset + index];
    188                 element = octet & 0x7F;
    189 
    190                 while ((octet & 0x80) != 0) {
    191                     index++;
    192                     octet = in.buffer[in.contentOffset + index];
    193                     element = element << 7 | (octet & 0x7f);
    194                 }
    195 
    196                 buf.append(element);
    197             }
    198 
    199             return buf.toString();
    200         }
    201 
    202         public void setEncodingContent(BerOutputStream out) {
    203 
    204             //FIXME this is a stub for a while
    205             out.content = ObjectIdentifier.toIntArray((String) out.content);
    206 
    207             super.setEncodingContent(out);
    208         }
    209     };
    210 
    211     /**
    212      * Returns ASN.1 Object Identifier type implementation
    213      *
    214      * This implementation works with encoding
    215      * that is mapped to java.lang.String object.
    216      *
    217      * @return ASN.1 Object Identifier type implementation
    218      */
    219     public static ASN1Oid getInstanceForString() {
    220         return STRING_OID;
    221     }
    222 }
    223