• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.util;
27 
28 import java.io.IOException;
29 import java.util.ArrayList;
30 
31 /**
32  * A package private utility class to convert indefinite length DER
33  * encoded byte arrays to definite length DER encoded byte arrays.
34  *
35  * This assumes that the basic data structure is "tag, length, value"
36  * triplet. In the case where the length is "indefinite", terminating
37  * end-of-contents bytes are expected.
38  *
39  * @author Hemma Prafullchandra
40  */
41 class DerIndefLenConverter {
42 
43     private static final int TAG_MASK            = 0x1f; // bits 5-1
44     private static final int FORM_MASK           = 0x20; // bits 6
45     private static final int CLASS_MASK          = 0xC0; // bits 8 and 7
46 
47     private static final int LEN_LONG            = 0x80; // bit 8 set
48     private static final int LEN_MASK            = 0x7f; // bits 7 - 1
49     private static final int SKIP_EOC_BYTES      = 2;
50 
51     private byte[] data, newData;
52     private int newDataPos, dataPos, dataSize, index;
53     private int unresolved = 0;
54 
55     private ArrayList<Object> ndefsList = new ArrayList<Object>();
56 
57     private int numOfTotalLenBytes = 0;
58 
isEOC(int tag)59     private boolean isEOC(int tag) {
60         return (((tag & TAG_MASK) == 0x00) &&  // EOC
61                 ((tag & FORM_MASK) == 0x00) && // primitive
62                 ((tag & CLASS_MASK) == 0x00)); // universal
63     }
64 
65     // if bit 8 is set then it implies either indefinite length or long form
isLongForm(int lengthByte)66     static boolean isLongForm(int lengthByte) {
67         return ((lengthByte & LEN_LONG) == LEN_LONG);
68     }
69 
70     /*
71      * Default package private constructor
72      */
DerIndefLenConverter()73     DerIndefLenConverter() { }
74 
75     /**
76      * Checks whether the given length byte is of the form
77      * <em>Indefinite</em>.
78      *
79      * @param lengthByte the length byte from a DER encoded
80      *        object.
81      * @return true if the byte is of Indefinite form otherwise
82      *         returns false.
83      */
isIndefinite(int lengthByte)84     static boolean isIndefinite(int lengthByte) {
85         return (isLongForm(lengthByte) && ((lengthByte & LEN_MASK) == 0));
86     }
87 
88     /**
89      * Parse the tag and if it is an end-of-contents tag then
90      * add the current position to the <code>eocList</code> vector.
91      */
parseTag()92     private void parseTag() throws IOException {
93         if (dataPos == dataSize)
94             return;
95         if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) {
96             int numOfEncapsulatedLenBytes = 0;
97             Object elem = null;
98             int index;
99             for (index = ndefsList.size()-1; index >= 0; index--) {
100                 // Determine the first element in the vector that does not
101                 // have a matching EOC
102                 elem = ndefsList.get(index);
103                 if (elem instanceof Integer) {
104                     break;
105                 } else {
106                     numOfEncapsulatedLenBytes += ((byte[])elem).length - 3;
107                 }
108             }
109             if (index < 0) {
110                 throw new IOException("EOC does not have matching " +
111                                       "indefinite-length tag");
112             }
113             int sectionLen = dataPos - ((Integer)elem).intValue() +
114                              numOfEncapsulatedLenBytes;
115             byte[] sectionLenBytes = getLengthBytes(sectionLen);
116             ndefsList.set(index, sectionLenBytes);
117             unresolved--;
118 
119             // Add the number of bytes required to represent this section
120             // to the total number of length bytes,
121             // and subtract the indefinite-length tag (1 byte) and
122             // EOC bytes (2 bytes) for this section
123             numOfTotalLenBytes += (sectionLenBytes.length - 3);
124         }
125         dataPos++;
126     }
127 
128     /**
129      * Write the tag and if it is an end-of-contents tag
130      * then skip the tag and its 1 byte length of zero.
131      */
writeTag()132     private void writeTag() {
133         if (dataPos == dataSize)
134             return;
135         int tag = data[dataPos++];
136         if (isEOC(tag) && (data[dataPos] == 0)) {
137             dataPos++;  // skip length
138             writeTag();
139         } else
140             newData[newDataPos++] = (byte)tag;
141     }
142 
143     /**
144      * Parse the length and if it is an indefinite length then add
145      * the current position to the <code>ndefsList</code> vector.
146      */
parseLength()147     private int parseLength() throws IOException {
148         int curLen = 0;
149         if (dataPos == dataSize)
150             return curLen;
151         int lenByte = data[dataPos++] & 0xff;
152         if (isIndefinite(lenByte)) {
153             ndefsList.add(new Integer(dataPos));
154             unresolved++;
155             return curLen;
156         }
157         if (isLongForm(lenByte)) {
158             lenByte &= LEN_MASK;
159             if (lenByte > 4)
160                 throw new IOException("Too much data");
161             if ((dataSize - dataPos) < (lenByte + 1))
162                 throw new IOException("Too little data");
163             for (int i = 0; i < lenByte; i++)
164                 curLen = (curLen << 8) + (data[dataPos++] & 0xff);
165         } else {
166            curLen = (lenByte & LEN_MASK);
167         }
168         return curLen;
169     }
170 
171     /**
172      * Write the length and if it is an indefinite length
173      * then calculate the definite length from the positions
174      * of the indefinite length and its matching EOC terminator.
175      * Then, write the value.
176      */
writeLengthAndValue()177     private void writeLengthAndValue() throws IOException {
178         if (dataPos == dataSize)
179            return;
180         int curLen = 0;
181         int lenByte = data[dataPos++] & 0xff;
182         if (isIndefinite(lenByte)) {
183             byte[] lenBytes = (byte[])ndefsList.get(index++);
184             System.arraycopy(lenBytes, 0, newData, newDataPos,
185                              lenBytes.length);
186             newDataPos += lenBytes.length;
187             return;
188         }
189         if (isLongForm(lenByte)) {
190             lenByte &= LEN_MASK;
191             for (int i = 0; i < lenByte; i++)
192                 curLen = (curLen << 8) + (data[dataPos++] & 0xff);
193         } else
194             curLen = (lenByte & LEN_MASK);
195         writeLength(curLen);
196         writeValue(curLen);
197     }
198 
writeLength(int curLen)199     private void writeLength(int curLen) {
200         if (curLen < 128) {
201             newData[newDataPos++] = (byte)curLen;
202 
203         } else if (curLen < (1 << 8)) {
204             newData[newDataPos++] = (byte)0x81;
205             newData[newDataPos++] = (byte)curLen;
206 
207         } else if (curLen < (1 << 16)) {
208             newData[newDataPos++] = (byte)0x82;
209             newData[newDataPos++] = (byte)(curLen >> 8);
210             newData[newDataPos++] = (byte)curLen;
211 
212         } else if (curLen < (1 << 24)) {
213             newData[newDataPos++] = (byte)0x83;
214             newData[newDataPos++] = (byte)(curLen >> 16);
215             newData[newDataPos++] = (byte)(curLen >> 8);
216             newData[newDataPos++] = (byte)curLen;
217 
218         } else {
219             newData[newDataPos++] = (byte)0x84;
220             newData[newDataPos++] = (byte)(curLen >> 24);
221             newData[newDataPos++] = (byte)(curLen >> 16);
222             newData[newDataPos++] = (byte)(curLen >> 8);
223             newData[newDataPos++] = (byte)curLen;
224         }
225     }
226 
getLengthBytes(int curLen)227     private byte[] getLengthBytes(int curLen) {
228         byte[] lenBytes;
229         int index = 0;
230 
231         if (curLen < 128) {
232             lenBytes = new byte[1];
233             lenBytes[index++] = (byte)curLen;
234 
235         } else if (curLen < (1 << 8)) {
236             lenBytes = new byte[2];
237             lenBytes[index++] = (byte)0x81;
238             lenBytes[index++] = (byte)curLen;
239 
240         } else if (curLen < (1 << 16)) {
241             lenBytes = new byte[3];
242             lenBytes[index++] = (byte)0x82;
243             lenBytes[index++] = (byte)(curLen >> 8);
244             lenBytes[index++] = (byte)curLen;
245 
246         } else if (curLen < (1 << 24)) {
247             lenBytes = new byte[4];
248             lenBytes[index++] = (byte)0x83;
249             lenBytes[index++] = (byte)(curLen >> 16);
250             lenBytes[index++] = (byte)(curLen >> 8);
251             lenBytes[index++] = (byte)curLen;
252 
253         } else {
254             lenBytes = new byte[5];
255             lenBytes[index++] = (byte)0x84;
256             lenBytes[index++] = (byte)(curLen >> 24);
257             lenBytes[index++] = (byte)(curLen >> 16);
258             lenBytes[index++] = (byte)(curLen >> 8);
259             lenBytes[index++] = (byte)curLen;
260         }
261 
262         return lenBytes;
263     }
264 
265     // Returns the number of bytes needed to represent the given length
266     // in ASN.1 notation
getNumOfLenBytes(int len)267     private int getNumOfLenBytes(int len) {
268         int numOfLenBytes = 0;
269 
270         if (len < 128) {
271             numOfLenBytes = 1;
272         } else if (len < (1 << 8)) {
273             numOfLenBytes = 2;
274         } else if (len < (1 << 16)) {
275             numOfLenBytes = 3;
276         } else if (len < (1 << 24)) {
277             numOfLenBytes = 4;
278         } else {
279             numOfLenBytes = 5;
280         }
281         return numOfLenBytes;
282     }
283 
284     /**
285      * Parse the value;
286      */
parseValue(int curLen)287     private void parseValue(int curLen) {
288         dataPos += curLen;
289     }
290 
291     /**
292      * Write the value;
293      */
writeValue(int curLen)294     private void writeValue(int curLen) {
295         for (int i=0; i < curLen; i++)
296             newData[newDataPos++] = data[dataPos++];
297     }
298 
299     /**
300      * Converts a indefinite length DER encoded byte array to
301      * a definte length DER encoding.
302      *
303      * @param indefData the byte array holding the indefinite
304      *        length encoding.
305      * @return the byte array containing the definite length
306      *         DER encoding.
307      * @exception IOException on parsing or re-writing errors.
308      */
convert(byte[] indefData)309     byte[] convert(byte[] indefData) throws IOException {
310         data = indefData;
311         dataPos=0; index=0;
312         dataSize = data.length;
313         int len=0;
314         int unused = 0;
315 
316         // parse and set up the vectors of all the indefinite-lengths
317         while (dataPos < dataSize) {
318             parseTag();
319             len = parseLength();
320             parseValue(len);
321             if (unresolved == 0) {
322                 unused = dataSize - dataPos;
323                 dataSize = dataPos;
324                 break;
325             }
326         }
327 
328         if (unresolved != 0) {
329             throw new IOException("not all indef len BER resolved");
330         }
331 
332         newData = new byte[dataSize + numOfTotalLenBytes + unused];
333         dataPos=0; newDataPos=0; index=0;
334 
335         // write out the new byte array replacing all the indefinite-lengths
336         // and EOCs
337         while (dataPos < dataSize) {
338            writeTag();
339            writeLengthAndValue();
340         }
341         System.arraycopy(indefData, dataSize,
342                          newData, dataSize + numOfTotalLenBytes, unused);
343 
344         return newData;
345     }
346 }
347