1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.apksig.internal.asn1.ber;
18 
19 import com.android.apksig.internal.asn1.Asn1Type;
20 import com.android.apksig.internal.asn1.Asn1TagClass;
21 
22 /**
23  * ASN.1 Basic Encoding Rules (BER) constants and helper methods. See {@code X.690}.
24  */
25 public abstract class BerEncoding {
BerEncoding()26     private BerEncoding() {}
27 
28     /**
29      * Constructed vs primitive flag in the first identifier byte.
30      */
31     public static final int ID_FLAG_CONSTRUCTED_ENCODING = 1 << 5;
32 
33     /**
34      * Tag class: UNIVERSAL
35      */
36     public static final int TAG_CLASS_UNIVERSAL = 0;
37 
38     /**
39      * Tag class: APPLICATION
40      */
41     public static final int TAG_CLASS_APPLICATION = 1;
42 
43     /**
44      * Tag class: CONTEXT SPECIFIC
45      */
46     public static final int TAG_CLASS_CONTEXT_SPECIFIC = 2;
47 
48     /**
49      * Tag class: PRIVATE
50      */
51     public static final int TAG_CLASS_PRIVATE = 3;
52 
53     /**
54      * Tag number: BOOLEAN
55      */
56     public static final int TAG_NUMBER_BOOLEAN = 0x1;
57 
58     /**
59      * Tag number: INTEGER
60      */
61     public static final int TAG_NUMBER_INTEGER = 0x2;
62 
63     /**
64      * Tag number: BIT STRING
65      */
66     public static final int TAG_NUMBER_BIT_STRING = 0x3;
67 
68     /**
69      * Tag number: OCTET STRING
70      */
71     public static final int TAG_NUMBER_OCTET_STRING = 0x4;
72 
73     /**
74      * Tag number: NULL
75      */
76     public static final int TAG_NUMBER_NULL = 0x05;
77 
78     /**
79      * Tag number: OBJECT IDENTIFIER
80      */
81     public static final int TAG_NUMBER_OBJECT_IDENTIFIER = 0x6;
82 
83     /**
84      * Tag number: SEQUENCE
85      */
86     public static final int TAG_NUMBER_SEQUENCE = 0x10;
87 
88     /**
89      * Tag number: SET
90      */
91     public static final int TAG_NUMBER_SET = 0x11;
92 
93     /**
94      * Tag number: UTC_TIME
95      */
96     public final static int TAG_NUMBER_UTC_TIME = 0x17;
97 
98     /**
99      * Tag number: GENERALIZED_TIME
100      */
101     public final static int TAG_NUMBER_GENERALIZED_TIME = 0x18;
102 
getTagNumber(Asn1Type dataType)103     public static int getTagNumber(Asn1Type dataType) {
104         switch (dataType) {
105             case INTEGER:
106                 return TAG_NUMBER_INTEGER;
107             case OBJECT_IDENTIFIER:
108                 return TAG_NUMBER_OBJECT_IDENTIFIER;
109             case OCTET_STRING:
110                 return TAG_NUMBER_OCTET_STRING;
111             case BIT_STRING:
112                 return TAG_NUMBER_BIT_STRING;
113             case SET_OF:
114                 return TAG_NUMBER_SET;
115             case SEQUENCE:
116             case SEQUENCE_OF:
117                 return TAG_NUMBER_SEQUENCE;
118             case UTC_TIME:
119                 return TAG_NUMBER_UTC_TIME;
120             case GENERALIZED_TIME:
121                 return TAG_NUMBER_GENERALIZED_TIME;
122             case BOOLEAN:
123                 return TAG_NUMBER_BOOLEAN;
124             default:
125                 throw new IllegalArgumentException("Unsupported data type: " + dataType);
126         }
127     }
128 
getTagClass(Asn1TagClass tagClass)129     public static int getTagClass(Asn1TagClass tagClass) {
130         switch (tagClass) {
131             case APPLICATION:
132                 return TAG_CLASS_APPLICATION;
133             case CONTEXT_SPECIFIC:
134                 return TAG_CLASS_CONTEXT_SPECIFIC;
135             case PRIVATE:
136                 return TAG_CLASS_PRIVATE;
137             case UNIVERSAL:
138                 return TAG_CLASS_UNIVERSAL;
139             default:
140                 throw new IllegalArgumentException("Unsupported tag class: " + tagClass);
141         }
142     }
143 
tagClassToString(int typeClass)144     public static String tagClassToString(int typeClass) {
145         switch (typeClass) {
146             case TAG_CLASS_APPLICATION:
147                 return "APPLICATION";
148             case TAG_CLASS_CONTEXT_SPECIFIC:
149                 return "";
150             case TAG_CLASS_PRIVATE:
151                 return "PRIVATE";
152             case TAG_CLASS_UNIVERSAL:
153                 return "UNIVERSAL";
154             default:
155                 throw new IllegalArgumentException("Unsupported type class: " + typeClass);
156         }
157     }
158 
tagClassAndNumberToString(int tagClass, int tagNumber)159     public static String tagClassAndNumberToString(int tagClass, int tagNumber) {
160         String classString = tagClassToString(tagClass);
161         String numberString = tagNumberToString(tagNumber);
162         return classString.isEmpty() ? numberString : classString + " " + numberString;
163     }
164 
165 
tagNumberToString(int tagNumber)166     public static String tagNumberToString(int tagNumber) {
167         switch (tagNumber) {
168             case TAG_NUMBER_INTEGER:
169                 return "INTEGER";
170             case TAG_NUMBER_OCTET_STRING:
171                 return "OCTET STRING";
172             case TAG_NUMBER_BIT_STRING:
173                 return "BIT STRING";
174             case TAG_NUMBER_NULL:
175                 return "NULL";
176             case TAG_NUMBER_OBJECT_IDENTIFIER:
177                 return "OBJECT IDENTIFIER";
178             case TAG_NUMBER_SEQUENCE:
179                 return "SEQUENCE";
180             case TAG_NUMBER_SET:
181                 return "SET";
182             case TAG_NUMBER_BOOLEAN:
183                 return "BOOLEAN";
184             case TAG_NUMBER_GENERALIZED_TIME:
185                 return "GENERALIZED TIME";
186             case TAG_NUMBER_UTC_TIME:
187                 return "UTC TIME";
188             default:
189                 return "0x" + Integer.toHexString(tagNumber);
190         }
191     }
192 
193     /**
194      * Returns {@code true} if the provided first identifier byte indicates that the data value uses
195      * constructed encoding for its contents, or {@code false} if the data value uses primitive
196      * encoding for its contents.
197      */
isConstructed(byte firstIdentifierByte)198     public static boolean isConstructed(byte firstIdentifierByte) {
199         return (firstIdentifierByte & ID_FLAG_CONSTRUCTED_ENCODING) != 0;
200     }
201 
202     /**
203      * Returns the tag class encoded in the provided first identifier byte. See {@code TAG_CLASS}
204      * constants.
205      */
getTagClass(byte firstIdentifierByte)206     public static int getTagClass(byte firstIdentifierByte) {
207         return (firstIdentifierByte & 0xff) >> 6;
208     }
209 
setTagClass(byte firstIdentifierByte, int tagClass)210     public static byte setTagClass(byte firstIdentifierByte, int tagClass) {
211         return (byte) ((firstIdentifierByte & 0x3f) | (tagClass << 6));
212     }
213 
214     /**
215      * Returns the tag number encoded in the provided first identifier byte. See {@code TAG_NUMBER}
216      * constants.
217      */
getTagNumber(byte firstIdentifierByte)218     public static int getTagNumber(byte firstIdentifierByte) {
219         return firstIdentifierByte & 0x1f;
220     }
221 
setTagNumber(byte firstIdentifierByte, int tagNumber)222     public static byte setTagNumber(byte firstIdentifierByte, int tagNumber) {
223         return (byte) ((firstIdentifierByte & ~0x1f) | tagNumber);
224     }
225 }
226