/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ /** * @author Stepan M. Mishura */ package org.apache.harmony.security.tests.asn1.der; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import junit.framework.TestCase; import org.apache.harmony.security.asn1.ASN1Boolean; import org.apache.harmony.security.asn1.ASN1Constants; import org.apache.harmony.security.asn1.ASN1Exception; import org.apache.harmony.security.asn1.ASN1Implicit; import org.apache.harmony.security.asn1.ASN1OctetString; import org.apache.harmony.security.asn1.ASN1SequenceOf; import org.apache.harmony.security.asn1.ASN1Type; import org.apache.harmony.security.asn1.DerInputStream; import org.apache.harmony.security.asn1.DerOutputStream; /** * ASN.1 DER test for Implicitly tagged type * * @see http://asn1.elibel.tm.fr/en/standards/index.htm */ public class ImplicitTest extends TestCase { private static ASN1SequenceOf sequence = new ASN1SequenceOf(ASN1Boolean .getInstance()); private static Object[][] taggedType = { // format: object to encode / ASN.1 tagged type / byte array // // Boolean = false // // [UNIVERSAL 5] Boolean { Boolean.FALSE, new byte[] { 0x05, 0x01, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_UNIVERSAL, 5, ASN1Boolean.getInstance()) }, // [APPLICATION 5] Boolean { Boolean.FALSE, new byte[] { 0x45, 0x01, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_APPLICATION, 5, ASN1Boolean.getInstance()) }, // [CONTEXT-SPECIFIC 5] Boolean { Boolean.FALSE, new byte[] { (byte) 0x85, 0x01, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 5, ASN1Boolean.getInstance()) }, // [5] Boolean (default = CONTEXT-SPECIFIC) { Boolean.FALSE, new byte[] { (byte) 0x85, 0x01, 0x00 }, new ASN1Implicit(5, ASN1Boolean.getInstance()) }, // [PRIVATE 5] Boolean { Boolean.FALSE, new byte[] { (byte) 0xC5, 0x01, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_PRIVATE, 5, ASN1Boolean.getInstance()) }, // // Boolean = true // // [UNIVERSAL 5] Boolean { Boolean.TRUE, new byte[] { 0x05, 0x01, (byte) 0xFF }, new ASN1Implicit(ASN1Constants.CLASS_UNIVERSAL, 5, ASN1Boolean.getInstance()) }, // [APPLICATION 5] Boolean { Boolean.TRUE, new byte[] { 0x45, 0x01, (byte) 0xFF }, new ASN1Implicit(ASN1Constants.CLASS_APPLICATION, 5, ASN1Boolean.getInstance()) }, // [CONTEXT-SPECIFIC 5] Boolean { Boolean.TRUE, new byte[] { (byte) 0x85, 0x01, (byte) 0xFF }, new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 5, ASN1Boolean.getInstance()) }, // [5] Boolean (default = CONTEXT-SPECIFIC) { Boolean.TRUE, new byte[] { (byte) 0x85, 0x01, (byte) 0xFF }, new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 5, ASN1Boolean.getInstance()) }, // [PRIVATE 5] Boolean { Boolean.TRUE, new byte[] { (byte) 0xC5, 0x01, (byte) 0xFF }, new ASN1Implicit(ASN1Constants.CLASS_PRIVATE, 5, ASN1Boolean.getInstance()) }, // // SequenceOf - testing constructed ASN.1 type // // [UNIVERSAL 5] SequenceOf { new ArrayList(), new byte[] { 0x25, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_UNIVERSAL, 5, sequence) }, // [APPLICATION 5] SequenceOf { new ArrayList(), new byte[] { 0x65, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_APPLICATION, 5, sequence) }, // [CONTEXT-SPECIFIC 5] SequenceOf { new ArrayList(), new byte[] { (byte) 0xA5, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 5, sequence) }, // [5] SequenceOf (default = CONTEXT-SPECIFIC) { new ArrayList(), new byte[] { (byte) 0xA5, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 5, sequence) }, // [PRIVATE 5] SequenceOf { new ArrayList(), new byte[] { (byte) 0xE5, 0x00 }, new ASN1Implicit(ASN1Constants.CLASS_PRIVATE, 5, sequence) } }; public void testDecode_Valid() throws IOException { for (int i = 0; i < taggedType.length; i++) { DerInputStream in = new DerInputStream((byte[]) taggedType[i][1]); assertEquals("Test case: " + i, taggedType[i][0], ((ASN1Type) taggedType[i][2]).decode(in)); } } // FIXME need testcase for decoding invalid encodings public void testEncode() throws IOException { for (int i = 0; i < taggedType.length; i++) { DerOutputStream out = new DerOutputStream( (ASN1Type) taggedType[i][2], taggedType[i][0]); assertTrue("Test case: " + i, Arrays.equals( (byte[]) taggedType[i][1], out.encoded)); } } /** * Tests 2 consecutive implicit string type tagging * * TYPE1 = [1] IMPLICIT OCTET STRING * TYPE2 = [2] IMPLICIT TYPE1 */ public void testConsecutiveStringTagging() throws Exception { ASN1Implicit type1 = new ASN1Implicit(1, ASN1OctetString.getInstance()); ASN1Implicit type2 = new ASN1Implicit(2, type1); byte[] primitiveEncoding = new byte[] { // tag: class(CONTEXT SPECIFIC) + number (2) (byte) 0x82, // length 0x03, // value 0x00, 0x01, 0x02 }; byte[] constructedEncoding = new byte[] { // tag: class(CONTEXT SPECIFIC) + constructed +number (2) (byte) 0xA2, // length 0x00 }; byte[] array = new byte[] { 0x00, 0x01, 0x02 }; // decode primitive assertTrue(Arrays.equals(array, (byte[]) type2 .decode(primitiveEncoding))); // encode primitive assertTrue(Arrays.equals(primitiveEncoding, type2.encode(array))); // decode constructed try { type2.decode(constructedEncoding); fail("No expected ASN1Exception"); } catch (ASN1Exception e) { // FIXME any other check instead of comparing the message??? assertEquals( "ASN.1 octetstring: constructed identifier at [0]. Not valid for DER.", e.getMessage()); } } }