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()); } }