001: /*
002: * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.util;
027:
028: import java.io.IOException;
029: import java.util.ArrayList;
030:
031: /**
032: * A package private utility class to convert indefinite length DER
033: * encoded byte arrays to definite length DER encoded byte arrays.
034: *
035: * This assumes that the basic data structure is "tag, length, value"
036: * triplet. In the case where the length is "indefinite", terminating
037: * end-of-contents bytes are expected.
038: *
039: * @author Hemma Prafullchandra
040: * @version 1.20 05/05/07
041: */
042: class DerIndefLenConverter {
043:
044: private static final int TAG_MASK = 0x1f; // bits 5-1
045: private static final int FORM_MASK = 0x20; // bits 6
046: private static final int CLASS_MASK = 0xC0; // bits 8 and 7
047:
048: private static final int LEN_LONG = 0x80; // bit 8 set
049: private static final int LEN_MASK = 0x7f; // bits 7 - 1
050: private static final int SKIP_EOC_BYTES = 2;
051:
052: private byte[] data, newData;
053: private int newDataPos, dataPos, dataSize, index;
054:
055: private ArrayList<Object> ndefsList = new ArrayList<Object>();
056:
057: private int numOfTotalLenBytes = 0;
058:
059: private boolean isEOC(int tag) {
060: return (((tag & TAG_MASK) == 0x00) && // EOC
061: ((tag & FORM_MASK) == 0x00) && // primitive
062: ((tag & CLASS_MASK) == 0x00)); // universal
063: }
064:
065: // if bit 8 is set then it implies either indefinite length or long form
066: static boolean isLongForm(int lengthByte) {
067: return ((lengthByte & LEN_LONG) == LEN_LONG);
068: }
069:
070: /*
071: * Default package private constructor
072: */
073: DerIndefLenConverter() {
074: }
075:
076: /**
077: * Checks whether the given length byte is of the form
078: * <em>Indefinite</em>.
079: *
080: * @param lengthByte the length byte from a DER encoded
081: * object.
082: * @return true if the byte is of Indefinite form otherwise
083: * returns false.
084: */
085: static boolean isIndefinite(int lengthByte) {
086: return (isLongForm(lengthByte) && ((lengthByte & LEN_MASK) == 0));
087: }
088:
089: /**
090: * Parse the tag and if it is an end-of-contents tag then
091: * add the current position to the <code>eocList</code> vector.
092: */
093: private void parseTag() throws IOException {
094: if (dataPos == dataSize)
095: return;
096: if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) {
097: int numOfEncapsulatedLenBytes = 0;
098: Object elem = null;
099: int index;
100: for (index = ndefsList.size() - 1; index >= 0; index--) {
101: // Determine the first element in the vector that does not
102: // have a matching EOC
103: elem = ndefsList.get(index);
104: if (elem instanceof Integer) {
105: break;
106: } else {
107: numOfEncapsulatedLenBytes += ((byte[]) elem).length - 3;
108: }
109: }
110: if (index < 0) {
111: throw new IOException("EOC does not have matching "
112: + "indefinite-length tag");
113: }
114: int sectionLen = dataPos - ((Integer) elem).intValue()
115: + numOfEncapsulatedLenBytes;
116: byte[] sectionLenBytes = getLengthBytes(sectionLen);
117: ndefsList.set(index, sectionLenBytes);
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: */
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: */
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: return curLen;
155: }
156: if (isLongForm(lenByte)) {
157: lenByte &= LEN_MASK;
158: if (lenByte > 4)
159: throw new IOException("Too much data");
160: if ((dataSize - dataPos) < (lenByte + 1))
161: throw new IOException("Too little data");
162: for (int i = 0; i < lenByte; i++)
163: curLen = (curLen << 8) + (data[dataPos++] & 0xff);
164: } else {
165: curLen = (lenByte & LEN_MASK);
166: }
167: return curLen;
168: }
169:
170: /**
171: * Write the length and if it is an indefinite length
172: * then calculate the definite length from the positions
173: * of the indefinite length and its matching EOC terminator.
174: * Then, write the value.
175: */
176: private void writeLengthAndValue() throws IOException {
177: if (dataPos == dataSize)
178: return;
179: int curLen = 0;
180: int lenByte = data[dataPos++] & 0xff;
181: if (isIndefinite(lenByte)) {
182: byte[] lenBytes = (byte[]) ndefsList.get(index++);
183: System.arraycopy(lenBytes, 0, newData, newDataPos,
184: lenBytes.length);
185: newDataPos += lenBytes.length;
186: return;
187: }
188: if (isLongForm(lenByte)) {
189: lenByte &= LEN_MASK;
190: for (int i = 0; i < lenByte; i++)
191: curLen = (curLen << 8) + (data[dataPos++] & 0xff);
192: } else
193: curLen = (lenByte & LEN_MASK);
194: writeLength(curLen);
195: writeValue(curLen);
196: }
197:
198: private void writeLength(int curLen) {
199: if (curLen < 128) {
200: newData[newDataPos++] = (byte) curLen;
201:
202: } else if (curLen < (1 << 8)) {
203: newData[newDataPos++] = (byte) 0x81;
204: newData[newDataPos++] = (byte) curLen;
205:
206: } else if (curLen < (1 << 16)) {
207: newData[newDataPos++] = (byte) 0x82;
208: newData[newDataPos++] = (byte) (curLen >> 8);
209: newData[newDataPos++] = (byte) curLen;
210:
211: } else if (curLen < (1 << 24)) {
212: newData[newDataPos++] = (byte) 0x83;
213: newData[newDataPos++] = (byte) (curLen >> 16);
214: newData[newDataPos++] = (byte) (curLen >> 8);
215: newData[newDataPos++] = (byte) curLen;
216:
217: } else {
218: newData[newDataPos++] = (byte) 0x84;
219: newData[newDataPos++] = (byte) (curLen >> 24);
220: newData[newDataPos++] = (byte) (curLen >> 16);
221: newData[newDataPos++] = (byte) (curLen >> 8);
222: newData[newDataPos++] = (byte) curLen;
223: }
224: }
225:
226: private byte[] getLengthBytes(int curLen) {
227: byte[] lenBytes;
228: int index = 0;
229:
230: if (curLen < 128) {
231: lenBytes = new byte[1];
232: lenBytes[index++] = (byte) curLen;
233:
234: } else if (curLen < (1 << 8)) {
235: lenBytes = new byte[2];
236: lenBytes[index++] = (byte) 0x81;
237: lenBytes[index++] = (byte) curLen;
238:
239: } else if (curLen < (1 << 16)) {
240: lenBytes = new byte[3];
241: lenBytes[index++] = (byte) 0x82;
242: lenBytes[index++] = (byte) (curLen >> 8);
243: lenBytes[index++] = (byte) curLen;
244:
245: } else if (curLen < (1 << 24)) {
246: lenBytes = new byte[4];
247: lenBytes[index++] = (byte) 0x83;
248: lenBytes[index++] = (byte) (curLen >> 16);
249: lenBytes[index++] = (byte) (curLen >> 8);
250: lenBytes[index++] = (byte) curLen;
251:
252: } else {
253: lenBytes = new byte[5];
254: lenBytes[index++] = (byte) 0x84;
255: lenBytes[index++] = (byte) (curLen >> 24);
256: lenBytes[index++] = (byte) (curLen >> 16);
257: lenBytes[index++] = (byte) (curLen >> 8);
258: lenBytes[index++] = (byte) curLen;
259: }
260:
261: return lenBytes;
262: }
263:
264: // Returns the number of bytes needed to represent the given length
265: // in ASN.1 notation
266: private int getNumOfLenBytes(int len) {
267: int numOfLenBytes = 0;
268:
269: if (len < 128) {
270: numOfLenBytes = 1;
271: } else if (len < (1 << 8)) {
272: numOfLenBytes = 2;
273: } else if (len < (1 << 16)) {
274: numOfLenBytes = 3;
275: } else if (len < (1 << 24)) {
276: numOfLenBytes = 4;
277: } else {
278: numOfLenBytes = 5;
279: }
280: return numOfLenBytes;
281: }
282:
283: /**
284: * Parse the value;
285: */
286: private void parseValue(int curLen) {
287: dataPos += curLen;
288: }
289:
290: /**
291: * Write the value;
292: */
293: private void writeValue(int curLen) {
294: for (int i = 0; i < curLen; i++)
295: newData[newDataPos++] = data[dataPos++];
296: }
297:
298: /**
299: * Converts a indefinite length DER encoded byte array to
300: * a definte length DER encoding.
301: *
302: * @param indefData the byte array holding the indefinite
303: * length encoding.
304: * @return the byte array containing the definite length
305: * DER encoding.
306: * @exception IOException on parsing or re-writing errors.
307: */
308: byte[] convert(byte[] indefData) throws IOException {
309: data = indefData;
310: dataPos = 0;
311: index = 0;
312: dataSize = data.length;
313: int len = 0;
314:
315: // parse and set up the vectors of all the indefinite-lengths
316: while (dataPos < dataSize) {
317: parseTag();
318: len = parseLength();
319: parseValue(len);
320: }
321:
322: newData = new byte[dataSize + numOfTotalLenBytes];
323: dataPos = 0;
324: newDataPos = 0;
325: index = 0;
326:
327: // write out the new byte array replacing all the indefinite-lengths
328: // and EOCs
329: while (dataPos < dataSize) {
330: writeTag();
331: writeLengthAndValue();
332: }
333:
334: return newData;
335: }
336: }
|