1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /** 19 * @author Stepan M. Mishura 20 */ 21 22 package org.apache.harmony.security.tests.asn1.der; 23 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.List; 28 29 import org.apache.harmony.security.asn1.ASN1Boolean; 30 import org.apache.harmony.security.asn1.ASN1Exception; 31 import org.apache.harmony.security.asn1.ASN1Integer; 32 import org.apache.harmony.security.asn1.ASN1Sequence; 33 import org.apache.harmony.security.asn1.ASN1SequenceOf; 34 import org.apache.harmony.security.asn1.ASN1Type; 35 import org.apache.harmony.security.asn1.BerInputStream; 36 import org.apache.harmony.security.asn1.DerInputStream; 37 import org.apache.harmony.security.asn1.DerOutputStream; 38 39 import junit.framework.TestCase; 40 41 42 /** 43 * ASN.1 DER test for Sequence type 44 * 45 * @see http://asn1.elibel.tm.fr/en/standards/index.htm 46 */ 47 48 public class SequenceTest extends TestCase { 49 50 private static ASN1SequenceOf sequenceOf = new ASN1SequenceOf(ASN1Boolean 51 .getInstance()); 52 53 private static ArrayList defaultList; 54 55 private static ASN1Sequence sequence; 56 57 private static Object[][] testcases; 58 59 protected void setUp() throws Exception { 60 super.setUp(); 61 62 // 63 // sequence ::= SEQUENCE { 64 // boolean BOOLEAN, DEFAULT true 65 // list SEQUENCE OF BOOLEAN, DEFAULT list(false) 66 // } 67 // 68 69 defaultList = new ArrayList(); 70 defaultList.add(Boolean.FALSE); 71 72 sequence = new ASN1Sequence(new ASN1Type[] { ASN1Boolean.getInstance(), 73 sequenceOf }) { 74 { 75 setDefault(Boolean.TRUE, 0); 76 setDefault(defaultList, 1); 77 } 78 79 protected Object getDecodedObject(BerInputStream in) 80 throws IOException { 81 Object[] values = (Object[]) in.content; 82 return new AppClass((Boolean) values[0], (List) values[1]); 83 } 84 85 protected void getValues(Object object, Object[] values) { 86 AppClass obj = (AppClass) object; 87 88 values[0] = obj.ok; 89 values[1] = obj.list; 90 } 91 }; 92 93 // 94 // Test Cases 95 // 96 97 testcases = new Object[][] { 98 // format: object to encode / byte array 99 100 // sequence : all values are default 101 { new AppClass(Boolean.TRUE, defaultList), 102 new byte[] { 0x30, 0x00 } }, 103 104 // sequence : true, default 105 { new AppClass(Boolean.FALSE, defaultList), 106 new byte[] { 0x30, 0x03, 0x01, 0x01, 0x00 } }, 107 108 // sequence = default, empty sequence 109 { new AppClass(Boolean.TRUE, new ArrayList()), 110 new byte[] { 0x30, 0x02, 0x30, 0x00 } }, 111 112 // sequence = false, empty sequence 113 { new AppClass(Boolean.FALSE, new ArrayList()), 114 new byte[] { 0x30, 0x05, 0x01, 0x01, 0x00, 0x30, 0x00 } }, 115 116 //TODO add testcase for another ASN.1 type` 117 118 }; 119 } 120 121 // 122 // Application class 123 // 124 125 public static class AppClass { 126 127 public Boolean ok; 128 129 public List list; 130 131 public AppClass(Boolean ok, List list) { 132 this.ok = ok; 133 this.list = list; 134 } 135 136 public boolean equals(Object o) { 137 if (o instanceof AppClass) { 138 AppClass obj = (AppClass) o; 139 return ok.equals(obj.ok) && list.equals(obj.list); 140 } 141 return false; 142 } 143 } 144 145 public void testDecode_Valid() throws IOException { 146 147 for (int i = 0; i < testcases.length; i++) { 148 try { 149 DerInputStream in = new DerInputStream((byte[]) testcases[i][1]); 150 assertEquals("Test case: " + i, testcases[i][0], sequence 151 .decode(in)); 152 } catch (ASN1Exception e) { 153 fail("Test case: " + i + "\n" + e.getMessage()); 154 } 155 } 156 } 157 158 //FIXME need testcase for decoding invalid encodings 159 160 public void testEncode() throws IOException { 161 162 for (int i = 0; i < testcases.length; i++) { 163 DerOutputStream out = new DerOutputStream(sequence, testcases[i][0]); 164 assertTrue("Test case: " + i, Arrays.equals( 165 (byte[]) testcases[i][1], out.encoded)); 166 } 167 } 168 169 public void testVerify() throws IOException { 170 171 ASN1Sequence seqVerify = new ASN1Sequence(new ASN1Type[] { 172 ASN1Boolean.getInstance(), sequenceOf }) { 173 { 174 setDefault(Boolean.TRUE, 0); 175 setDefault(defaultList, 1); 176 } 177 178 protected Object getDecodedObject(BerInputStream in) 179 throws IOException { 180 throw new IOException( 181 "Method getDecodedObject MUST not be invoked"); 182 } 183 }; 184 185 for (int i = 0; i < testcases.length; i++) { 186 DerInputStream in = new DerInputStream((byte[]) testcases[i][1]); 187 in.setVerify(); 188 seqVerify.decode(in); 189 } 190 } 191 192 /** 193 * Tests encoding default fields 194 */ 195 public void testEncodeDefault() throws IOException { 196 197 // 198 // Boolean as default 199 // 200 ASN1Sequence s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean 201 .getInstance() }) { 202 { 203 setDefault(Boolean.TRUE, 0); 204 } 205 206 protected void getValues(Object object, Object[] values) { 207 values = (Object[]) object; 208 } 209 }; 210 211 byte[] expectedArray = new byte[] { 0x30, 0x00 }; 212 213 byte[] encoded = s.encode(new Object[] { Boolean.TRUE }); 214 assertTrue("Encoded boolean:", Arrays.equals(expectedArray, encoded)); 215 216 // 217 // Integer as default 218 // 219 s = new ASN1Sequence(new ASN1Type[] { ASN1Integer.getInstance() }) { 220 { 221 setDefault(new byte[] { 0x01 }, 0); 222 } 223 224 protected void getValues(Object object, Object[] values) { 225 values = (Object[]) object; 226 } 227 }; 228 229 encoded = s.encode(new Object[] { new byte[] { 0x01 } }); 230 assertTrue("Encoded integer:", Arrays.equals(expectedArray, encoded)); 231 } 232 233 /** 234 * Tests encoding optional fields 235 */ 236 public void testEncodeOptional() throws IOException { 237 238 // 239 // Test not optional 240 // 241 ASN1Sequence s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean 242 .getInstance() }) { 243 244 protected void getValues(Object object, Object[] values) { 245 values[0] = ((Object[]) object)[0]; 246 } 247 }; 248 249 try { 250 s.encode(new Object[] { null }); 251 fail("No expected RuntimeException"); 252 } catch (RuntimeException e) { 253 } 254 255 // 256 // Test optional 257 // 258 s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean.getInstance() }) { 259 { 260 setOptional(0); 261 } 262 263 protected void getValues(Object object, Object[] values) { 264 values[0] = ((Object[]) object)[0]; 265 } 266 }; 267 268 byte[] expectedArray = new byte[] { 0x30, 0x00 }; 269 270 byte[] encoded = s.encode(new Object[] { null }); 271 assertTrue("Encoded boolean:", Arrays.equals(expectedArray, encoded)); 272 } 273 } 274