private int strToInt(int off, int count) throws ASN1Exception { int result = 0; for (int i = off, end = off + count; i < end; i++) { int c = buffer[i] - 48; if (c < 0 || c > 9) { throw new ASN1Exception("Time encoding has invalid char"); } result = result * 10 + c; } return result; }
private ASN1Exception expected(String what) throws ASN1Exception { throw new ASN1Exception("ASN.1 " + what + " identifier expected at [" + tagOffset + "], got " + Integer.toHexString(tag)); }
/** * Reads the next encoded byte from the encoded input stream. */ protected int read() throws IOException { if (offset == buffer.length) { throw new ASN1Exception("Unexpected end of encoding"); } if (in == null) { return buffer[offset++] & 0xFF; } else { int octet = in.read(); if (octet == -1) { throw new ASN1Exception("Unexpected end of encoding"); } buffer[offset++] = (byte) octet; return octet; } }
public void readUTCTime() throws IOException { if (tag == ASN1Constants.TAG_C_UTCTIME) { // It is a string type and it can be encoded as primitive or constructed. throw new ASN1Exception("ASN.1 UTCTime: constructed identifier at [" + tagOffset + "]. Not valid for DER."); } // check format: DER uses YYMMDDHHMMSS'Z' only if (length != ASN1UTCTime.UTC_HMS) { throw new ASN1Exception("ASN.1 UTCTime: wrong format for DER, identifier at [" + tagOffset + "]"); } super.readUTCTime(); }
throw new ASN1Exception("ASN.1 Named Bitstring: size constraints");
public void readBitString() throws IOException { if (tag == ASN1Constants.TAG_C_BITSTRING) { throw new ASN1Exception("ASN.1 bitstring: constructed identifier at [" + tagOffset + "]. Not valid for DER."); } super.readBitString(); //check: unused bits values - MUST be 0 if (length > 1 && buffer[contentOffset] != 0 && (buffer[offset - 1] & UNUSED_BITS_MASK[buffer[contentOffset] - 1]) != 0) { throw new ASN1Exception("ASN.1 bitstring: wrong content at [" + contentOffset + "]. DER requires zero unused bits in final octet."); } }
/** * Reads the next encoded content from the encoded input stream. * The method MUST be used for reading a primitive encoded content. */ public void readContent() throws IOException { if (offset + length > buffer.length) { throw new ASN1Exception("Unexpected end of encoding"); } if (in == null) { offset += length; } else { int bytesRead = in.read(buffer, offset, length); if (bytesRead != length) { // if input stream didn't return all data at once // try to read it in several blocks int c = bytesRead; do { if (c < 1 || bytesRead > length) { throw new ASN1Exception("Failed to read encoded content"); } c = in.read(buffer, offset + bytesRead, length - bytesRead); bytesRead += c; } while (bytesRead != length); } offset += length; } }
public int next() throws IOException { int tag = super.next(); if (length == INDEFINIT_LENGTH) { throw new ASN1Exception("DER: only definite length encoding MUST be used"); } // FIXME add check: length encoding uses minimum number of octets return tag; }
public void readOctetString() throws IOException { if (tag == ASN1Constants.TAG_C_OCTETSTRING) { throw new ASN1Exception("ASN.1 octetstring: constructed identifier at [" + tagOffset + "]. Not valid for DER."); } super.readOctetString(); }
/** * Decodes ASN.1 Set type */ public void readSet(ASN1Set set) throws IOException { if (tag != ASN1Constants.TAG_C_SET) { throw expected("set"); } throw new ASN1Exception("Decoding ASN.1 Set type is not supported"); }
public void readGeneralizedTime() throws IOException { if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) { // It is a string type and it can be encoded as primitive or constructed. throw new ASN1Exception("ASN.1 GeneralizedTime: constructed identifier at [" + tagOffset + "]. Not valid for DER."); } super.readGeneralizedTime(); } }
public void readString(ASN1StringType type) throws IOException { if (tag == type.constrId) { throw new ASN1Exception("ASN.1 string: constructed identifier at [" + tagOffset + "]. Not valid for DER."); } super.readString(type); }
public void readBoolean() throws IOException { super.readBoolean(); // check encoded content if (buffer[contentOffset] != 0 && buffer[contentOffset] != (byte) 0xFF) { throw new ASN1Exception("ASN.1 boolean: wrong content at [" + contentOffset + "]. DER allows only 0x00 or 0xFF values"); } }
/** * Decodes ASN.1 bitstring type */ public void readBitString() throws IOException { if (tag == ASN1Constants.TAG_BITSTRING) { if (length == 0) { throw new ASN1Exception("ASN.1 Bitstring: wrong length. Tag at [" + tagOffset + "]"); } readContent(); // content: check unused bits if (buffer[contentOffset] > 7) { throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset + "]. A number of unused bits MUST be in range 0 to 7"); } if (length == 1 && buffer[contentOffset] != 0) { throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset + "]. For empty string unused bits MUST be 0"); } } else if (tag == ASN1Constants.TAG_C_BITSTRING) { throw new ASN1Exception("Decoding constructed ASN.1 bitstring type is not provided"); } else { throw expected("bitstring"); } }
/** * Creates stream for decoding. * * @param encoded bytes array to be decoded * @param offset the encoding offset * @param expectedLength expected length of full encoding, this includes * identifier, length an content octets */ public BerInputStream(byte[] encoded, int offset, int expectedLength) throws IOException { this.in = null; this.buffer = encoded; this.offset = offset; next(); // compare expected and decoded length if (length != INDEFINIT_LENGTH && (offset + expectedLength) != (this.offset + this.length)) { throw new ASN1Exception("Wrong content length"); } }
public Object decode(BerInputStream in) throws IOException { int index = Arrays.binarySearch(identifiers[0], in.tag); if (index < 0) { throw new ASN1Exception("Failed to decode ASN.1 choice type. No alternatives were found for " + getClass().getName());// FIXME message } index = identifiers[1][index]; in.content = type[index].decode(in); // set index for getDecodedObject method in.choiceIndex = index; if (in.isVerify) { return null; } return getDecodedObject(in); }
/** * Creates stream for decoding. * * @param initialSize the internal buffer initial size */ public BerInputStream(InputStream in, int initialSize) throws IOException { this.in = in; buffer = new byte[initialSize]; next(); if (length != INDEFINIT_LENGTH) { // input stream has definite length encoding // check allocated length to avoid further reallocations if (buffer.length < (length + offset)) { byte[] newBuffer = new byte[length + offset]; System.arraycopy(buffer, 0, newBuffer, 0, offset); buffer = newBuffer; } } else { isIndefinedLength = true; throw new ASN1Exception("Decoding indefinite length encoding is not supported"); } }
/** * Decodes ASN.1 Integer type */ public void readInteger() throws IOException { if (tag != ASN1Constants.TAG_INTEGER) { throw expected("integer"); } // check encoded length if (length < 1) { throw new ASN1Exception("Wrong length for ASN.1 integer at [" + tagOffset + "]"); } readContent(); // check encoded content if (length > 1) { byte firstByte = buffer[offset - length]; byte secondByte = (byte) (buffer[offset - length + 1] & 0x80); if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF && secondByte == (byte) 0x80) { throw new ASN1Exception("Wrong content for ASN.1 integer at [" + (offset - length) + "]. An integer MUST be encoded in minimum number of octets"); } } }
/** * Decodes ASN.1 ObjectIdentifier type */ public void readOID() throws IOException { if (tag != ASN1Constants.TAG_OID) { throw expected("OID"); } // check encoded length if (length < 1) { throw new ASN1Exception("Wrong length for ASN.1 object identifier at [" + tagOffset + "]"); } readContent(); // check content: last encoded byte (8th bit MUST be zero) if ((buffer[offset - 1] & 0x80) != 0) { throw new ASN1Exception("Wrong encoding at [" + (offset - 1) + "]"); } oidElement = 1; for (int i = 0; i < length; i++, ++oidElement) { while ((buffer[contentOffset + i] & 0x80) == 0x80) { i++; } } }
/** * Decodes ASN.1 Enumerated type */ public void readEnumerated() throws IOException { if (tag != ASN1Constants.TAG_ENUM) { throw expected("enumerated"); } // check encoded length if (length == 0) { throw new ASN1Exception("ASN.1 enumerated: wrong length for identifier at [" + tagOffset + "]"); } readContent(); // check encoded content if (length > 1) { int bits = buffer[contentOffset] & 0xFF; if (buffer[contentOffset + 1] < 0) { bits += 0x100; } if (bits == 0 || bits == 0x1FF) { throw new ASN1Exception("ASN.1 enumerated: wrong content at [" + contentOffset + "]. An integer MUST be encoded in minimum number of octets"); } } }