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.io.IOException; 39 import java.util.ArrayList; 40 41 /** 42 * APDU-AR-DO: An APDU access rule data object defines an access rule for APDU access. The APDU 43 * access can either be restricted by a general rule based on an access is NEVER/ ALWAYS allowed 44 * policy or by a specific rule based on APDU filters which defines the range of allowed APDUs more 45 * precisely. 46 */ 47 public class APDU_AR_DO extends BerTlv { 48 49 public static final int TAG = 0xD0; 50 51 private boolean mApduAllowed = false; 52 private ArrayList<byte[]> mApduHeader = new ArrayList<byte[]>(); 53 private ArrayList<byte[]> mFilterMask = new ArrayList<byte[]>(); 54 APDU_AR_DO(byte[] rawData, int valueIndex, int valueLength)55 public APDU_AR_DO(byte[] rawData, int valueIndex, int valueLength) { 56 super(rawData, TAG, valueIndex, valueLength); 57 } 58 APDU_AR_DO(boolean allowed)59 public APDU_AR_DO(boolean allowed) { 60 super(null, TAG, 0, 0); 61 mApduAllowed = allowed; 62 } 63 APDU_AR_DO(ArrayList<byte[]> apduHeader, ArrayList<byte[]> filterMask)64 public APDU_AR_DO(ArrayList<byte[]> apduHeader, ArrayList<byte[]> filterMask) { 65 super(null, TAG, 0, 0); 66 mApduHeader = apduHeader; 67 mFilterMask = filterMask; 68 } 69 isApduAllowed()70 public boolean isApduAllowed() { 71 return mApduAllowed; 72 } 73 getApduHeaderList()74 public ArrayList<byte[]> getApduHeaderList() { 75 return mApduHeader; 76 } 77 getFilterMaskList()78 public ArrayList<byte[]> getFilterMaskList() { 79 return mFilterMask; 80 } 81 82 @Override 83 /** 84 * Tag: D0 Length: 1 or n*8 1 if value contains a general APDU access rule. n*8 if value 85 * contains 86 * a specific APDU access rule. 87 * 88 * <p>Value: Contains a general APDU access rule: NEVER (00): APDU access is not allowed 89 * ALWAYS(01): APDU access is allowed or contains a specific APDU access rule based on one or 90 * more 91 * APDU filter(s): APDU filter: 8 bytes APDU filter mask consists of: 4 bytes APDU header 92 * (defines 93 * the header of allowed APDUs) 4 bytes APDU mask (bit set defines the bits which shall be 94 * considered for the APDU header comparison) An APDU filter has to be applied as follows: 95 * if((APDUHeader & FilterMask) == FilterAPDUHeader) then allow APDU 96 */ interpret()97 public void interpret() throws ParserException { 98 99 mApduAllowed = false; 100 mApduHeader.clear(); 101 mFilterMask.clear(); 102 103 byte[] data = getRawData(); 104 int index = getValueIndex(); 105 106 if (index + getValueLength() > data.length) { 107 throw new ParserException("Not enough data for APDU_AR_DO!"); 108 } 109 110 // APDU-AR-DO contains either a flag which allows/disallows APDU communication 111 // or 112 // it contains APDU filter (APDUHeader | FilterMask) which should have length n*8. 113 if (getValueLength() == 1) { 114 if ((data[index] != 0x00) && (data[index] != 0x01)) { 115 // Undefined value cannot be treated as a general APDU access rule. 116 // Access to the SE shall not be allowed when the interpretation error occurs. 117 throw new ParserException("Invalid value of APDU-AR-DO : " + String.format("%02x", 118 data[index] & 0xff)); 119 } 120 mApduAllowed = (data[index] == 0x01); 121 } else if ((getValueLength() % 8 == 0) && (getValueLength() != 0)) { 122 mApduAllowed = true; 123 124 for (int i = index; i < index + getValueLength(); i += 8) { 125 byte[] apduHeader = new byte[4]; 126 byte[] filterMask = new byte[4]; 127 128 apduHeader[0] = data[i + 0]; 129 apduHeader[1] = data[i + 1]; 130 apduHeader[2] = data[i + 2]; 131 apduHeader[3] = data[i + 3]; 132 filterMask[0] = data[i + 4]; 133 filterMask[1] = data[i + 5]; 134 filterMask[2] = data[i + 6]; 135 filterMask[3] = data[i + 7]; 136 137 mApduHeader.add(apduHeader); 138 mFilterMask.add(filterMask); 139 } 140 } else if (getValueLength() == 0) { 141 mApduAllowed = false; 142 } else { 143 throw new ParserException("Invalid length of APDU-AR-DO!"); 144 } 145 } 146 147 @Override 148 /** 149 * Tag: D0 Length: 1 or n*8 1 if value contains a general APDU access rule. n*8 if value 150 * contains 151 * a specific APDU access rule. 152 * 153 * <p>Value: Contains a general APDU access rule: NEVER (00): APDU access is not allowed 154 * ALWAYS(01): APDU access is allowed or contains a specific APDU access rule based on one or 155 * more 156 * APDU filter(s): APDU filter: 8 bytes APDU filter mask consists of: 4 bytes APDU header 157 * (defines 158 * the header of allowed APDUs) 4 bytes APDU mask (bit set defines the bits which shall be 159 * considered for the APDU header comparison) An APDU filter has to be applied as follows: 160 * if((APDUHeader & FilterMask) == FilterAPDUHeader) then allow APDU 161 */ build(ByteArrayOutputStream stream)162 public void build(ByteArrayOutputStream stream) throws DO_Exception { 163 164 // APDU header and filter mask has to have the same size 165 // even if they are not used (then size() == 0 ). 166 if (mApduHeader.size() != this.mFilterMask.size()) { 167 throw new DO_Exception("APDU filter is invalid"); 168 } 169 170 // write tag 171 stream.write(getTag()); 172 173 // check if APDU Flag shall be written 174 if (mApduHeader.size() == 0) { 175 stream.write(0x01); 176 stream.write(this.mApduAllowed ? 0x01 : 0x00); 177 } else { 178 ByteArrayOutputStream temp = new ByteArrayOutputStream(); 179 for (int i = 0; i < mApduHeader.size(); i++) { 180 byte[] apduHeader = mApduHeader.get(i); 181 byte[] filterMask = mFilterMask.get(i); 182 183 if (apduHeader.length != 4 || filterMask.length != 4) { 184 throw new DO_Exception("APDU filter is invalid!"); 185 } 186 187 try { 188 temp.write(apduHeader); 189 temp.write(filterMask); 190 } catch (IOException e) { 191 throw new DO_Exception("APDU Filter Memory IO problem! " + e.getMessage()); 192 } 193 } 194 195 BerTlv.encodeLength(temp.size(), stream); 196 try { 197 stream.write(temp.toByteArray()); 198 } catch (IOException e) { 199 throw new DO_Exception("APDU Filter Memory IO problem! " + e.getMessage()); 200 } 201 } 202 } 203 } 204