0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: /**
0019: * @author Vladimir N. Molotkov, Stepan M. Mishura
0020: * @version $Revision$
0021: */package org.apache.harmony.security.asn1;
0022:
0023: import java.io.IOException;
0024: import java.io.InputStream;
0025: import java.util.ArrayList;
0026:
0027: import org.apache.harmony.security.internal.nls.Messages;
0028:
0029: /**
0030: * Decodes ASN.1 types encoded with BER (X.690)
0031: *
0032: * @see http://asn1.elibel.tm.fr/en/standards/index.htm
0033: */
0034:
0035: public class BerInputStream {
0036:
0037: /**
0038: * Associated <code>InputStream</code>
0039: */
0040: protected InputStream in;
0041:
0042: /**
0043: * Internal buffer for storing encoded array
0044: */
0045: protected byte[] buffer;
0046:
0047: /**
0048: * The position in the buffer.
0049: *
0050: * Next read must place data into the buffer from this offset
0051: */
0052: protected int offset = 0;
0053:
0054: // The buffer increment size.
0055: // Must be reasonable big to reallocate memory not to often.
0056: // Primary is used for decoding indefinite length encoding
0057: private static final int BUF_INCREASE_SIZE = 1024 * 16;
0058:
0059: /**
0060: * Indicates indefinite length of the current type
0061: */
0062: protected static final int INDEFINIT_LENGTH = -1;
0063:
0064: /**
0065: * Creates stream for decoding.
0066: *
0067: * @param encoded - bytes array to be decoded
0068: * @throws IOException - if an error occurs
0069: */
0070: public BerInputStream(byte[] encoded) throws IOException {
0071: this (encoded, 0, encoded.length);
0072: }
0073:
0074: /**
0075: * Creates stream for decoding.
0076: *
0077: * @param encoded -
0078: * bytes array to be decoded
0079: * @param offset -
0080: * the encoding offset
0081: * @param expectedLength -
0082: * expected length of full encoding, this includes identifier,
0083: * length an content octets
0084: * @throws IOException -
0085: * if an error occurs
0086: */
0087: public BerInputStream(byte[] encoded, int offset, int expectedLength)
0088: throws IOException {
0089:
0090: this .buffer = encoded;
0091: this .offset = offset;
0092:
0093: next();
0094:
0095: // compare expected and decoded length
0096: if (length != INDEFINIT_LENGTH
0097: && (offset + expectedLength) != (this .offset + this .length)) {
0098: throw new ASN1Exception(Messages.getString("security.111")); //$NON-NLS-1$
0099: }
0100: }
0101:
0102: /**
0103: * Creates stream for decoding.
0104: *
0105: * Allocates initial buffer of default size
0106: *
0107: * @param is associated <code>InputStream</code>
0108: */
0109: public BerInputStream(InputStream in) throws IOException {
0110: this (in, BUF_INCREASE_SIZE);
0111: }
0112:
0113: /**
0114: * Creates stream for decoding.
0115: *
0116: * Allocates initial buffer of <code>initialSize</code> size
0117: *
0118: * @param initialSize the internal buffer initial size
0119: * @param is associated <code>InputStream</code>
0120: */
0121: public BerInputStream(InputStream in, int initialSize)
0122: throws IOException {
0123:
0124: this .in = in;
0125: buffer = new byte[initialSize];
0126:
0127: next();
0128:
0129: if (length != INDEFINIT_LENGTH) {
0130: // input stream has definite length encoding
0131: // check allocated length to avoid further reallocations
0132: if (buffer.length < (length + offset)) {
0133: byte[] newBuffer = new byte[length + offset];
0134: System.arraycopy(buffer, 0, newBuffer, 0, offset);
0135: buffer = newBuffer;
0136: }
0137: } else {
0138: isIndefinedLength = true;
0139: throw new ASN1Exception(Messages.getString("security.112")); //$NON-NLS-1$
0140: }
0141: }
0142:
0143: /**
0144: * Resets this stream to initial state.
0145: *
0146: * @param encoded - a new bytes array to be decoded
0147: * @throws IOException - if an error occurs
0148: */
0149: public final void reset(byte[] encoded) throws IOException {
0150: buffer = encoded;
0151:
0152: next();
0153: }
0154:
0155: /**
0156: * Current decoded tag
0157: */
0158: public int tag;
0159:
0160: /**
0161: * Current decoded length
0162: */
0163: protected int length;
0164:
0165: /**
0166: * Current decoded content
0167: */
0168: public Object content;
0169:
0170: /**
0171: * Current decoded tag offset
0172: */
0173: protected int tagOffset;
0174:
0175: /**
0176: * Current decoded content offset
0177: */
0178: protected int contentOffset;
0179:
0180: /**
0181: * Decodes next encoded type.
0182: * Initializes tag, length, tagOffset and contentOffset variables
0183: *
0184: * @return next decoded tag
0185: * @throws IOException - if error occured
0186: */
0187: public int next() throws IOException {
0188:
0189: tagOffset = offset;
0190:
0191: // read tag
0192: tag = read();
0193:
0194: // read length
0195: length = read();
0196: if (length != 0x80) { // definite form
0197: // long or short length form
0198: if ((length & 0x80) != 0) { // long form
0199: int numOctets = length & 0x7F;
0200:
0201: if (numOctets > 5) {
0202: throw new ASN1Exception(Messages.getString(
0203: "security.113", //$NON-NLS-1$
0204: tagOffset)); //FIXME message
0205: }
0206:
0207: // collect this value length
0208: length = read();
0209: for (int i = 1; i < numOctets; i++) {
0210: int ch = read();
0211: length = (length << 8) + ch;//read();
0212: }
0213:
0214: if (length > 0xFFFFFF) {
0215: throw new ASN1Exception(Messages.getString(
0216: "security.113", //$NON-NLS-1$
0217: tagOffset)); //FIXME message
0218: }
0219: }
0220: } else { //indefinite form
0221: length = INDEFINIT_LENGTH;
0222: }
0223: contentOffset = offset;
0224:
0225: return tag;
0226: }
0227:
0228: /**
0229: * Returns the length of the encoding
0230: */
0231: public static int getLength(byte[] encoding) {
0232: int length = encoding[1] & 0xFF;
0233: int numOctets = 0;
0234: if ((length & 0x80) != 0) { // long form
0235: numOctets = length & 0x7F;
0236:
0237: // collect this value length
0238: length = encoding[2] & 0xFF;
0239: for (int i = 3; i < numOctets + 2; i++) {
0240: length = (length << 8) + (encoding[i] & 0xFF);
0241: }
0242: }
0243: // tag length long_form content
0244: return 1 + 1 + numOctets + length;
0245: }
0246:
0247: /**
0248: * Decodes ASN.1 bitstring type
0249: *
0250: * @throws IOException - if error occured
0251: */
0252: public void readBitString() throws IOException {
0253:
0254: if (tag == ASN1Constants.TAG_BITSTRING) {
0255:
0256: if (length == 0) {
0257: throw new ASN1Exception(Messages.getString(
0258: "security.114", tagOffset)); //$NON-NLS-1$
0259: }
0260:
0261: readContent();
0262:
0263: // content: check unused bits
0264: if (buffer[contentOffset] > 7) {
0265: throw new ASN1Exception(Messages.getString(
0266: "security.115", //$NON-NLS-1$
0267: contentOffset));
0268: }
0269:
0270: if (length == 1 && buffer[contentOffset] != 0) {
0271: throw new ASN1Exception(Messages.getString(
0272: "security.116", //$NON-NLS-1$
0273: contentOffset));
0274: }
0275:
0276: } else if (tag == ASN1Constants.TAG_C_BITSTRING) {
0277: throw new ASN1Exception(Messages.getString("security.117")); //$NON-NLS-1$
0278: } else {
0279: throw new ASN1Exception(Messages.getString(
0280: "security.118", tagOffset, //$NON-NLS-1$
0281: Integer.toHexString(tag)));
0282: }
0283: }
0284:
0285: /**
0286: * Decodes ASN.1 Enumerated type
0287: *
0288: * @throws IOException - if error occured
0289: */
0290: public void readEnumerated() throws IOException {
0291:
0292: if (tag != ASN1Constants.TAG_ENUM) {
0293: throw new ASN1Exception(Messages.getString(
0294: "security.119", tagOffset, //$NON-NLS-1$
0295: Integer.toHexString(tag)));
0296: }
0297:
0298: //
0299: // all checks are the same as for ASN.1 integer type
0300: //
0301:
0302: // check encoded length
0303: if (length == 0) {
0304: throw new ASN1Exception(Messages.getString(
0305: "security.11A", tagOffset));//$NON-NLS-1$
0306: }
0307:
0308: readContent();
0309:
0310: // check encoded content
0311: if (length > 1) {
0312:
0313: int bits = buffer[contentOffset] & 0xFF;
0314: if (buffer[contentOffset + 1] < 0) {
0315: bits += 0x100;
0316: }
0317:
0318: if (bits == 0 || bits == 0x1FF) {
0319: throw new ASN1Exception(Messages.getString(
0320: "security.11B", contentOffset)); //$NON-NLS-1$
0321: }
0322: }
0323: }
0324:
0325: /**
0326: * Decodes ASN.1 boolean type
0327: *
0328: * @throws IOException - if error occured
0329: */
0330: public void readBoolean() throws IOException {
0331:
0332: if (tag != ASN1Constants.TAG_BOOLEAN) {
0333: throw new ASN1Exception(Messages.getString("security.11C", //$NON-NLS-1$
0334: tagOffset, Integer.toHexString(tag)));
0335: }
0336:
0337: // check encoded length
0338: if (length != 1) {
0339: throw new ASN1Exception(Messages.getString(
0340: "security.11D", tagOffset));//$NON-NLS-1$
0341: }
0342:
0343: readContent();
0344: }
0345:
0346: /**
0347: * The last choice index
0348: */
0349: public int choiceIndex;
0350:
0351: /**
0352: * Keeps last decoded: year, month, day, hour, minute, second, millisecond
0353: */
0354: public int[] times;
0355:
0356: /**
0357: * Decodes ASN.1 GeneralizedTime type
0358: *
0359: * @throws IOException - if error occured
0360: */
0361: public void readGeneralizedTime() throws IOException {
0362:
0363: if (tag == ASN1Constants.TAG_GENERALIZEDTIME) {
0364:
0365: // FIXME: any other optimizations?
0366: readContent();
0367: // FIXME store string somewhere to allow a custom time type perform
0368: // additional checks
0369:
0370: // check syntax: the last char MUST be Z
0371: if (buffer[offset - 1] != 'Z') {
0372: // FIXME support only format that is acceptable for DER
0373: throw new ASN1Exception(Messages
0374: .getString("security.11E")); //$NON-NLS-1$
0375: }
0376:
0377: // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z'
0378: if (length != 15 && (length < 17 || length > 19)) // invalid
0379: // length
0380: {
0381: throw new ASN1Exception(Messages.getString(
0382: "security.11F", //$NON-NLS-1$
0383: contentOffset));
0384: }
0385:
0386: // check content: milliseconds
0387: if (length > 16) {
0388: byte char14 = buffer[contentOffset + 14];
0389: if (char14 != '.' && char14 != ',') {
0390: throw new ASN1Exception(Messages.getString(
0391: "security.11F", //$NON-NLS-1$
0392: contentOffset));
0393: }
0394: }
0395:
0396: if (times == null) {
0397: times = new int[7];
0398: }
0399: times[0] = strToInt(contentOffset, 4); // year
0400: times[1] = strToInt(contentOffset + 4, 2); // month
0401: times[2] = strToInt(contentOffset + 6, 2); // day
0402: times[3] = strToInt(contentOffset + 8, 2); // hour
0403: times[4] = strToInt(contentOffset + 10, 2); // minute
0404: times[5] = strToInt(contentOffset + 12, 2); // second
0405:
0406: if (length > 16) {
0407: // FIXME optimize me
0408: times[6] = strToInt(contentOffset + 15, length - 16);
0409:
0410: if (length == 17) {
0411: times[6] = times[6] * 100;
0412: } else if (length == 18) {
0413: times[6] = times[6] * 10;
0414: }
0415: }
0416:
0417: // FIXME check all values for valid numbers!!!
0418: } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) {
0419: throw new ASN1Exception(Messages.getString("security.120")); //$NON-NLS-1$
0420:
0421: } else {
0422: throw new ASN1Exception(Messages.getString("security.121", //$NON-NLS-1$
0423: tagOffset, Integer.toHexString(tag)));
0424: }
0425: }
0426:
0427: /**
0428: * Decodes ASN.1 UTCTime type
0429: *
0430: * @throws IOException - if an I/O error occurs or the end of the stream is reached
0431: */
0432: public void readUTCTime() throws IOException {
0433:
0434: if (tag == ASN1Constants.TAG_UTCTIME) {
0435:
0436: switch (length) {
0437: case ASN1UTCTime.UTC_HM:
0438: case ASN1UTCTime.UTC_HMS:
0439: break;
0440: case ASN1UTCTime.UTC_LOCAL_HM:
0441: case ASN1UTCTime.UTC_LOCAL_HMS:
0442: // FIXME only coordinated universal time formats are supported
0443: throw new ASN1Exception(Messages
0444: .getString("security.122")); //$NON-NLS-1$
0445: default:
0446: throw new ASN1Exception(Messages.getString(
0447: "security.123", //$NON-NLS-1$
0448: tagOffset));
0449: }
0450:
0451: // FIXME: any other optimizations?
0452: readContent();
0453:
0454: // FIXME store string somewhere to allow a custom time type perform
0455: // additional checks
0456:
0457: // check syntax: the last char MUST be Z
0458: if (buffer[offset - 1] != 'Z') {
0459: throw new ASN1Exception(
0460: "ASN.1 UTCTime wrongly encoded at [" //$NON-NLS-1$
0461: + contentOffset + ']');
0462: }
0463:
0464: if (times == null) {
0465: times = new int[7];
0466: }
0467:
0468: times[0] = strToInt(contentOffset, 2); // year
0469: if (times[0] > 49) {
0470: times[0] += 1900;
0471: } else {
0472: times[0] += 2000;
0473: }
0474:
0475: times[1] = strToInt(contentOffset + 2, 2); // month
0476: times[2] = strToInt(contentOffset + 4, 2); // day
0477: times[3] = strToInt(contentOffset + 6, 2); // hour
0478: times[4] = strToInt(contentOffset + 8, 2); // minute
0479:
0480: if (length == ASN1UTCTime.UTC_HMS) {
0481: times[5] = strToInt(contentOffset + 10, 2); // second
0482: }
0483:
0484: // FIXME check all time values for valid numbers!!!
0485: } else if (tag == ASN1Constants.TAG_C_UTCTIME) {
0486: throw new ASN1Exception(Messages.getString("security.124")); //$NON-NLS-1$
0487: } else {
0488: throw new ASN1Exception(Messages.getString("security.125", //$NON-NLS-1$
0489: tagOffset, Integer.toHexString(tag)));
0490: }
0491: }
0492:
0493: //TODO comment me
0494: private int strToInt(int off, int count) throws ASN1Exception {
0495:
0496: //FIXME works only with buffer
0497:
0498: int c;
0499: int result = 0;
0500: for (int i = off, end = off + count; i < end; i++) {
0501: c = buffer[i] - 48;
0502: if (c < 0 || c > 9) {
0503: throw new ASN1Exception(Messages
0504: .getString("security.126")); //$NON-NLS-1$
0505: }
0506: result = result * 10 + c;
0507: }
0508: return result;
0509: }
0510:
0511: /**
0512: * Decodes ASN.1 Integer type
0513: *
0514: * @throws IOException - if error occured
0515: */
0516: public void readInteger() throws IOException {
0517:
0518: if (tag != ASN1Constants.TAG_INTEGER) {
0519: throw new ASN1Exception(Messages.getString("security.127", //$NON-NLS-1$
0520: tagOffset, Integer.toHexString(tag)));
0521: }
0522:
0523: // check encoded length
0524: if (length < 1) {
0525: throw new ASN1Exception(Messages.getString("security.128", //$NON-NLS-1$
0526: tagOffset)); //$NON-NLS-1$
0527: }
0528:
0529: readContent();
0530:
0531: // check encoded content
0532: if (length > 1) {
0533:
0534: byte firstByte = buffer[offset - length];
0535: byte secondByte = (byte) (buffer[offset - length + 1] & 0x80);
0536:
0537: if (firstByte == 0 && secondByte == 0
0538: || firstByte == (byte) 0xFF
0539: && secondByte == (byte) 0x80) {
0540: throw new ASN1Exception(Messages.getString(
0541: "security.129", //$NON-NLS-1$
0542: (offset - length)));
0543: }
0544: }
0545: }
0546:
0547: /**
0548: * Decodes ASN.1 Octetstring type
0549: *
0550: * @throws IOException - if error occured
0551: */
0552: public void readOctetString() throws IOException {
0553:
0554: if (tag == ASN1Constants.TAG_OCTETSTRING) {
0555: readContent();
0556: } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) {
0557: throw new ASN1Exception(Messages.getString("security.12A")); //$NON-NLS-1$
0558: } else {
0559: throw new ASN1Exception(Messages.getString(
0560: "security.12B", tagOffset, //$NON-NLS-1$
0561: Integer.toHexString(tag)));
0562: }
0563: }
0564:
0565: //FIXME comment me
0566: public int oidElement;
0567:
0568: /**
0569: * Decodes ASN.1 ObjectIdentifier type
0570: *
0571: * @throws IOException - if error occured
0572: */
0573: public void readOID() throws IOException {
0574:
0575: if (tag != ASN1Constants.TAG_OID) {
0576: throw new ASN1Exception(Messages.getString("security.12C", //$NON-NLS-1$
0577: tagOffset, Integer.toHexString(tag)));
0578: }
0579:
0580: // check encoded length
0581: if (length < 1) {
0582: throw new ASN1Exception(Messages.getString(
0583: "security.12D", tagOffset)); //$NON-NLS-1$
0584: }
0585:
0586: readContent();
0587:
0588: // check content: last encoded byte (8th bit MUST be zero)
0589: if ((buffer[offset - 1] & 0x80) != 0) {
0590: throw new ASN1Exception(Messages.getString(
0591: "security.12E", (offset - 1))); //$NON-NLS-1$
0592: }
0593:
0594: oidElement = 1;
0595: for (int i = 0; i < length; i++, ++oidElement) {
0596:
0597: // According to ASN.1 BER spec:
0598: // leading octet of subidentifier MUST not be 0x80
0599: // This assertion is not verified
0600: //
0601: //if (buffer[contentOffset + i] == (byte)0x80) {
0602: // throw new ASN1Exception(
0603: // "Wrong content for ASN.1 object identifier at ["
0604: // + contentOffset
0605: // + "]. Subidentifier MUST be encoded in minimum number of octets");
0606: //}
0607:
0608: while ((buffer[contentOffset + i] & 0x80) == 0x80) {
0609: i++;
0610: }
0611: }
0612: }
0613:
0614: /**
0615: * Decodes ASN.1 Sequence type
0616: *
0617: * @param sequence - ASN.1 sequence to be decoded
0618: * @throws IOException - if error occured
0619: */
0620: public void readSequence(ASN1Sequence sequence) throws IOException {
0621:
0622: if (tag != ASN1Constants.TAG_C_SEQUENCE) {
0623: throw new ASN1Exception(Messages.getString(
0624: "security.12F", tagOffset, //$NON-NLS-1$
0625: Integer.toHexString(tag)));
0626: }
0627:
0628: int begOffset = offset;
0629: int endOffset = begOffset + length;
0630:
0631: ASN1Type[] type = sequence.type;
0632:
0633: int i = 0;
0634:
0635: if (isVerify) {
0636:
0637: for (; (offset < endOffset) && (i < type.length); i++) {
0638:
0639: next();
0640: while (!type[i].checkTag(tag)) {
0641: // check whether it is optional component or not
0642: if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
0643: throw new ASN1Exception(Messages.getString(
0644: "security.130", //$NON-NLS-1$
0645: tagOffset));
0646: }
0647: i++;
0648: }
0649:
0650: type[i].decode(this );
0651: }
0652:
0653: // check the rest of components
0654: for (; i < type.length; i++) {
0655: if (!sequence.OPTIONAL[i]) {
0656: throw new ASN1Exception(Messages.getString(
0657: "security.131", //$NON-NLS-1$
0658: tagOffset));
0659: }
0660: }
0661:
0662: } else {
0663:
0664: int seqTagOffset = tagOffset; //store tag offset
0665:
0666: Object[] values = new Object[type.length];
0667: for (; (offset < endOffset) && (i < type.length); i++) {
0668:
0669: next();
0670: while (!type[i].checkTag(tag)) {
0671: // check whether it is optional component or not
0672: if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
0673: throw new ASN1Exception(Messages.getString(
0674: "security.132", //$NON-NLS-1$
0675: tagOffset));
0676: }
0677:
0678: // sets default value
0679: if (sequence.DEFAULT[i] != null) {
0680: values[i] = sequence.DEFAULT[i];
0681: }
0682: i++;
0683: }
0684: values[i] = type[i].decode(this );
0685: }
0686:
0687: // check the rest of components
0688: for (; i < type.length; i++) {
0689: if (!sequence.OPTIONAL[i]) {
0690: throw new ASN1Exception(Messages.getString(
0691: "security.133", //$NON-NLS-1$
0692: tagOffset));
0693: }
0694: if (sequence.DEFAULT[i] != null) {
0695: values[i] = sequence.DEFAULT[i];
0696: }
0697: }
0698: content = values;
0699:
0700: tagOffset = seqTagOffset; //retrieve tag offset
0701: }
0702:
0703: if (offset != endOffset) {
0704: throw new ASN1Exception(Messages.getString(
0705: "security.134", begOffset)); //$NON-NLS-1$
0706: }
0707: }
0708:
0709: /**
0710: * Decodes ASN.1 SequenceOf type
0711: *
0712: * @param sequenceOf - ASN.1 sequence to be decoded
0713: * @throws IOException - if error occured
0714: */
0715: public void readSequenceOf(ASN1SequenceOf sequenceOf)
0716: throws IOException {
0717:
0718: if (tag != ASN1Constants.TAG_C_SEQUENCEOF) {
0719: throw new ASN1Exception(Messages.getString(
0720: "security.135", tagOffset, //$NON-NLS-1$
0721: Integer.toHexString(tag)));
0722: }
0723:
0724: decodeValueCollection(sequenceOf);
0725: }
0726:
0727: /**
0728: * Decodes ASN.1 Set type
0729: *
0730: * @param set - ASN.1 set to be decoded
0731: * @throws IOException - if error occured
0732: */
0733: public void readSet(ASN1Set set) throws IOException {
0734:
0735: if (tag != ASN1Constants.TAG_C_SET) {
0736: throw new ASN1Exception(Messages.getString("security.136", //$NON-NLS-1$
0737: tagOffset, Integer.toHexString(tag)));
0738: }
0739:
0740: throw new ASN1Exception(Messages.getString("security.137")); //$NON-NLS-1$
0741: }
0742:
0743: /**
0744: * Decodes ASN.1 SetOf type
0745: *
0746: * @param set - ASN.1 set to be decoded
0747: * @throws IOException - if error occured
0748: */
0749: public void readSetOf(ASN1SetOf setOf) throws IOException {
0750:
0751: if (tag != ASN1Constants.TAG_C_SETOF) {
0752: throw new ASN1Exception(Messages.getString("security.138", //$NON-NLS-1$
0753: tagOffset, Integer.toHexString(tag)));
0754: }
0755:
0756: decodeValueCollection(setOf);
0757: }
0758:
0759: private final void decodeValueCollection(
0760: ASN1ValueCollection collection) throws IOException {
0761:
0762: int begOffset = offset;
0763: int endOffset = begOffset + length;
0764:
0765: ASN1Type type = collection.type;
0766:
0767: if (isVerify) {
0768: while (endOffset > offset) {
0769: next();
0770: type.decode(this );
0771: }
0772: } else {
0773:
0774: int seqTagOffset = tagOffset; //store tag offset
0775:
0776: ArrayList values = new ArrayList();
0777: while (endOffset > offset) {
0778: next();
0779: values.add(type.decode(this ));
0780: }
0781:
0782: content = values;
0783:
0784: tagOffset = seqTagOffset; //retrieve tag offset
0785: }
0786:
0787: if (offset != endOffset) {
0788: throw new ASN1Exception(Messages.getString(
0789: "security.134", begOffset)); //$NON-NLS-1$
0790: }
0791: }
0792:
0793: /**
0794: * Decodes ASN.1 String type
0795: *
0796: * @throws IOException - if an I/O error occurs or the end of the stream is reached
0797: */
0798: public void readString(ASN1StringType type) throws IOException {
0799:
0800: //FIXME check string content
0801: if (tag == type.id) {
0802: readContent();
0803: } else if (tag == type.constrId) {
0804: throw new ASN1Exception(Messages.getString("security.139")); //$NON-NLS-1$
0805: } else {
0806: throw new ASN1Exception(Messages.getString(
0807: "security.13A", tagOffset, //$NON-NLS-1$
0808: Integer.toHexString(tag)));
0809: }
0810: }
0811:
0812: /**
0813: * Returns encoded array.
0814: *
0815: * MUST be invoked after decoding corresponding ASN.1 notation
0816: */
0817: public byte[] getEncoded() {
0818: byte[] encoded = new byte[offset - tagOffset];
0819: System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length);
0820: return encoded;
0821: }
0822:
0823: /**
0824: * Returns internal buffer used for decoding
0825: *
0826: * @return - buffer
0827: */
0828: public final byte[] getBuffer() {
0829: return buffer;
0830: }
0831:
0832: /**
0833: * Returns length of the current content for decoding
0834: *
0835: * @return - length of content
0836: */
0837: public final int getLength() {
0838: return length;
0839: }
0840:
0841: /**
0842: * Returns the current offset
0843: *
0844: * @return - offset
0845: */
0846: public final int getOffset() {
0847: return offset;
0848: }
0849:
0850: /**
0851: * Returns end offset for the current encoded type
0852: *
0853: * @return - offset
0854: */
0855: public final int getEndOffset() {
0856: return offset + length;
0857: }
0858:
0859: /**
0860: * Returns start offset for the current encoded type
0861: *
0862: * @return - offset
0863: */
0864: public final int getTagOffset() {
0865: return tagOffset;
0866: }
0867:
0868: public final int getContentOffset() {
0869: return contentOffset;
0870: }
0871:
0872: /**
0873: * Indicates verify or store mode.
0874: *
0875: * In store mode a decoded content is stored in a newly allocated
0876: * appropriate object. The <code>content</code> variable holds
0877: * a reference to the last created object.
0878: *
0879: * In verify mode a decoded content is not stored.
0880: */
0881: // FIXME it is used only for one case
0882: // decoding PCKS#8 Private Key Info notation
0883: // remove this option because it does decoding more complex
0884: protected boolean isVerify;
0885:
0886: /**
0887: * Sets verify mode.
0888: */
0889: public final void setVerify() {
0890: isVerify = true;
0891: }
0892:
0893: /**
0894: * Indicates defined or indefined reading mode for associated InputStream.
0895: *
0896: * This mode is defined by reading a length
0897: * for a first ASN.1 type from InputStream.
0898: */
0899: protected boolean isIndefinedLength;
0900:
0901: /**
0902: * Reads the next encoded byte from the encoded input stream.
0903: *
0904: * @return the next encoded byte
0905: * @throws IOException - if error occured
0906: */
0907: protected int read() throws IOException {
0908:
0909: if (offset == buffer.length) {
0910: throw new ASN1Exception(Messages.getString("security.13B")); //$NON-NLS-1$
0911: }
0912:
0913: if (in == null) {
0914: return buffer[offset++] & 0xFF;
0915: } else {
0916: int octet = in.read();
0917: if (octet == -1) {
0918: throw new ASN1Exception(Messages
0919: .getString("security.13B")); //$NON-NLS-1$
0920: }
0921:
0922: buffer[offset++] = (byte) octet;
0923:
0924: return octet;
0925: }
0926: }
0927:
0928: /**
0929: * Reads the next encoded content from the encoded input stream.
0930: * The method MUST be used for reading a primitive encoded content.
0931: *
0932: * @throws IOException - if error occured
0933: */
0934: public void readContent() throws IOException {
0935: if (offset + length > buffer.length) {
0936: throw new ASN1Exception(Messages.getString("security.13B")); //$NON-NLS-1$
0937: }
0938:
0939: if (in == null) {
0940: offset += length;
0941: } else {
0942: int bytesRead = in.read(buffer, offset, length);
0943:
0944: if (bytesRead != length) {
0945: // if input stream didn't return all data at once
0946: // try to read it in several blocks
0947: int c = bytesRead;
0948: do {
0949: if (c < 1 || bytesRead > length) {
0950: throw new ASN1Exception(Messages
0951: .getString("security.13C")); //$NON-NLS-1$
0952: }
0953: c = in.read(buffer, offset + bytesRead, length
0954: - bytesRead);
0955: bytesRead += c;
0956: } while (bytesRead != length);
0957: }
0958:
0959: offset += length;
0960: }
0961: }
0962:
0963: // // reallocates internal buffer for indefined reading mode
0964: // private void reallocateBuffer(int n) {
0965: // int newSize;
0966: // for (newSize = buffer.length * 2; newSize < buffer.length + n; newSize = newSize * 2)
0967: // ;
0968: // byte[] newBuffer = new byte[newSize];
0969: // System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
0970: // buffer = newBuffer;
0971: // }
0972:
0973: /**
0974: * Reallocates the buffer in order to make it
0975: * exactly the size of data it contains
0976: */
0977: public void compactBuffer() {
0978: if (offset != buffer.length) {
0979: byte[] newBuffer = new byte[offset];
0980: // restore buffer content
0981: System.arraycopy(buffer, 0, newBuffer, 0, offset);
0982: // set new buffer
0983: buffer = newBuffer;
0984: }
0985: }
0986:
0987: //
0988: //
0989: //
0990: //
0991: //
0992:
0993: private Object[][] pool;
0994:
0995: public void put(Object key, Object entry) {
0996:
0997: if (pool == null) {
0998: pool = new Object[2][10];
0999: }
1000:
1001: int i = 0;
1002: for (; i < pool[0].length && pool[0][i] != null; i++) {
1003: if (pool[0][i] == key) {
1004: pool[1][i] = entry;
1005: return;
1006: }
1007: }
1008:
1009: if (i == pool[0].length) {
1010: Object[][] newPool = new Object[pool[0].length * 2][2];
1011: System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length);
1012: System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length);
1013: pool = newPool;
1014: } else {
1015: pool[0][i] = key;
1016: pool[1][i] = entry;
1017: }
1018: }
1019:
1020: public Object get(Object key) {
1021:
1022: if (pool == null) {
1023: return null;
1024: }
1025:
1026: for (int i = 0; i < pool[0].length; i++) {
1027: if (pool[0][i] == key) {
1028: return pool[1][i];
1029: }
1030: }
1031: return null;
1032: }
1033: }
|