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 libcore.util.Objects;
     26 
     27 
     28 /**
     29  * Encodes ASN.1 types with DER (X.690)
     30  *
     31  * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
     32  */
     33 public final class DerOutputStream extends BerOutputStream {
     34     private static final int initSize = 32;
     35     private int index;
     36     private int[][] len = new int[initSize][];
     37     private Object[][] val = new Object[initSize][];
     38 
     39     public DerOutputStream(ASN1Type asn1, Object object) {
     40         content = object;
     41         index = -1;
     42         asn1.setEncodingContent(this);
     43         encoded = new byte[asn1.getEncodedLength(this)];
     44         index = 0;
     45         asn1.encodeASN(this);
     46     }
     47 
     48     @Override public void encodeChoice(ASN1Choice choice) {
     49         ASN1Type type = (ASN1Type) val[index][0];
     50         content = val[index][1];
     51         index++;
     52         type.encodeASN(this);
     53     }
     54 
     55     @Override public void encodeExplicit(ASN1Explicit explicit) {
     56         content = val[index][0];
     57         length = len[index][0];
     58         index++;
     59         explicit.type.encodeASN(this);
     60     }
     61 
     62     @Override public void encodeSequence(ASN1Sequence sequence) {
     63         ASN1Type[] type = sequence.type;
     64 
     65         Object[] values = val[index];
     66         int[] compLens = len[index];
     67 
     68         index++;
     69         for (int i = 0; i < type.length; i++) {
     70             if (values[i] == null) {
     71                 continue;
     72             }
     73 
     74             content = values[i];
     75             length = compLens[i];
     76 
     77             type[i].encodeASN(this);
     78         }
     79     }
     80 
     81     @Override public void encodeSequenceOf(ASN1SequenceOf sequenceOf) {
     82         encodeValueCollection(sequenceOf);
     83     }
     84 
     85     @Override public void encodeSetOf(ASN1SetOf setOf) {
     86         encodeValueCollection(setOf);
     87     }
     88 
     89     private void encodeValueCollection(ASN1ValueCollection collection) {
     90         Object[] values = val[index];
     91         int[] compLens = len[index];
     92 
     93         index++;
     94         for (int i = 0; i < values.length; i++) {
     95             content = values[i];
     96             length = compLens[i];
     97             collection.type.encodeASN(this);
     98         }
     99     }
    100 
    101     private void push(int[] lengths, Object[] values) {
    102         index++;
    103         if (index == val.length) {
    104 
    105             int[][] newLen = new int[val.length * 2][];
    106             System.arraycopy(len, 0, newLen, 0, val.length);
    107             len = newLen;
    108 
    109             Object[][] newVal = new Object[val.length * 2][];
    110             System.arraycopy(val, 0, newVal, 0, val.length);
    111             val = newVal;
    112         }
    113         len[index] = lengths;
    114         val[index] = values;
    115     }
    116 
    117     @Override public void getChoiceLength(ASN1Choice choice) {
    118         int i = choice.getIndex(content);
    119         content = choice.getObjectToEncode(content);
    120 
    121         Object[] values = new Object[] { choice.type[i], content };
    122 
    123         push(null, values);
    124 
    125         choice.type[i].setEncodingContent(this);
    126 
    127         // in case if we get content bytes while getting its length
    128         // FIXME what about remove it: need redesign
    129         values[1] = content;
    130     }
    131 
    132     @Override public void getExplicitLength(ASN1Explicit explicit) {
    133         Object[] values = new Object[1];
    134         int[] compLens = new int[1];
    135 
    136         values[0] = content;
    137 
    138         push(compLens, values);
    139 
    140         explicit.type.setEncodingContent(this);
    141 
    142         // in case if we get content bytes while getting its length
    143         // FIXME what about remove it: need redesign
    144         values[0] = content;
    145         compLens[0] = length;
    146 
    147         length = explicit.type.getEncodedLength(this);
    148     }
    149 
    150     @Override public void getSequenceLength(ASN1Sequence sequence) {
    151         ASN1Type[] type = sequence.type;
    152 
    153         Object[] values = new Object[type.length];
    154         int[] compLens = new int[type.length];
    155 
    156         sequence.getValues(content, values);
    157 
    158         push(compLens, values);
    159 
    160         int seqLen = 0;
    161         for (int i = 0; i < type.length; i++) {
    162             // check optional types
    163             if (values[i] == null) {
    164                 if (sequence.OPTIONAL[i]) {
    165                     continue;
    166                 } else {
    167                     throw new RuntimeException();//FIXME type & message
    168                 }
    169             }
    170 
    171             if (Objects.equal(sequence.DEFAULT[i], values[i])) {
    172                 values[i] = null;
    173                 continue;
    174             }
    175 
    176             content = values[i];
    177 
    178             type[i].setEncodingContent(this);
    179 
    180             compLens[i] = length;
    181 
    182             // in case if we get content bytes while getting its length
    183             // FIXME what about remove it: need redesign
    184             values[i] = content;
    185 
    186             seqLen += type[i].getEncodedLength(this);
    187         }
    188         length = seqLen;
    189     }
    190 
    191     @Override public void getSequenceOfLength(ASN1SequenceOf sequence) {
    192         getValueOfLength(sequence);
    193     }
    194 
    195     @Override public void getSetOfLength(ASN1SetOf setOf) {
    196         getValueOfLength(setOf);
    197     }
    198 
    199     private void getValueOfLength(ASN1ValueCollection collection) {
    200         //FIXME what about another way?
    201         Object[] cv = collection.getValues(content).toArray();
    202 
    203         Object[] values = new Object[cv.length];
    204         int[] compLens = new int[values.length];
    205 
    206         push(compLens, values);
    207         int seqLen = 0;
    208         for (int i = 0; i < values.length; i++) {
    209 
    210             content = cv[i];
    211 
    212             collection.type.setEncodingContent(this);
    213 
    214             compLens[i] = length;
    215 
    216             // in case if we get content bytes while getting its length
    217             // FIXME what about remove it: need redesign
    218             values[i] = content;
    219 
    220             seqLen += collection.type.getEncodedLength(this);
    221         }
    222         length = seqLen;
    223     }
    224 }
    225