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 Vladimir N. Molotkov 20 */ 21 22package org.apache.harmony.security.tests.x509; 23 24import java.io.ByteArrayInputStream; 25import java.io.InputStream; 26 27import junit.framework.TestCase; 28 29/** 30 * Test for thread safety of the PolicyQualifierInfo DER decoder 31 * ("DER" stands for "Distinguished Encoding Rules", 32 * see ITU-T Recommendation X.690, 33 * http://asn1.elibel.tm.fr) 34 */ 35public class PolicyQualifierInfoTest extends TestCase { 36 // Number of test working threads (may be set externally) 37 private static int workersNumber; 38 // Number of test iterations performed by each thread 39 // (may be set externally) 40 private static int iterationsNumber; 41 42 static { 43 try { 44 workersNumber = Integer.parseInt( 45 System.getProperty("PolicyQualifierInfoTest.workersNumber", 46 "10")); 47 iterationsNumber = Integer.parseInt( 48 System.getProperty("PolicyQualifierInfoTest.iterationsNumber", 49 "10000")); 50 } catch (Exception e) { 51 workersNumber = 10; 52 iterationsNumber = 10000; 53 } 54 } 55 56 // Holder for thread-specific PolicyQualifier DER encodings 57 private static final byte[][] enc = new byte[workersNumber][]; 58 59 private volatile boolean arrayPassed = true; 60 private volatile boolean inpstPassed = true; 61 62 // "Valid" reference DER encoding 63 // (generated by own encoder during test development) 64 private static final byte[] encoding = { 65 (byte) 0x30, (byte) 0x26, // tag Seq, length 66 (byte) 0x06, (byte) 0x08, // tag OID, length 67 (byte) 0x2b, (byte) 0x06, (byte) 0x01, (byte) 0x05, // oid value 68 (byte) 0x05, (byte) 0x07, (byte) 0x02, (byte) 0x01, // oid value 69 (byte) 0x16, (byte) 0x1a, // tag IA5String, length 70 (byte) 0x68, (byte) 0x74, (byte) 0x74, (byte) 0x70, // IA5String value 71 (byte) 0x3a, (byte) 0x2f, (byte) 0x2f, (byte) 0x77, // IA5String value 72 (byte) 0x77, (byte) 0x77, (byte) 0x2e, (byte) 0x71, // IA5String value 73 (byte) 0x71, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, // IA5String value 74 (byte) 0x6d, (byte) 0x2f, (byte) 0x73, (byte) 0x74, // IA5String value 75 (byte) 0x6d, (byte) 0x74, (byte) 0x2e, (byte) 0x74, // IA5String value 76 (byte) 0x78, (byte) 0x74 // IA5String value 77 }; 78 79 80 // Test worker for decoding from byte array 81 private class TestWorker1 extends Thread { 82 83 private final int myIntValue; 84 85 public TestWorker1(int num) { 86 super("Worker_" + num); 87 myIntValue = num; 88 } 89 90 public void run() { 91 for (int i = 0; i < iterationsNumber; i++) { 92 try { 93 // Perform DER decoding: 94 Object[] decoded = 95 (Object[]) org.apache.harmony.security.x509. 96 PolicyQualifierInfo.ASN1.decode( 97 getDerEncoding(myIntValue)); 98 // check OID value 99 assertEquals(this.getName() + "(OID)", 100 myIntValue, ((int[]) decoded[0])[8]); 101 // check qualifier 102 assertEquals(this.getName() + "(QA)", 103 (byte) myIntValue, ((byte[]) decoded[1])[2]); 104 } catch (Throwable e) { 105 System.err.println(e); 106 arrayPassed = false; 107 return; 108 } 109 } 110 } 111 } 112 113 // Test worker for decoding from InputStream 114 private class TestWorker2 extends Thread { 115 116 private final int myIntValue; 117 118 public TestWorker2(int num) { 119 super("Worker_" + num); 120 myIntValue = num; 121 } 122 123 public void run() { 124 for (int i = 0; i < iterationsNumber; i++) { 125 try { 126 // Perform DER decoding: 127 Object[] decoded = 128 (Object[]) org.apache.harmony.security.x509. 129 PolicyQualifierInfo.ASN1.decode( 130 getDerInputStream(myIntValue)); 131 // check OID value 132 assertEquals(this.getName() + "(OID)", 133 myIntValue, ((int[]) decoded[0])[8]); 134 // check qualifier 135 assertEquals(this.getName() + "(QA)", 136 (byte) myIntValue, ((byte[]) decoded[1])[2]); 137 } catch (Throwable e) { 138 System.err.println(e); 139 inpstPassed = false; 140 return; 141 } 142 } 143 } 144 } 145 146 /** 147 * Test 1 148 * 149 * @throws InterruptedException 150 */ 151 public final void testMtByteArray() throws InterruptedException { 152 Thread[] workers = new Thread[workersNumber]; 153 for (int i = 0; i < workersNumber; i++) { 154 workers[i] = new TestWorker1(i); 155 } 156 for (int i = 0; i < workersNumber; i++) { 157 workers[i].start(); 158 } 159 for (int i = 0; i < workersNumber; i++) { 160 workers[i].join(); 161 } 162 assertTrue(arrayPassed); 163 } 164 165 /** 166 * Test 2 167 * 168 * @throws InterruptedException 169 */ 170 public final void testMtInputStream() throws InterruptedException { 171 Thread[] workers = new Thread[workersNumber]; 172 for (int i = 0; i < workersNumber; i++) { 173 workers[i] = new TestWorker2(i); 174 } 175 for (int i = 0; i < workersNumber; i++) { 176 workers[i].start(); 177 } 178 for (int i = 0; i < workersNumber; i++) { 179 workers[i].join(); 180 } 181 assertTrue(inpstPassed); 182 } 183 184 // 185 // Generates unique (based on parameter) DER encoding 186 // @param intVal value to be incorporated into the resulting encoding 187 // @return PolicyQualifier DER encoding 188 // 189 private static final byte[] getDerEncoding(int intVal) { 190 setEncArray(intVal); 191 return enc[intVal]; 192 } 193 194 // 195 // Generates unique (based on parameter) DER encoding 196 // @param intVal value to be incorporated into the resulting encoding 197 // @return PolicyQualifier DER encoding 198 // 199 private static final InputStream getDerInputStream(int intVal) { 200 setEncArray(intVal); 201 return new ByteArrayInputStream(enc[intVal]); 202 } 203 204 // 205 // Init thread specific data 206 // @param intVal worker thread number 207 // 208 private static void setEncArray(int intVal) { 209 if (enc[intVal] == null) { 210 // make encoding thread-specific 211 byte[] a = encoding.clone(); 212 a[11] = (byte) intVal; 213 a[14] = (byte) intVal; 214 enc[intVal] = a; 215 } 216 } 217} 218