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