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 import libcore.util.EmptyArray;
     27 
     28 /**
     29  * This class represents ASN.1 Bitstring type.
     30  *
     31  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     32  */
     33 public class ASN1BitString extends ASN1StringType {
     34 
     35     // default implementation
     36     private static final ASN1BitString ASN1 = new ASN1BitString();
     37 
     38     /**
     39      * Constructs ASN.1 Bitstring type
     40      *
     41      * The constructor is provided for inheritance purposes
     42      * when there is a need to create a custom ASN.1 Bitstring type.
     43      * To get a default implementation it is recommended to use
     44      * getInstance() method.
     45      */
     46     public ASN1BitString() {
     47         super(TAG_BITSTRING);
     48     }
     49 
     50     /**
     51      * Returns ASN.1 Bitstring type default implementation
     52      *
     53      * The default implementation works with encoding
     54      * that is represented as BitString object.
     55      *
     56      * @return ASN.1 Bitstring type default implementation
     57      * @see org.apache.harmony.security.asn1.BitString
     58      */
     59     public static ASN1BitString getInstance() {
     60         return ASN1;
     61     }
     62 
     63     @Override public Object decode(BerInputStream in) throws IOException {
     64         in.readBitString();
     65 
     66         if (in.isVerify) {
     67             return null;
     68         }
     69         return getDecodedObject(in);
     70     }
     71 
     72     /**
     73      * Extracts BitString object from BER input stream.
     74      *
     75      * @param in - BER input stream
     76      * @return BitString object
     77      */
     78     @Override public Object getDecodedObject(BerInputStream in) throws IOException {
     79         byte[] bytes = new byte[in.length - 1];
     80         System.arraycopy(in.buffer, in.contentOffset + 1, bytes, 0,
     81                 in.length - 1);
     82         return new BitString(bytes, in.buffer[in.contentOffset]);
     83     }
     84 
     85     @Override public void encodeContent(BerOutputStream out) {
     86         out.encodeBitString();
     87     }
     88 
     89     @Override public void setEncodingContent(BerOutputStream out) {
     90         out.length = ((BitString) out.content).bytes.length + 1;
     91     }
     92 
     93     /**
     94      * Default implementation for ASN.1 Named Bitstring type
     95      *
     96      * The default implementation works with encoding
     97      * that is mapped to array of boolean.
     98      */
     99     public static class ASN1NamedBitList extends ASN1BitString {
    100         private static final byte[] SET_MASK = { (byte) 128, 64, 32, 16, 8, 4, 2, 1};
    101         private static final BitString emptyString = new BitString(EmptyArray.BYTE, 0);
    102         private static final int INDEFINITE_SIZE = -1;
    103 
    104         private final int minBits;
    105         private final int maxBits;
    106 
    107         public ASN1NamedBitList(int minBits) {
    108             this.minBits = minBits;
    109             this.maxBits = INDEFINITE_SIZE;
    110         }
    111 
    112         @Override public Object getDecodedObject(BerInputStream in) throws IOException {
    113             boolean[] value;
    114 
    115             int unusedBits = in.buffer[in.contentOffset];
    116             int bitsNumber = (in.length - 1) * 8 - unusedBits;
    117 
    118             if (maxBits == INDEFINITE_SIZE) {
    119                 if (minBits == INDEFINITE_SIZE) {
    120                     value = new boolean[bitsNumber];
    121                 } else {
    122                     if (bitsNumber > minBits) {
    123                         value = new boolean[bitsNumber];
    124                     } else {
    125                         value = new boolean[minBits];
    126                     }
    127                 }
    128             } else {
    129                 if (bitsNumber > maxBits) {
    130                     throw new ASN1Exception("ASN.1 Named Bitstring: size constraints");
    131                 }
    132                 value = new boolean[maxBits];
    133             }
    134 
    135             if (bitsNumber == 0) {
    136                 // empty bit string
    137                 return value;
    138             }
    139 
    140             int i = 1;
    141             int j = 0;
    142             byte octet = in.buffer[in.contentOffset + i];
    143             for (int size = in.length - 1; i < size; i++) {
    144                 for (int k = 0; k < 8; k++, j++) {
    145                     value[j] = (SET_MASK[k] & octet) != 0;
    146                 }
    147                 i++;
    148                 octet = in.buffer[in.contentOffset + i];
    149             }
    150 
    151             // final octet
    152             for (int k = 0; k < (8 - unusedBits); k++, j++) {
    153                 value[j] = (SET_MASK[k] & octet) != 0;
    154             }
    155 
    156             return value;
    157         }
    158 
    159         @Override public void setEncodingContent(BerOutputStream out) {
    160             boolean[] toEncode = (boolean[]) out.content;
    161 
    162             int index = toEncode.length - 1;
    163             while (index > -1 && !toEncode[index]) {
    164                 index--;
    165             }
    166 
    167             if (index == -1) {
    168                 out.content = emptyString;
    169                 out.length = 1;
    170             } else {
    171                 int unusedBits = 7 - index % 8;
    172                 byte[] bytes = new byte[index / 8 + 1];
    173 
    174                 int j = 0;
    175                 index = bytes.length - 1;
    176                 for (int i = 0; i < index; i++) {
    177                     for (int k = 0; k < 8; k++, j++) {
    178                         if (toEncode[j]) {
    179                             bytes[i] = (byte) (bytes[i] | SET_MASK[k]);
    180                         }
    181                     }
    182                 }
    183 
    184                 //final octet
    185                 for (int k = 0; k < (8 - unusedBits); k++, j++) {
    186                     if (toEncode[j]) {
    187                         bytes[index] = (byte) (bytes[index] | SET_MASK[k]);
    188                     }
    189                 }
    190 
    191                 out.content = new BitString(bytes, unusedBits);
    192                 out.length = bytes.length + 1;
    193             }
    194         }
    195     }
    196 }
    197