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 2010 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 36 package com.android.se.security.ara; 37 38 import com.android.se.Channel; 39 import com.android.se.security.CommandApdu; 40 import com.android.se.security.ResponseApdu; 41 import com.android.se.security.gpac.BerTlv; 42 import com.android.se.security.gpac.ParserException; 43 import com.android.se.security.gpac.Response_DO_Factory; 44 import com.android.se.security.gpac.Response_RefreshTag_DO; 45 46 import java.io.ByteArrayOutputStream; 47 import java.io.IOException; 48 import java.security.AccessControlException; 49 50 /** Reads the ARA Rules from the Secure Element */ 51 public class AccessRuleApplet { 52 private static final int MAX_LEN = 0x00; 53 private static final CommandApdu GET_ALL_CMD = new CommandApdu(0x80, 0xCA, 0xFF, 0x40, MAX_LEN); 54 // MAX_LEN should be adapted by OEM, this is a defensive value since some devices/modems have 55 // problems with Le=0x00 or 0xFF. 56 private static final CommandApdu GET_NEXT_CMD = new CommandApdu(0x80, 0xCA, 0xFF, 0x60, 57 MAX_LEN); 58 private static final CommandApdu GET_REFRESH_TAG = new CommandApdu(0x80, 0xCA, 0xDF, 0x20, 59 MAX_LEN); 60 private final String mTag = "SecureElement-AccessRuleApplet"; 61 private Channel mChannel = null; 62 AccessRuleApplet(Channel channel)63 public AccessRuleApplet(Channel channel) { 64 mChannel = channel; 65 } 66 67 /** Reads all the access rules from the secure element */ readAllAccessRules()68 public byte[] readAllAccessRules() throws AccessControlException, IOException { 69 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 70 int overallLen = 0; 71 72 // send GET DATA (specific) 73 CommandApdu apdu = (CommandApdu) GET_ALL_CMD.clone(); 74 ResponseApdu response = send(apdu); 75 76 // OK 77 if (response.isStatus(0x9000)) { 78 // check if more data has to be fetched 79 BerTlv tempTlv = null; 80 try { 81 tempTlv = BerTlv.decode(response.getData(), 0, false); 82 } catch (ParserException e) { 83 throw new AccessControlException( 84 "GET DATA (all) not successfull. Tlv encoding wrong."); 85 } 86 87 // the first data block contain the length of the TLV + Tag bytes + length bytes. 88 overallLen = tempTlv.getValueLength() + tempTlv.getValueIndex(); 89 90 try { 91 stream.write(response.getData()); 92 } catch (IOException e) { 93 throw new AccessControlException("GET DATA (all) IO problem. " + e.getMessage()); 94 } 95 96 int le; 97 // send subsequent GET DATA (next) commands 98 while (stream.size() < overallLen) { 99 le = overallLen - stream.size(); 100 101 if (le > MAX_LEN) { 102 le = MAX_LEN; 103 } 104 // send GET DATA (next) 105 apdu = (CommandApdu) GET_NEXT_CMD.clone(); 106 apdu.setLe(le); 107 108 response = send(apdu); 109 // OK 110 if (response.isStatus(0x9000)) { 111 try { 112 stream.write(response.getData()); 113 } catch (IOException e) { 114 throw new AccessControlException("GET DATA (next) IO problem. " 115 + e.getMessage()); 116 } 117 } else { 118 throw new AccessControlException("GET DATA (next) not successfull, SW1SW2=" 119 + response.getSW1SW2()); 120 } 121 } 122 return stream.toByteArray(); 123 // referenced data not found 124 } else if (response.isStatus(0x6A88)) { 125 return null; 126 } else { 127 throw new AccessControlException("GET DATA (all) not successfull. SW1SW2=" 128 + response.getSW1SW2()); 129 } 130 } 131 132 /** Fetches the Refresh Tag from the Secure Element */ readRefreshTag()133 public byte[] readRefreshTag() throws AccessControlException, IOException { 134 CommandApdu apdu = (CommandApdu) GET_REFRESH_TAG.clone(); 135 ResponseApdu response = send(apdu); 136 // OK 137 if (response.isStatus(0x9000)) { 138 // check if more data has to be fetched 139 BerTlv tempTlv = null; 140 Response_RefreshTag_DO refreshDo; 141 try { 142 tempTlv = Response_DO_Factory.createDO(response.getData()); 143 if (tempTlv instanceof Response_RefreshTag_DO) { 144 refreshDo = (Response_RefreshTag_DO) tempTlv; 145 return refreshDo.getRefreshTagArray(); 146 } else { 147 throw new AccessControlException("GET REFRESH TAG returned invalid Tlv."); 148 } 149 } catch (ParserException e) { 150 throw new AccessControlException( 151 "GET REFRESH TAG not successfull. Tlv encoding wrong."); 152 } 153 } 154 throw new AccessControlException("GET REFRESH TAG not successfull."); 155 } 156 send(CommandApdu cmdApdu)157 private ResponseApdu send(CommandApdu cmdApdu) throws IOException { 158 byte[] response = mChannel.transmit(cmdApdu.toBytes()); 159 return new ResponseApdu(response); 160 } 161 } 162