package model.asn1; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import org.junit.jupiter.api.Test; import java.time.ZoneId; import java.time.ZonedDateTime; import static org.junit.jupiter.api.Assertions.*; public class ASN1ObjectTest { @Test void testParseType() throws ParseException { assertEquals(Bool.class, ASN1Object.parse(new BytesReader(new Bool(Bool.TAG, null, true).encodeDER()), false).getClass()); assertEquals(Int.class, ASN1Object.parse(new BytesReader(new Int(Int.TAG, null, 1).encodeDER()), false).getClass()); assertEquals(BitString.class, ASN1Object.parse(new BytesReader(new BitString(BitString.TAG, null, 0, new Byte[]{1}).encodeDER()), false).getClass()); assertEquals(OctetString.class, ASN1Object.parse(new BytesReader(new OctetString(OctetString.TAG, null, new Byte[]{1}).encodeDER()), false).getClass()); assertEquals(Null.class, ASN1Object.parse(new BytesReader(new Null(Null.TAG, null).encodeDER()), false).getClass()); assertEquals(ObjectIdentifier.class, ASN1Object.parse(new BytesReader(new ObjectIdentifier(ObjectIdentifier.TAG, null, new Integer[]{1, 2, 3}).encodeDER()), false).getClass()); assertEquals(UTF8String.class, ASN1Object.parse(new BytesReader(new UTF8String(UTF8String.TAG, null, "qwq").encodeDER()), false).getClass()); assertEquals(PrintableString.class, ASN1Object.parse(new BytesReader(new PrintableString(PrintableString.TAG, null, "qwq").encodeDER()), false).getClass()); assertEquals(IA5String.class, ASN1Object.parse(new BytesReader(new IA5String(IA5String.TAG, null, "qwq").encodeDER()), false).getClass()); assertEquals(UtcTime.class, ASN1Object.parse(new BytesReader(new UtcTime(UtcTime.TAG, null, ZonedDateTime.now(ZoneId.of("UTC"))).encodeDER()), false).getClass()); assertEquals(GeneralizedTime.class, ASN1Object.parse(new BytesReader(new GeneralizedTime(GeneralizedTime.TAG, null, ZonedDateTime.now(ZoneId.of("UTC"))).encodeDER()), false).getClass()); assertEquals(ASN1Object.class, ASN1Object.parse(new BytesReader(new Byte[]{0x30, 1, 0x0}), false) .getClass()); } @Test void testConstructor() { assertEquals(0, new ASN1Object(Null.TAG, null).getLength()); assertNull(new ASN1Object(Null.TAG, null).encodeValueDER()); assertEquals(0x5, new ASN1Object(new Tag(TagClass.UNIVERSAL, false, 0x5), null).getTag().getNumber()); assertEquals(0x6, new ASN1Object(new Tag(TagClass.UNIVERSAL, false, 0x5), new Tag(TagClass.UNIVERSAL, false, 0x6)).getParentTag().getNumber()); } @Test void testParseSuccess() throws ParseException { // No parent tag assertEquals(0x5, new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .getTag().getNumber()); assertEquals(TagClass.UNIVERSAL, new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .getTag().getCls()); assertFalse(new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .getTag().isConstructive()); assertNull(new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .getParentTag()); assertEquals(0, new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .encodeValueDER().length); assertEquals(0, new ASN1Object(new BytesReader(new Byte[]{0x5, 0x0}), false) .getLength()); // With parent tag // -95 is the 2's complement represent of 0b10100001 assertEquals(0x5, new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getTag().getNumber()); assertEquals(TagClass.UNIVERSAL, new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getTag().getCls()); assertFalse(new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getTag().isConstructive()); assertEquals(0x1, new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getParentTag().getNumber()); assertEquals(TagClass.CONTEXT_SPECIFIC, new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getParentTag().getCls()); assertTrue(new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5, 0x0}), true) .getParentTag().isConstructive()); // Test index BytesReader reader = new BytesReader(new Byte[]{0xE, 5, 1, 2, 3, 4, 5}); ASN1Object obj = new ASN1Object(reader, false); // Contents should not be read. assertEquals(2, reader.getIndex()); // But is copied assertArrayEquals(new Byte[]{1, 2, 3, 4, 5}, obj.encodeValueDER()); // If we parse an unknown type reader = new BytesReader(new Byte[]{0xE, 5, 1, 2, 3, 4, 5}); obj = ASN1Object.parse(reader, false); // Contents should be read now assertEquals(7, reader.getIndex()); } @Test void testParseFail() { // Value early EOF assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{0x5, 0x1}), false)); // Tag early EOF assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-95, 2}), true)); // Length not found assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{0x5}), false)); assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-95, 2, 0x5}), true)); // Parent tag is not CONTEXT_SPECIFIC // UNIVERSAL assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{33, 2, 0x5, 0x0}), true)); // APPLICATION assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{97, 2, 0x5, 0x0}), true)); // PRIVATE assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-31, 2, 0x5, 0x0}), true)); // Parent tag is not constructive assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-127, 2, 0x5, 0x0}), true)); // Parent tag length incorrect assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-95, 0, 0x5, 0x0}), true)); assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-95, 1, 0x5, 0x0}), true)); assertThrows(ParseException.class, () -> new ASN1Object(new BytesReader(new Byte[]{-95, 3, 0x5, 0x0}), true)); } @Test void testEncode() { // No parent tag assertArrayEquals(new Byte[]{ 0x5, 0x0 }, new Null(Null.TAG, null).encodeDER()); // Custom tag assertArrayEquals(new Byte[]{ 0x72, 0x0 }, new Null(new Tag(TagClass.APPLICATION, true, 0x12), null) .encodeDER()); // With parent tag assertArrayEquals(new Byte[]{ -95, 2, 0x72, 0x0 }, new Null(new Tag(TagClass.APPLICATION, true, 0x12), new Tag(TagClass.CONTEXT_SPECIFIC, true, 0x1)) .encodeDER()); } }