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