001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.crypto.asn1;
017:
018: import java.io.ByteArrayInputStream;
019: import java.io.ByteArrayOutputStream;
020: import java.io.EOFException;
021: import java.io.FilterInputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.util.Vector;
025:
026: /**
027: * a general purpose ASN.1 decoder - note: this class differs from the
028: * others in that it returns null after it has read the last object in
029: * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
030: * returned.
031: */
032: public class ASN1InputStream extends FilterInputStream implements
033: DERTags {
034: private DERObject END_OF_STREAM = new DERObject() {
035: void encode(DEROutputStream out) throws IOException {
036: throw new IOException("Eeek!");
037: }
038:
039: public int hashCode() {
040: return 0;
041: }
042:
043: public boolean equals(Object o) {
044: return o == this ;
045: }
046: };
047: boolean eofFound = false;
048:
049: public ASN1InputStream(InputStream is) {
050: super (is);
051: }
052:
053: public ASN1InputStream(byte[] input) {
054: super (new ByteArrayInputStream(input));
055: }
056:
057: protected int readLength() throws IOException {
058: int length = read();
059: if (length < 0) {
060: throw new IOException("EOF found when length expected");
061: }
062:
063: if (length == 0x80) {
064: return -1; // indefinite-length encoding
065: }
066:
067: if (length > 127) {
068: int size = length & 0x7f;
069:
070: if (size > 4) {
071: throw new IOException("DER length more than 4 bytes");
072: }
073:
074: length = 0;
075: for (int i = 0; i < size; i++) {
076: int next = read();
077:
078: if (next < 0) {
079: throw new IOException("EOF found reading length");
080: }
081:
082: length = (length << 8) + next;
083: }
084:
085: if (length < 0) {
086: throw new IOException(
087: "corrupted steam - negative length found");
088: }
089: }
090:
091: return length;
092: }
093:
094: protected void readFully(byte[] bytes) throws IOException {
095: int left = bytes.length;
096: int len;
097:
098: if (left == 0) {
099: return;
100: }
101:
102: while ((len = read(bytes, bytes.length - left, left)) > 0) {
103: if ((left -= len) == 0) {
104: return;
105: }
106: }
107:
108: if (left != 0) {
109: throw new EOFException(
110: "EOF encountered in middle of object");
111: }
112: }
113:
114: /**
115: * build an object given its tag and a byte stream to construct it
116: * from.
117: */
118: protected DERObject buildObject(int tag, byte[] bytes)
119: throws IOException {
120: if ((tag & APPLICATION) != 0) {
121: return new DERApplicationSpecific(tag, bytes);
122: }
123:
124: switch (tag) {
125: case NULL:
126: return new DERNull();
127: case SEQUENCE | CONSTRUCTED:
128: ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
129: ASN1InputStream aIn = new ASN1InputStream(bIn);
130: ASN1EncodableVector v = new ASN1EncodableVector();
131:
132: DERObject obj = aIn.readObject();
133:
134: while (obj != null) {
135: v.add(obj);
136: obj = aIn.readObject();
137: }
138:
139: return new DERSequence(v);
140: case SET | CONSTRUCTED:
141: bIn = new ByteArrayInputStream(bytes);
142: aIn = new ASN1InputStream(bIn);
143: v = new ASN1EncodableVector();
144:
145: obj = aIn.readObject();
146:
147: while (obj != null) {
148: v.add(obj);
149: obj = aIn.readObject();
150: }
151:
152: return new DERSet(v, false);
153: case BOOLEAN:
154: return new DERBoolean(bytes);
155: case INTEGER:
156: return new DERInteger(bytes);
157: case ENUMERATED:
158: return new DEREnumerated(bytes);
159: case OBJECT_IDENTIFIER:
160: return new DERObjectIdentifier(bytes);
161: case BIT_STRING:
162: int padBits = bytes[0];
163: byte[] data = new byte[bytes.length - 1];
164:
165: System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
166:
167: return new DERBitString(data, padBits);
168: case NUMERIC_STRING:
169: return new DERNumericString(bytes);
170: case UTF8_STRING:
171: return new DERUTF8String(bytes);
172: case PRINTABLE_STRING:
173: return new DERPrintableString(bytes);
174: case IA5_STRING:
175: return new DERIA5String(bytes);
176: case T61_STRING:
177: return new DERT61String(bytes);
178: case VISIBLE_STRING:
179: return new DERVisibleString(bytes);
180: case GENERAL_STRING:
181: return new DERGeneralString(bytes);
182: case UNIVERSAL_STRING:
183: return new DERUniversalString(bytes);
184: case BMP_STRING:
185: return new DERBMPString(bytes);
186: case OCTET_STRING:
187: return new DEROctetString(bytes);
188: case UTC_TIME:
189: return new DERUTCTime(bytes);
190: case GENERALIZED_TIME:
191: return new DERGeneralizedTime(bytes);
192: default:
193: //
194: // with tagged object tag number is bottom 5 bits
195: //
196: if ((tag & TAGGED) != 0) {
197: int tagNo = tag & 0x1f;
198:
199: if (tagNo == 0x1f) {
200: int idx = 0;
201:
202: tagNo = 0;
203:
204: while ((bytes[idx] & 0x80) != 0) {
205: tagNo |= (bytes[idx++] & 0x7f);
206: tagNo <<= 7;
207: }
208:
209: tagNo |= (bytes[idx] & 0x7f);
210:
211: byte[] tmp = bytes;
212:
213: bytes = new byte[tmp.length - (idx + 1)];
214: System.arraycopy(tmp, idx + 1, bytes, 0,
215: bytes.length);
216: }
217:
218: if (bytes.length == 0) // empty tag!
219: {
220: if ((tag & CONSTRUCTED) == 0) {
221: return new DERTaggedObject(false, tagNo,
222: new DERNull());
223: } else {
224: return new DERTaggedObject(false, tagNo,
225: new DERSequence());
226: }
227: }
228:
229: //
230: // simple type - implicit... return an octet string
231: //
232: if ((tag & CONSTRUCTED) == 0) {
233: return new DERTaggedObject(false, tagNo,
234: new DEROctetString(bytes));
235: }
236:
237: bIn = new ByteArrayInputStream(bytes);
238: aIn = new ASN1InputStream(bIn);
239:
240: DEREncodable dObj = aIn.readObject();
241:
242: //
243: // explicitly tagged (probably!) - if it isn't we'd have to
244: // tell from the context
245: //
246: if (aIn.available() == 0) {
247: return new DERTaggedObject(tagNo, dObj);
248: }
249:
250: //
251: // another implicit object, we'll create a sequence...
252: //
253: v = new ASN1EncodableVector();
254:
255: while (dObj != null) {
256: v.add(dObj);
257: dObj = aIn.readObject();
258: }
259:
260: return new DERTaggedObject(false, tagNo,
261: new DERSequence(v));
262: }
263:
264: return new DERUnknownTag(tag, bytes);
265: }
266: }
267:
268: /**
269: * read a string of bytes representing an indefinite length object.
270: */
271: private byte[] readIndefiniteLengthFully() throws IOException {
272: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
273: int b, b1;
274:
275: b1 = read();
276:
277: while ((b = read()) >= 0) {
278: if (b1 == 0 && b == 0) {
279: break;
280: }
281:
282: bOut.write(b1);
283: b1 = b;
284: }
285:
286: return bOut.toByteArray();
287: }
288:
289: private BERConstructedOctetString buildConstructedOctetString()
290: throws IOException {
291: Vector octs = new Vector();
292:
293: for (;;) {
294: DERObject o = readObject();
295:
296: if (o == END_OF_STREAM) {
297: break;
298: }
299:
300: octs.addElement(o);
301: }
302:
303: return new BERConstructedOctetString(octs);
304: }
305:
306: public DERObject readObject() throws IOException {
307: int tag = read();
308: if (tag == -1) {
309: if (eofFound) {
310: throw new EOFException(
311: "attempt to read past end of file.");
312: }
313:
314: eofFound = true;
315:
316: return null;
317: }
318:
319: int length = readLength();
320:
321: if (length < 0) // indefinite length method
322: {
323: switch (tag) {
324: case NULL:
325: return new BERNull();
326: case SEQUENCE | CONSTRUCTED:
327: ASN1EncodableVector v = new ASN1EncodableVector();
328:
329: for (;;) {
330: DERObject obj = readObject();
331:
332: if (obj == END_OF_STREAM) {
333: break;
334: }
335:
336: v.add(obj);
337: }
338: return new BERSequence(v);
339: case SET | CONSTRUCTED:
340: v = new ASN1EncodableVector();
341:
342: for (;;) {
343: DERObject obj = readObject();
344:
345: if (obj == END_OF_STREAM) {
346: break;
347: }
348:
349: v.add(obj);
350: }
351: return new BERSet(v, false);
352: case OCTET_STRING | CONSTRUCTED:
353: return buildConstructedOctetString();
354: default:
355: //
356: // with tagged object tag number is bottom 5 bits
357: //
358: if ((tag & TAGGED) != 0) {
359: int tagNo = tag & 0x1f;
360:
361: if (tagNo == 0x1f) {
362: int b = read();
363:
364: tagNo = 0;
365:
366: while ((b >= 0) && ((b & 0x80) != 0)) {
367: tagNo |= (b & 0x7f);
368: tagNo <<= 7;
369: b = read();
370: }
371:
372: tagNo |= (b & 0x7f);
373: }
374:
375: //
376: // simple type - implicit... return an octet string
377: //
378: if ((tag & CONSTRUCTED) == 0) {
379: byte[] bytes = readIndefiniteLengthFully();
380:
381: return new BERTaggedObject(false, tagNo,
382: new DEROctetString(bytes));
383: }
384:
385: //
386: // either constructed or explicitly tagged
387: //
388: DERObject dObj = readObject();
389:
390: if (dObj == END_OF_STREAM) // empty tag!
391: {
392: return new DERTaggedObject(tagNo);
393: }
394:
395: DERObject next = readObject();
396:
397: //
398: // explicitly tagged (probably!) - if it isn't we'd have to
399: // tell from the context
400: //
401: if (next == END_OF_STREAM) {
402: return new BERTaggedObject(tagNo, dObj);
403: }
404:
405: //
406: // another implicit object, we'll create a sequence...
407: //
408: v = new ASN1EncodableVector();
409:
410: v.add(dObj);
411:
412: do {
413: v.add(next);
414: next = readObject();
415: } while (next != END_OF_STREAM);
416:
417: return new BERTaggedObject(false, tagNo,
418: new BERSequence(v));
419: }
420:
421: throw new IOException("unknown BER object encountered");
422: }
423: } else {
424: if (tag == 0 && length == 0) // end of contents marker.
425: {
426: return END_OF_STREAM;
427: }
428:
429: byte[] bytes = new byte[length];
430:
431: readFully(bytes);
432:
433: return buildObject(tag, bytes);
434: }
435: }
436: }
|