1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  this work for additional information regarding copyright ownership.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  the License.  You may obtain a copy of the License at
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  See the License for the specific language governing permissions and
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  limitations under the License.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project* @author Vladimir N. Molotkov, Stepan M. Mishura
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project* @version $Revision$
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project*/
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.security.asn1;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.math.BigInteger;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Arrays;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Iterator;
28e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughesimport java.util.Map;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.security.internal.nls.Messages;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This abstract class represents ASN.1 Choice type.
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * To implement custom ASN.1 choice type an application class
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * must provide implementation for the following methods:
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     getIndex()
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     getObjectToEncode()
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * There are two ways to implement custom ASN.1 choice type:
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * with application class that represents ASN.1 custom choice type or without.
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The key point is how a value of choice type is stored by application classes.
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For example, let's consider the following ASN.1 notations
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (see http://www.ietf.org/rfc/rfc3280.txt)
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Time ::= CHOICE {
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *       utcTime        UTCTime,
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *       generalTime    GeneralizedTime
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * }
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Validity ::= SEQUENCE {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *       notBefore      Time,
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *       notAfter       Time
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  }
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 1)First approach:
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * No application class to represent ASN.1 Time notation
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The Time notation is a choice of different time formats: UTC and Generalized.
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Both of them are mapped to java.util.Date object, so an application
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class that represents ASN.1 Validity notation may keep values
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * as Date objects.
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * So a custom ASN.1 Time choice type should map its notation to Date object.
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class Time {
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     // custom ASN.1 choice class: maps Time to is notation
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] {
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) {
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         public int getIndex(java.lang.Object object) {
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             return 0; // always encode as ASN1GeneralizedTime
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         public Object getObjectToEncode(Object object) {
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // A value to be encoded value is a Date object
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // pass it to custom time class
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             return object;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     };
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * }
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class Validity {
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Date notBefore;    // choice as Date
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Date notAfter;     // choice as Date
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     ... // constructors and other methods go here
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     // custom ASN.1 sequence class: maps Validity class to is notation
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     public static final ASN1Sequence ASN1
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) {
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         protected Object getObject(Object[] values) {
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // ASN.1 Time choice passed Data object - use it
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             return new Validity((Date) values[0], (Date) values[1]);
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         protected void getValues(Object object, Object[] values) {
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             Validity validity = (Validity) object;
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // pass Date objects to ASN.1 Time choice
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             values[0] = validity.notBefore;
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             values[1] = validity.notAfter;
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     }
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * }
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 2)Second approach:
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * There is an application class to represent ASN.1 Time notation
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If it is a matter what time format should be used to decode/encode
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Date objects a class to represent ASN.1 Time notation must be created.
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For example,
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class Time {
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Date utcTime;
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Date gTime;
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     ... // constructors and other methods go here
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     // custom ASN.1 choice class: maps Time to is notation
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] {
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) {
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         public Object getDecodedObject(BerInputStream in) {
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // create Time object to pass as decoded value
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             Time time = new Time();
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             if (in.choiceIndex==0) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // we decoded GeneralizedTime
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // store decoded Date value in corresponding field
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 time.gTime = in.content;
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // return it
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return time;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             } else {
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // we decoded UTCTime
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // store decoded Date value in corresponding field
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 time.utcTime = in.content;
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // return it
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return time;
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             }
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         public int getIndex(java.lang.Object object) {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             Time time = (Time)object;
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             if(time.utcTime!=null){
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // encode Date as UTCTime
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return 1;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             } else {
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // otherwise encode Date as GeneralizedTime
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return 0;
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             }
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         public Object getObjectToEncode(Object object) {
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             Time time = (Time)object;
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             if(time.utcTime!=null){
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // encode Date as UTCTime
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return 1;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             } else {
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 // otherwise encode Date as GeneralizedTime
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *                 return 0;
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     };
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * }
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * So now Validity class must keep all values in Time object
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and its custom ASN.1 sequence class must handle this class of objects
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class Validity {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Time notBefore;    // now it is a Time!!!
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     private Time notAfter;     // now it is a Time!!!
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     ... // constructors and other methods go here
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     // custom ASN.1 sequence class: maps Validity class to is notation
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     public static final ASN1Sequence ASN1
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) {
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         protected Object getObject(Object[] values) {
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // We've gotten Time objects here !!!
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             return new Validity((Time) values[0], (Time) values[1]);
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         protected void getValues(Object object, Object[] values) {
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             Validity validity = (Validity) object;
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             // pass Time objects to ASN.1 Time choice
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             values[0] = validity.notBefore;
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *             values[1] = validity.notAfter;
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *         }
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     }
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * }
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic abstract class ASN1Choice extends ASN1Type {
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final ASN1Type[] type;
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // identifiers table: [2][number of distinct identifiers]
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // identifiers[0]: stores identifiers (includes nested choices)
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // identifiers[1]: stores identifiers' indexes in array of types
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int[][] identifiers;
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs ASN.1 choice type.
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param type -
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            an array of one or more ASN.1 type alternatives.
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IllegalArgumentException -
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             type parameter is invalid
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ASN1Choice(ASN1Type[] type) {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(TAG_CHOICE); // has not tag number
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (type.length == 0) {
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException(Messages.getString("security.10E", //$NON-NLS-1$
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    getClass().getName()));
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // create map of all identifiers
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap map = new TreeMap();
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int index = 0; index < type.length; index++) {
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ASN1Type t = type[index];
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (t instanceof ASN1Any) {
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // ASN.1 ANY is not allowed,
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // even it is a single component (not good for nested choices)
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        getClass().getName())); // FIXME name
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (t instanceof ASN1Choice) {
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // add all choice's identifiers
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int[][] choiceToAdd = ((ASN1Choice) t).identifiers;
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int j = 0; j < choiceToAdd[0].length; j++) {
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    addIdentifier(map, choiceToAdd[0][j], index);
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // add primitive identifier
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (t.checkTag(t.id)) {
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                addIdentifier(map, t.id, index);
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // add constructed identifier
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (t.checkTag(t.constrId)) {
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                addIdentifier(map, t.constrId, index);
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // fill identifiers array
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = map.size();
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        identifiers = new int[2][size];
273e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes        Iterator it = map.entrySet().iterator();
274e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < size; i++) {
276e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes        	Map.Entry entry = (Map.Entry) it.next();
277e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes            BigInteger identifier = (BigInteger) entry.getKey();
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            identifiers[0][i] = identifier.intValue();
280e7637fe9734c4e3bece51db6773505c04e49fabaElliott Hughes            identifiers[1][i] = ((BigInteger) entry.getValue()).intValue();
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.type = type;
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addIdentifier(TreeMap map, int identifier, int index){
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (map.put(BigInteger.valueOf(identifier), BigInteger.valueOf(index)) != null) {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    getClass().getName())); // FIXME name
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // DECODE
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Tests whether one of choice alternatives has the same identifier or not.
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param identifier -
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            ASN.1 identifier to be verified
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return - true if one of choice alternatives has the same identifier,
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *         otherwise false;
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final boolean checkTag(int identifier) {
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return Arrays.binarySearch(identifiers[0], identifier) >= 0;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Object decode(BerInputStream in) throws IOException {
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int index = Arrays.binarySearch(identifiers[0], in.tag);
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (index < 0) {
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new ASN1Exception(Messages.getString("security.110", //$NON-NLS-1$
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    getClass().getName()));// FIXME message
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        index = identifiers[1][index];
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        in.content = type[index].decode(in);
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // set index for getDecodedObject method
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        in.choiceIndex = index;
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (in.isVerify) {
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return null;
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return getDecodedObject(in);
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // ENCODE
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void encodeASN(BerOutputStream out) {
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        encodeContent(out);
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final void encodeContent(BerOutputStream out) {
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.encodeChoice(this);
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * TODO Put method description here
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param object - an object to be encoded
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public abstract int getIndex(Object object);
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public abstract Object getObjectToEncode(Object object);
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final void setEncodingContent(BerOutputStream out) {
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.getChoiceLength(this);
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
360