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 // quick 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