blob: c74a74f2ec8565f1a131fc86a6c7dcce80889170 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.apksig.internal.asn1.ber;
import static com.android.apksig.internal.test.MoreAsserts.assertByteBufferEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import com.android.apksig.internal.test.HexEncoding;
/**
* Base class for unit tests of ASN.1 BER (see {@code X.690}) data value reader implementations.
*
* <p>Subclasses need to provide only an implementation of {@link #createReader(byte[])} and
* subclass-specific tests.
*/
public abstract class BerDataValueReaderTestBase {
/**
* Returns a new reader initialized with the provided input.
*/
protected abstract BerDataValueReader createReader(byte[] input);
@Test
public void testEmptyInput() throws Exception {
assertNull(readDataValue(""));
}
@Test
public void testEndOfInput() throws Exception {
BerDataValueReader reader = createReader("3000"); // SEQUENCE with empty contents
assertNotNull(reader.readDataValue());
// End of input has been reached
assertNull(reader.readDataValue());
// Null should also be returned on consecutive invocations
assertNull(reader.readDataValue());
}
@Test
public void testSingleByteTagId() throws Exception {
BerDataValue dataValue = readDataValue("1000");
assertEquals(BerEncoding.TAG_CLASS_UNIVERSAL, dataValue.getTagClass());
assertFalse(dataValue.isConstructed());
assertEquals(0x10, dataValue.getTagNumber());
dataValue = readDataValue("3900");
assertEquals(BerEncoding.TAG_CLASS_UNIVERSAL, dataValue.getTagClass());
assertTrue(dataValue.isConstructed());
assertEquals(0x19, dataValue.getTagNumber());
dataValue = readDataValue("6700");
assertEquals(BerEncoding.TAG_CLASS_APPLICATION, dataValue.getTagClass());
assertTrue(dataValue.isConstructed());
assertEquals(7, dataValue.getTagNumber());
dataValue = readDataValue("8600");
assertEquals(BerEncoding.TAG_CLASS_CONTEXT_SPECIFIC, dataValue.getTagClass());
assertFalse(dataValue.isConstructed());
assertEquals(6, dataValue.getTagNumber());
dataValue = readDataValue("fe00");
assertEquals(BerEncoding.TAG_CLASS_PRIVATE, dataValue.getTagClass());
assertTrue(dataValue.isConstructed());
assertEquals(0x1e, dataValue.getTagNumber());
}
@Test
public void testHighTagNumber() throws Exception {
assertEquals(7, readDataValue("3f0700").getTagNumber());
assertEquals(7, readDataValue("3f800700").getTagNumber());
assertEquals(7, readDataValue("3f80800700").getTagNumber());
assertEquals(7, readDataValue("3f8080800700").getTagNumber());
assertEquals(7, readDataValue("3f808080808080808080808080808080800700").getTagNumber());
assertEquals(375, readDataValue("3f827700").getTagNumber());
assertEquals(268435455, readDataValue("3fffffff7f00").getTagNumber());
assertEquals(Integer.MAX_VALUE, readDataValue("3f87ffffff7f00").getTagNumber());
}
@Test(expected = BerDataValueFormatException.class)
public void testHighTagNumberTooLarge() throws Exception {
readDataValue("3f888080800000"); // Integer.MAX_VALUE + 1
}
// @Test(expected = BerDataValueFormatException.class)
public void testTruncatedHighTagNumberLastOctetMissing() throws Exception {
readDataValue("9f80"); // terminating octet must not have the highest bit set
}
@Test(expected = BerDataValueFormatException.class)
public void testTruncatedBeforeFirstLengthOctet() throws Exception {
readDataValue("30");
}
@Test
public void testShortFormLength() throws Exception {
assertByteBufferEquals(new byte[0], readDataValue("3000").getEncodedContents());
assertByteBufferEquals(
HexEncoding.decode("010203"), readDataValue("3003010203").getEncodedContents());
}
@Test
public void testLongFormLength() throws Exception {
assertByteBufferEquals(new byte[0], readDataValue("308100").getEncodedContents());
assertByteBufferEquals(
HexEncoding.decode("010203"), readDataValue("30820003010203").getEncodedContents());
assertEquals(
255,
readDataValue(concat(HexEncoding.decode("3081ff"), new byte[255]))
.getEncodedContents().remaining());
assertEquals(
0x110,
readDataValue(concat(HexEncoding.decode("30820110"), new byte[0x110]))
.getEncodedContents().remaining());
}
@Test(expected = BerDataValueFormatException.class)
public void testTruncatedLongFormLengthBeforeFirstLengthByte() throws Exception {
readDataValue("3081");
}
@Test(expected = BerDataValueFormatException.class)
public void testTruncatedLongFormLengthLastLengthByteMissing() throws Exception {
readDataValue("308200");
}
@Test(expected = BerDataValueFormatException.class)
public void testLongFormLengthTooLarge() throws Exception {
readDataValue("3084ffffffff");
}
@Test
public void testIndefiniteFormLength() throws Exception {
assertByteBufferEquals(new byte[0], readDataValue("30800000").getEncodedContents());
assertByteBufferEquals(
HexEncoding.decode("010203"), readDataValue("30800102030000").getEncodedContents());
assertByteBufferEquals(
HexEncoding.decode(
"000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"),
readDataValue(
"3080"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "000102030405060708090a0b0c0d0e0f"
+ "0000"
).getEncodedContents());
}
@Test(expected = BerDataValueFormatException.class)
public void testDefiniteLengthContentsTruncatedBeforeFirstContentOctet() throws Exception {
readDataValue("3001");
}
@Test(expected = BerDataValueFormatException.class)
public void testIndefiniteLengthContentsTruncatedBeforeFirstContentOctet() throws Exception {
readDataValue("3080");
}
@Test(expected = BerDataValueFormatException.class)
public void testTruncatedDefiniteLengthContents() throws Exception {
readDataValue("30030102");
}
@Test(expected = BerDataValueFormatException.class)
public void testTruncatedIndefiniteLengthContents() throws Exception {
readDataValue("308001020300");
}
@Test
public void testEmptyDefiniteLengthContents() throws Exception {
assertByteBufferEquals(new byte[0], readDataValue("3000").getEncodedContents());
}
@Test
public void testEmptyIndefiniteLengthContents() throws Exception {
assertByteBufferEquals(new byte[0], readDataValue("30800000").getEncodedContents());
}
@Test
public void testReadAdvancesPosition() throws Exception {
BerDataValueReader reader = createReader("37018f050001020304");
assertByteBufferEquals(HexEncoding.decode("37018f"), reader.readDataValue().getEncoded());
assertByteBufferEquals(HexEncoding.decode("0500"), reader.readDataValue().getEncoded());
assertByteBufferEquals(HexEncoding.decode("01020304"), reader.readDataValue().getEncoded());
assertNull(reader.readDataValue());
}
private BerDataValueReader createReader(String hexEncodedInput) {
return createReader(HexEncoding.decode(hexEncodedInput));
}
private BerDataValue readDataValue(byte[] input)
throws BerDataValueFormatException {
return createReader(input).readDataValue();
}
private BerDataValue readDataValue(String hexEncodedInput)
throws BerDataValueFormatException {
return createReader(hexEncodedInput).readDataValue();
}
private static byte[] concat(byte[] arr1, byte[] arr2) {
byte[] result = new byte[arr1.length + arr2.length];
System.arraycopy(arr1, 0, result, 0, arr1.length);
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
return result;
}
}