Home | History | Annotate | Download | only in ara
      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 
     63     public AccessRuleApplet(Channel channel) {
     64         mChannel = channel;
     65     }
     66 
     67     /** Reads all the access rules from the secure element */
     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 */
    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 
    157     private ResponseApdu send(CommandApdu cmdApdu) throws IOException {
    158         byte[] response = mChannel.transmit(cmdApdu.toBytes());
    159         return new ResponseApdu(response);
    160     }
    161 }
    162