1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Vladimir N. Molotkov, Stepan M. Mishura 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @version $Revision$ 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/ 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.security.asn1; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList; 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 types encoded with BER (X.690) 32f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a> 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class BerInputStream { 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 385c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson private final InputStream in; 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected byte[] buffer; 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The position in the buffer. 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Next read must place data into the buffer from this offset 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected int offset = 0; 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 485c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * The buffer increment size. 495c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * Must be reasonable big to reallocate memory not to often. 505c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * Primary is used for decoding indefinite length encoding 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 525c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson private static final int BUF_INCREASE_SIZE = 1024 * 16; 535c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 545c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Indicates indefinite length of the current type */ 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected static final int INDEFINIT_LENGTH = -1; 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 575c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Current decoded tag */ 585c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson public int tag; 595c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 605c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Current decoded length */ 615c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson protected int length; 625c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 635c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Current decoded content */ 645c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson public Object content; 655c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 665c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Current decoded tag offset */ 675c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson protected int tagOffset; 685c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 695c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Current decoded content offset */ 705c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson protected int contentOffset; 715c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates stream for decoding. 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public BerInputStream(byte[] encoded) throws IOException { 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(encoded, 0, encoded.length); 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates stream for decoding. 81f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 825c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @param encoded bytes array to be decoded 835c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @param offset the encoding offset 845c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @param expectedLength expected length of full encoding, this includes 855c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * identifier, length an content octets 865c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson */ 875c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson public BerInputStream(byte[] encoded, int offset, int expectedLength) throws IOException { 885c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson this.in = null; 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.buffer = encoded; 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.offset = offset; 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // compare expected and decoded length 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length != INDEFINIT_LENGTH 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project && (offset + expectedLength) != (this.offset + this.length)) { 97897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong content length"); 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates stream for decoding. 103f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Allocates initial buffer of default size 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public BerInputStream(InputStream in) throws IOException { 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(in, BUF_INCREASE_SIZE); 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates stream for decoding. 112f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param initialSize the internal buffer initial size 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public BerInputStream(InputStream in, int initialSize) throws IOException { 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.in = in; 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer = new byte[initialSize]; 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length != INDEFINIT_LENGTH) { 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // input stream has definite length encoding 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check allocated length to avoid further reallocations 1242f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes if (buffer.length < (length + offset)) { 1252f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes byte[] newBuffer = new byte[length + offset]; 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project System.arraycopy(buffer, 0, newBuffer, 0, offset); 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer = newBuffer; 128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project isIndefinedLength = true; 131897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding indefinite length encoding is not supported"); 132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Resets this stream to initial state. 137f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 1385c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @param encoded a new bytes array to be decoded 1395c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @throws IOException if an error occurs 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final void reset(byte[] encoded) throws IOException { 142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer = encoded; 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes next encoded type. 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Initializes tag, length, tagOffset and contentOffset variables 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return next decoded tag 1515c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @throws IOException if error occured 152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int next() throws IOException { 154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project tagOffset = offset; 155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // read tag 157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project tag = read(); 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // read length 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = read(); 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length != 0x80) { // definite form 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // long or short length form 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if ((length & 0x80) != 0) { // long form 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int numOctets = length & 0x7F; 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (numOctets > 5) { 167897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // collect this value length 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = read(); 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 1; i < numOctets; i++) { 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int ch = read(); 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = (length << 8) + ch;//read(); 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 0xFFFFFF) { 178897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { //indefinite form 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = INDEFINIT_LENGTH; 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project contentOffset = offset; 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return tag; 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the length of the encoding 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public static int getLength(byte[] encoding) { 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int length = encoding[1] & 0xFF; 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int numOctets = 0; 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if ((length & 0x80) != 0) { // long form 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project numOctets = length & 0x7F; 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // collect this value length 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = encoding[2] & 0xFF; 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 3; i < numOctets + 2; i++) { 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project length = (length << 8) + (encoding[i] & 0xFF); 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // tag length long_form content 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return 1 + 1 + numOctets + length; 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 bitstring type 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readBitString() throws IOException { 212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag == ASN1Constants.TAG_BITSTRING) { 213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length == 0) { 215897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 Bitstring: wrong length. Tag at [" + tagOffset + "]"); 216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // content: check unused bits 221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (buffer[contentOffset] > 7) { 2225c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset 2235c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + "]. A number of unused bits MUST be in range 0 to 7"); 224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length == 1 && buffer[contentOffset] != 0) { 2275c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset 2285c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + "]. For empty string unused bits MUST be 0"); 229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (tag == ASN1Constants.TAG_C_BITSTRING) { 232897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding constructed ASN.1 bitstring type is not provided"); 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 234897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("bitstring"); 235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 Enumerated type 240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readEnumerated() throws IOException { 242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_ENUM) { 243897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("enumerated"); 244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded length 247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length == 0) { 2485c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 enumerated: wrong length for identifier at [" 2495c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + tagOffset + "]"); 250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded content 255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 1) { 256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int bits = buffer[contentOffset] & 0xFF; 257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (buffer[contentOffset + 1] < 0) { 258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project bits += 0x100; 259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (bits == 0 || bits == 0x1FF) { 2625c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 enumerated: wrong content at [" + contentOffset 2635c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + "]. An integer MUST be encoded in minimum number of octets"); 264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 boolean type 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readBoolean() throws IOException { 272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_BOOLEAN) { 273897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("boolean"); 274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded length 277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length != 1) { 278897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong length for ASN.1 boolean at [" + tagOffset + "]"); 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2845c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** The last choice index */ 285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int choiceIndex; 286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 2875c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson /** Keeps last decoded: year, month, day, hour, minute, second, millisecond */ 288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int[] times; 289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 GeneralizedTime type 292f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 2935c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @throws IOException if error occured 294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readGeneralizedTime() throws IOException { 296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag == ASN1Constants.TAG_GENERALIZEDTIME) { 297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME: any other optimizations? 298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME store string somewhere to allow a custom time type perform 300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // additional checks 301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check syntax: the last char MUST be Z 303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (buffer[offset - 1] != 'Z') { 304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME support only format that is acceptable for DER 305897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 GeneralizedTime: encoded format is not implemented"); 306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z' 3095c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson if (length != 15 && (length < 17 || length > 19)) { 3105c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at [" 3115c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + contentOffset + "]"); 312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check content: milliseconds 315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 16) { 316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte char14 = buffer[contentOffset + 14]; 317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (char14 != '.' && char14 != ',') { 3185c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at [" 3195c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson + contentOffset + "]"); 320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (times == null) { 324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times = new int[7]; 325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[0] = strToInt(contentOffset, 4); // year 327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[1] = strToInt(contentOffset + 4, 2); // month 328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[2] = strToInt(contentOffset + 6, 2); // day 329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[3] = strToInt(contentOffset + 8, 2); // hour 330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[4] = strToInt(contentOffset + 10, 2); // minute 331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[5] = strToInt(contentOffset + 12, 2); // second 332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 16) { 334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME optimize me 335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[6] = strToInt(contentOffset + 15, length - 16); 336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length == 17) { 338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[6] = times[6] * 100; 339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (length == 18) { 340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[6] = times[6] * 10; 341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME check all values for valid numbers!!! 345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) { 346897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding constructed ASN.1 GeneralizedTime type is not supported"); 347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 348897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("GeneralizedTime"); 349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 UTCTime type 354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 3555c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @throws IOException if an I/O error occurs or the end of the stream is reached 356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readUTCTime() throws IOException { 358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag == ASN1Constants.TAG_UTCTIME) { 359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project switch (length) { 360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project case ASN1UTCTime.UTC_HM: 361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project case ASN1UTCTime.UTC_HMS: 362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project break; 363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project case ASN1UTCTime.UTC_LOCAL_HM: 364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project case ASN1UTCTime.UTC_LOCAL_HMS: 365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME only coordinated universal time formats are supported 366897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 UTCTime: local time format is not supported"); 367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project default: 368897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 UTCTime: wrong length, identifier at " + tagOffset); 369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME: any other optimizations? 372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME store string somewhere to allow a custom time type perform 375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // additional checks 376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check syntax: the last char MUST be Z 378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (buffer[offset - 1] != 'Z') { 379f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes throw new ASN1Exception("ASN.1 UTCTime wrongly encoded at [" 380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project + contentOffset + ']'); 381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (times == null) { 384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times = new int[7]; 385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[0] = strToInt(contentOffset, 2); // year 388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (times[0] > 49) { 389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[0] += 1900; 390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[0] += 2000; 392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[1] = strToInt(contentOffset + 2, 2); // month 395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[2] = strToInt(contentOffset + 4, 2); // day 396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[3] = strToInt(contentOffset + 6, 2); // hour 397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[4] = strToInt(contentOffset + 8, 2); // minute 398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length == ASN1UTCTime.UTC_HMS) { 400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project times[5] = strToInt(contentOffset + 10, 2); // second 401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME check all time values for valid numbers!!! 404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (tag == ASN1Constants.TAG_C_UTCTIME) { 405897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding constructed ASN.1 UTCTime type is not supported"); 406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 407897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("UTCTime"); 408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private int strToInt(int off, int count) throws ASN1Exception { 412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int result = 0; 413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = off, end = off + count; i < end; i++) { 4145c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson int c = buffer[i] - 48; 415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (c < 0 || c > 9) { 416897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Time encoding has invalid char"); 417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project result = result * 10 + c; 419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return result; 421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 Integer type 425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readInteger() throws IOException { 427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_INTEGER) { 428897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("integer"); 429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded length 432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length < 1) { 433897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong length for ASN.1 integer at [" + tagOffset + "]"); 434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 437adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded content 439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 1) { 440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte firstByte = buffer[offset - length]; 441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte secondByte = (byte) (buffer[offset - length + 1] & 0x80); 442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF 444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project && secondByte == (byte) 0x80) { 445897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong content for ASN.1 integer at [" + (offset - length) + "]. An integer MUST be encoded in minimum number of octets"); 446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 Octetstring type 452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readOctetString() throws IOException { 454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag == ASN1Constants.TAG_OCTETSTRING) { 455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) { 457897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding constructed ASN.1 octet string type is not supported"); 458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 459897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("octetstring"); 460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 463897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes private ASN1Exception expected(String what) throws ASN1Exception { 464897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 " + what + " identifier expected at [" + tagOffset + "], got " + Integer.toHexString(tag)); 465897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes } 466897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes 467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int oidElement; 468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 ObjectIdentifier type 471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readOID() throws IOException { 473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_OID) { 474897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("OID"); 475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check encoded length 478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length < 1) { 479897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong length for ASN.1 object identifier at [" + tagOffset + "]"); 480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check content: last encoded byte (8th bit MUST be zero) 485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if ((buffer[offset - 1] & 0x80) != 0) { 486897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong encoding at [" + (offset - 1) + "]"); 487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project oidElement = 1; 490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 0; i < length; i++, ++oidElement) { 491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while ((buffer[contentOffset + i] & 0x80) == 0x80) { 492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project i++; 493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 Sequence type 499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readSequence(ASN1Sequence sequence) throws IOException { 501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_C_SEQUENCE) { 502897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("sequence"); 503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int begOffset = offset; 506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int endOffset = begOffset + length; 507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ASN1Type[] type = sequence.type; 509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int i = 0; 511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (isVerify) { 513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (; (offset < endOffset) && (i < type.length); i++) { 515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (!type[i].checkTag(tag)) { 518f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes // check whether it is optional component or not 519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!sequence.OPTIONAL[i] || (i == type.length - 1)) { 520897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 522adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project i++; 523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project type[i].decode(this); 526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check the rest of components 529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (; i < type.length; i++) { 530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!sequence.OPTIONAL[i]) { 531897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int seqTagOffset = tagOffset; //store tag offset 537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Object[] values = new Object[type.length]; 539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (; (offset < endOffset) && (i < type.length); i++) { 540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (!type[i].checkTag(tag)) { 543f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes // check whether it is optional component or not 544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!sequence.OPTIONAL[i] || (i == type.length - 1)) { 545897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // sets default value 549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (sequence.DEFAULT[i] != null) { 550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project values[i] = sequence.DEFAULT[i]; 551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project i++; 553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project values[i] = type[i].decode(this); 555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // check the rest of components 558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (; i < type.length; i++) { 559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!sequence.OPTIONAL[i]) { 560897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (sequence.DEFAULT[i] != null) { 563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project values[i] = sequence.DEFAULT[i]; 564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project content = values; 567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project tagOffset = seqTagOffset; //retrieve tag offset 569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (offset != endOffset) { 572897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same"); 573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 SequenceOf type 578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readSequenceOf(ASN1SequenceOf sequenceOf) throws IOException { 580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_C_SEQUENCEOF) { 581897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("sequenceOf"); 582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decodeValueCollection(sequenceOf); 585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 Set type 589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readSet(ASN1Set set) throws IOException { 591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_C_SET) { 592897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("set"); 593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 595897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding ASN.1 Set type is not supported"); 596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 SetOf type 600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readSetOf(ASN1SetOf setOf) throws IOException { 602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag != ASN1Constants.TAG_C_SETOF) { 603897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("setOf"); 604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decodeValueCollection(setOf); 607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 6095c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson private void decodeValueCollection(ASN1ValueCollection collection) throws IOException { 610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int begOffset = offset; 611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int endOffset = begOffset + length; 612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ASN1Type type = collection.type; 614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (isVerify) { 616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (endOffset > offset) { 617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project type.decode(this); 619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int seqTagOffset = tagOffset; //store tag offset 622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 6235c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson ArrayList<Object> values = new ArrayList<Object>(); 624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (endOffset > offset) { 625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project next(); 626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project values.add(type.decode(this)); 627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 62921f21e9f56ab8c9abfd8728473533fcaafafeac0Jesse Wilson values.trimToSize(); 630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project content = values; 631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project tagOffset = seqTagOffset; //retrieve tag offset 633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (offset != endOffset) { 636897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same"); 637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 String type 642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 6435c27fb80ffd335aa45dc8829ba3ecbc18c01e4e8Jesse Wilson * @throws IOException if an I/O error occurs or the end of the stream is reached 644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readString(ASN1StringType type) throws IOException { 646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tag == type.id) { 647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project readContent(); 648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else if (tag == type.constrId) { 649897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Decoding constructed ASN.1 string type is not provided"); 650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 651897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw expected("string"); 652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns encoded array. 657f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 658f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * MUST be invoked after decoding corresponding ASN.1 notation 659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public byte[] getEncoded() { 661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte[] encoded = new byte[offset - tagOffset]; 662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length); 663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return encoded; 664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns internal buffer used for decoding 668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final byte[] getBuffer() { 670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return buffer; 671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns length of the current content for decoding 675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int getLength() { 677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return length; 678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the current offset 682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int getOffset() { 684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return offset; 685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns end offset for the current encoded type 689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int getEndOffset() { 691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return offset + length; 692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns start offset for the current encoded type 696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int getTagOffset() { 698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return tagOffset; 699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Indicates verify or store mode. 703f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * In store mode a decoded content is stored in a newly allocated 705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * appropriate object. The <code>content</code> variable holds 706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * a reference to the last created object. 707f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * In verify mode a decoded content is not stored. 709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // FIXME it is used only for one case 711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // decoding PCKS#8 Private Key Info notation 712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // remove this option because it does decoding more complex 713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected boolean isVerify; 714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Sets verify mode. 717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final void setVerify() { 719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project isVerify = true; 720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Indicates defined or indefined reading mode for associated InputStream. 724f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This mode is defined by reading a length 726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * for a first ASN.1 type from InputStream. 727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected boolean isIndefinedLength; 729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Reads the next encoded byte from the encoded input stream. 732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected int read() throws IOException { 734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (offset == buffer.length) { 735897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Unexpected end of encoding"); 736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (in == null) { 739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return buffer[offset++] & 0xFF; 740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int octet = in.read(); 742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (octet == -1) { 743897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Unexpected end of encoding"); 744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 745f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer[offset++] = (byte) octet; 747f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes 748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return octet; 749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Reads the next encoded content from the encoded input stream. 754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The method MUST be used for reading a primitive encoded content. 755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void readContent() throws IOException { 757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (offset + length > buffer.length) { 758897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Unexpected end of encoding"); 759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (in == null) { 762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project offset += length; 763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 7642f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes int bytesRead = in.read(buffer, offset, length); 7652f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes 7662f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes if (bytesRead != length) { 7672f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes // if input stream didn't return all data at once 7682f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes // try to read it in several blocks 7692f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes int c = bytesRead; 7702f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes do { 7712f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes if (c < 1 || bytesRead > length) { 772897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new ASN1Exception("Failed to read encoded content"); 7732f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes } 7742f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes c = in.read(buffer, offset + bytesRead, length - bytesRead); 7752f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes bytesRead += c; 7762f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes } while (bytesRead != length); 777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 7782f9e468ed4985edfd5e351faf2089d91e561e41dElliott Hughes 779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project offset += length; 780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Reallocates the buffer in order to make it 785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * exactly the size of data it contains 786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void compactBuffer() { 788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (offset != buffer.length) { 789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte[] newBuffer = new byte[offset]; 790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // restore buffer content 791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project System.arraycopy(buffer, 0, newBuffer, 0, offset); 792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // set new buffer 793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project buffer = newBuffer; 794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private Object[][] pool; 797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void put(Object key, Object entry) { 799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (pool == null) { 800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project pool = new Object[2][10]; 801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int i = 0; 804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (; i < pool[0].length && pool[0][i] != null; i++) { 805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (pool[0][i] == key) { 806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project pool[1][i] = entry; 807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return; 808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (i == pool[0].length) { 812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Object[][] newPool = new Object[pool[0].length * 2][2]; 813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length); 814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length); 815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project pool = newPool; 816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project pool[0][i] = key; 818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project pool[1][i] = entry; 819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Object get(Object key) { 823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (pool == null) { 824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 0; i < pool[0].length; i++) { 828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (pool[0][i] == key) { 829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return pool[1][i]; 830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 835