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  * Copyright (c) 2015-2017, The Linux Foundation.
18  */
19 
20 /*
21  * Copyright (C) 2011 Deutsche Telekom, A.G.
22  *
23  * Licensed under the Apache License, Version 2.0 (the "License");
24  * you may not use this file except in compliance with the License.
25  * You may obtain a copy of the License at
26  *
27  *      http://www.apache.org/licenses/LICENSE-2.0
28  *
29  * Unless required by applicable law or agreed to in writing, software
30  * distributed under the License is distributed on an "AS IS" BASIS,
31  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32  * See the License for the specific language governing permissions and
33  * limitations under the License.
34  */
35 
36 package com.android.se.security.arf;
37 
38 import android.util.Log;
39 
40 import com.android.se.security.arf.pkcs15.PKCS15Exception;
41 
42 import java.util.Arrays;
43 
44 /** Base class for parsing PKCS#15 files */
45 public class DERParser {
46     public final String mTag = "SecureElement-DERParser";
47     // DER parameters
48     private byte[] mDERBuffer;
49     private short mDERSize, mDERIndex, mTLVDataSize = 0;
50 
DERParser(byte[] buffer)51     public DERParser(byte[] buffer) throws PKCS15Exception {
52         mDERBuffer = buffer;
53         mDERIndex = 0;
54         mDERSize = 0;
55         if (mDERBuffer == null) return;
56         mDERSize = (short) mDERBuffer.length;
57         mTLVDataSize = mDERSize;
58 
59         if (mDERSize == 0) return;
60         // Remove padding
61         if (mDERBuffer[mDERIndex] == ASN1.TAG_Padding) {
62             mTLVDataSize = 0;
63             while (++mDERIndex < mDERSize) {
64                 if (mDERBuffer[mDERIndex] != ASN1.TAG_Padding) {
65                     throw new PKCS15Exception("[Parser] Incorrect file format");
66                 }
67             }
68         }
69     }
70 
71     /**
72      * Returns "Base 128" encoded integer
73      *
74      * @return Converted integer
75      */
readIntBase128()76     private int readIntBase128() {
77         int value = 0;
78         // If the MSb is set to 0, it is the last byte
79         do {
80             value = (value << 7) + (mDERBuffer[mDERIndex] & 0x7F);
81         } while ((mDERBuffer[mDERIndex++] & 0x80) != 0);
82         return value;
83     }
84 
85     /**
86      * Returns size of the TLV encoded value
87      *
88      * @return Size of the TLV
89      */
getTLVSize()90     private short getTLVSize() throws PKCS15Exception {
91         int size, TLVSize = 0;
92 
93         if (isEndofBuffer()) throw new PKCS15Exception("[Parser] Cannot retreive size");
94         // Determine data size
95         if ((TLVSize = (mDERBuffer[mDERIndex++] & 0xff)) >= 128) {
96             size = TLVSize - 128;
97             for (TLVSize = 0; size > 0; size--) {
98                 if (!isEndofBuffer()) {
99                     TLVSize = (TLVSize << 8) + (mDERBuffer[mDERIndex++] & 0xff);
100                 } else {
101                     throw new PKCS15Exception("[Parser] Cannot retreive size");
102                 }
103             }
104         }
105 
106         // Check if the buffer contains enough data
107         if ((mDERIndex + TLVSize) > mDERSize) throw new PKCS15Exception("[Parser] Not enough data");
108         return (short) TLVSize;
109     }
110 
111     /**
112      * Returns type of the TLV encoded value
113      *
114      * @return Type of the TLV
115      */
getTLVType()116     private byte getTLVType() throws PKCS15Exception {
117         if (isEndofBuffer()) throw new PKCS15Exception("[Parser] Cannot retreive type");
118         return mDERBuffer[mDERIndex++];
119     }
120 
121     /**
122      * Determines if we reached the end of the buffer
123      *
124      * @return True if end of buffer is reached; False otherwise
125      */
isEndofBuffer()126     public boolean isEndofBuffer() throws PKCS15Exception {
127         if (mDERIndex == mDERSize) return true;
128         if (mDERBuffer[mDERIndex] == ASN1.TAG_Padding) {
129             // Remove padding
130             while (++mDERIndex < mDERSize) {
131                 if (mDERBuffer[mDERIndex] != ASN1.TAG_Padding) {
132                     throw new PKCS15Exception("[Parser] Incorrect file format");
133                 }
134             }
135             return true;
136         }
137         return false;
138     }
139 
140     /**
141      * Parses TLV from current index
142      *
143      * @return Type of TLV structure
144      */
parseTLV()145     public byte parseTLV() throws PKCS15Exception {
146         byte type = getTLVType();
147         mTLVDataSize = getTLVSize();
148         return type;
149     }
150 
151     /**
152      * Parses TLV from current index and check if type is correct
153      *
154      * @param type Type required
155      * @return Length of TLV data structure
156      */
parseTLV(byte type)157     public short parseTLV(byte type) throws PKCS15Exception {
158         byte typeInBuffer = getTLVType();
159         if (typeInBuffer == type) {
160             mTLVDataSize = getTLVSize();
161         } else {
162             Log.e(mTag, "parseTLV expected: " + type + " got:" + typeInBuffer);
163             Log.e(mTag, "parseTLV mDERIndex: " + mDERIndex + " mDERSize:" + mDERSize);
164             throw new PKCS15Exception("[Parser] Unexpected type");
165         }
166         return mTLVDataSize;
167     }
168 
169     /** Skips data of the current TLV structure */
skipTLVData()170     public void skipTLVData() {
171         mDERIndex += mTLVDataSize;
172     }
173 
174     /**
175      * Returns data of the current TLV structure
176      *
177      * @return Data of current TLV structure
178      */
getTLVData()179     public byte[] getTLVData() {
180         byte[] data = Arrays.copyOfRange(mDERBuffer, mDERIndex, mDERIndex + mTLVDataSize);
181         mDERIndex += mTLVDataSize;
182         return data;
183     }
184 
185     /**
186      * Takes snaptshot of the current context
187      *
188      * @return Saved context
189      */
saveContext()190     public short[] saveContext() {
191         short[] context = new short[2];
192         context[0] = mDERIndex;
193         context[1] = mTLVDataSize;
194         return context;
195     }
196 
197     /**
198      * Restores a context from a snapshot previously saved
199      *
200      * @param context Context snapshot
201      */
restoreContext(short[] context)202     public void restoreContext(short[] context) throws PKCS15Exception {
203         if ((context == null) || (context.length != 2)) {
204             throw new PKCS15Exception("[Parser] Invalid context");
205         }
206         if ((context[0] < 0) || (context[0] > mDERSize)) {
207             throw new PKCS15Exception("[Parser] Index out of bound");
208         }
209         mDERIndex = context[0];
210         mTLVDataSize = context[1];
211     }
212 
213     /**
214      * Parses standardized OID
215      *
216      * @return String containing OID
217      */
parseOID()218     public String parseOID() throws PKCS15Exception {
219         if (parseTLV(ASN1.TAG_OID) == 0) throw new PKCS15Exception("[Parser] OID Length is null");
220 
221         int end = mDERIndex + mTLVDataSize;
222         StringBuffer oid = new StringBuffer();
223 
224         // First subidentifier
225         int subid = readIntBase128();
226         // The first subidentifier contains the first two OID components
227         // X.Y is encoded as (X*40)+Y (0<=X<=2 and 0<=Y<=39 for X=0 or X=1)
228         if (subid <= 79) {
229             oid.append(subid / 40).append('.').append(subid % 40);
230         } else {
231             oid.append("2.").append(subid - 80);
232         }
233 
234         while (mDERIndex < end) oid.append('.').append(readIntBase128());
235         Log.i(mTag, "Found OID: " + oid.toString());
236         return oid.toString();
237     }
238 
239     /**
240      * Parses PKCS#15 path attribute
241      *
242      * @return Path retreived from the attribute
243      */
parsePathAttributes()244     public byte[] parsePathAttributes() throws PKCS15Exception {
245         parseTLV(ASN1.TAG_Sequence);
246         parseTLV(ASN1.TAG_OctetString);
247         return getTLVData();
248     }
249 }
250