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