• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) 2017, The Linux Foundation.
18  */
19 
20 /*
21  * Copyright 2012 Giesecke & Devrient GmbH.
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 package com.android.se.security.gpac;
36 
37 import java.io.ByteArrayOutputStream;
38 import java.util.Arrays;
39 
40 /** Base Class for all Access Control Data Objects */
41 public class BerTlv {
42 
43     private byte[] mRawData = new byte[0];
44 
45     private int mTag = 0;
46 
47     private int mValueIndex = 0;
48     private int mValueLength = 0;
49 
BerTlv(byte[] rawData, int tag, int valueIndex, int valueLength)50     public BerTlv(byte[] rawData, int tag, int valueIndex, int valueLength) {
51         if (rawData != null) mRawData = rawData;
52         mTag = tag;
53         mValueIndex = valueIndex;
54         mValueLength = valueLength;
55     }
56 
57     /** Converts the byte into Hex */
toHex(byte[] digest)58     public static String toHex(byte[] digest) {
59         String digits = "0123456789abcdef";
60         StringBuilder sb = new StringBuilder(digest.length * 2);
61         for (byte b : digest) {
62             int bi = b & 0xff;
63             sb.append(digits.charAt(bi >> 4));
64             sb.append(digits.charAt(bi & 0xf));
65         }
66         return sb.toString();
67     }
68 
69     /** Decodes the byte array into BerTlv Object. Performs checks for length and tag */
decode(byte[] data, int startIndex)70     public static BerTlv decode(byte[] data, int startIndex) throws ParserException {
71         return BerTlv.decode(data, startIndex, true);
72     }
73 
74     /** Decodes the byte array into BerTlv Object. Performs checks for length and tag */
decode(byte[] data, int startIndex, boolean containsAllData)75     public static BerTlv decode(byte[] data, int startIndex, boolean containsAllData)
76             throws ParserException {
77 
78         if (data == null || data.length == 0) {
79             throw new ParserException("No data given!");
80         }
81 
82         int curIndex = startIndex;
83         int tag = 0;
84 
85     /* tag */
86         if (curIndex < data.length) {
87             int temp = data[curIndex++] & 0xff;
88             switch (temp) {
89                 case 0xff: // tag is in two byte format
90                 case 0xdf:
91                     if (curIndex < data.length) {
92                         tag = ((temp & 0xff) << 8) | (data[curIndex++] & 0xff);
93                     } else {
94                         throw new ParserException(
95                                 "Index " + curIndex + " out of range! [0..[" + data.length);
96                     }
97                     break;
98 
99                 default: // tag is in single-byte format
100                     tag = temp;
101                     break;
102             }
103         } else {
104             throw new ParserException("Index " + curIndex + " out of range! [0..[" + data.length);
105         }
106 
107     /* length */
108         int length;
109         if (curIndex < data.length) {
110             int temp = data[curIndex++] & 0xff;
111             if (temp < 0x80) {
112                 length = temp;
113             } else if (temp == 0x81) {
114                 if (curIndex < data.length) {
115                     length = data[curIndex++] & 0xff;
116                     if (length < 0x80) {
117                         throw new ParserException("Invalid TLV length encoding!");
118                     }
119                     if (containsAllData && data.length < length + curIndex) {
120                         throw new ParserException("Not enough data provided!");
121                     }
122                 } else {
123                     throw new ParserException(
124                             "Index " + curIndex + " out of range! [0..[" + data.length);
125                 }
126             } else if (temp == 0x82) {
127                 if ((curIndex + 1) < data.length) {
128                     length = ((data[curIndex] & 0xff) << 8) | (data[curIndex + 1] & 0xff);
129                 } else {
130                     throw new ParserException("Index out of range! [0..[" + data.length);
131                 }
132                 curIndex += 2;
133                 if (length < 0x100) {
134                     throw new ParserException("Invalid TLV length encoding!");
135                 }
136                 if (containsAllData && data.length < length + curIndex) {
137                     throw new ParserException("Not enough data provided!");
138                 }
139             } else if (temp == 0x83) {
140                 if ((curIndex + 2) < data.length) {
141                     length =
142                             ((data[curIndex] & 0xff) << 16)
143                                     | ((data[curIndex + 1] & 0xff) << 8)
144                                     | (data[curIndex + 2] & 0xff);
145                 } else {
146                     throw new ParserException("Index out of range! [0..[" + data.length);
147                 }
148                 curIndex += 3;
149                 if (length < 0x10000) {
150                     throw new ParserException("Invalid TLV length encoding!");
151                 }
152                 if (containsAllData && data.length < length + curIndex) {
153                     throw new ParserException("Not enough data provided!");
154                 }
155             } else {
156                 throw new ParserException("Unsupported TLV length encoding!");
157             }
158         } else {
159             throw new ParserException("Index " + curIndex + " out of range! [0..[" + data.length);
160         }
161         // create object
162         return new BerTlv(data, tag, curIndex, length);
163     }
164 
165     /**
166      * Encodes length according to ASN1. Supported are length values up to 3 bytes -> 83 xx yy zz.
167      */
encodeLength(int length, ByteArrayOutputStream stream)168     public static void encodeLength(int length, ByteArrayOutputStream stream) {
169 
170         if (length > 0x0000FFFF) {
171             stream.write(0x83);
172             stream.write(((length & 0x00FF0000) >> 16));
173             stream.write(((length & 0x0000FF00) >> 8));
174             stream.write((length & 0x000000FF));
175         } else if (length > 0x000000FF) {
176             stream.write(0x82);
177             stream.write(((length & 0x0000FF00) >> 8));
178             stream.write((length & 0x000000FF));
179         } else if (length > 0x0000007F) {
180             stream.write(0x81);
181             stream.write((length & 0x000000FF));
182         } else {
183             stream.write((length & 0x000000FF));
184         }
185     }
186 
187     /**
188      * Interprets the byte stream and performs the required checks.
189      * To to overridden in the derived class.
190      */
interpret()191     public void interpret() throws ParserException {
192     }
193 
194     /**
195      * Builds up the TLV into a byte stream.
196      *
197      * <p>Tags can be encoded as one or two bytes
198      */
build(ByteArrayOutputStream stream)199     public void build(ByteArrayOutputStream stream) throws DO_Exception {
200 
201         // put tag into stream
202         if (mTag > 0xFF) {
203             stream.write(((mTag & 0x0000FF00) >> 8));
204             stream.write((mTag & 0x000000FF));
205         } else {
206             stream.write((mTag & 0x000000FF));
207         }
208 
209         // write length
210         encodeLength(mValueLength, stream);
211 
212         // write value
213         if (mValueLength > 0) {
214             stream.write(mRawData, mValueIndex, mValueLength);
215         }
216     }
217 
getTag()218     public int getTag() {
219         return mTag;
220     }
221 
getValueIndex()222     public int getValueIndex() {
223         return mValueIndex;
224     }
225 
226     /** Returns the byte array of only the data values */
getValue()227     public byte[] getValue() {
228         // sanity checks
229         if (mRawData == null
230                 || mValueLength == 0
231                 || mValueIndex < 0
232                 || mValueIndex > mRawData.length
233                 || mValueIndex + mValueLength > mRawData.length) {
234             return new byte[0];
235         }
236 
237         byte[] data = new byte[mValueLength];
238 
239         System.arraycopy(mRawData, mValueIndex, data, 0, mValueLength);
240 
241         return data;
242     }
243 
getRawData()244     protected byte[] getRawData() {
245         return mRawData;
246     }
247 
getValueLength()248     public int getValueLength() {
249         return mValueLength;
250     }
251 
252     @Override
equals(Object obj)253     public boolean equals(Object obj) {
254         if (obj instanceof BerTlv) {
255             BerTlv berTlv = (BerTlv) obj;
256             if (mTag == berTlv.mTag) {
257                 byte[] test1 = this.getValue();
258                 byte[] test2 = berTlv.getValue();
259                 return Arrays.equals(test1, test2);
260             }
261         }
262         return false;
263     }
264 }
265