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 2012 Giesecke & Devrient GmbH.
     22  *
     23  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
     24  * use this file except in compliance with the License. You may obtain a copy of
     25  * 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, WITHOUT
     31  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     32  * License for the specific language governing permissions and limitations under
     33  * the License.
     34  */
     35 
     36 package com.android.se.security.ara;
     37 
     38 import android.util.Log;
     39 
     40 import com.android.se.Channel;
     41 import com.android.se.Terminal;
     42 import com.android.se.security.AccessRuleCache;
     43 import com.android.se.security.ChannelAccess;
     44 import com.android.se.security.gpac.BerTlv;
     45 import com.android.se.security.gpac.ParserException;
     46 import com.android.se.security.gpac.REF_AR_DO;
     47 import com.android.se.security.gpac.Response_ALL_AR_DO;
     48 import com.android.se.security.gpac.Response_DO_Factory;
     49 
     50 import java.io.IOException;
     51 import java.security.AccessControlException;
     52 import java.util.ArrayList;
     53 import java.util.Iterator;
     54 import java.util.MissingResourceException;
     55 import java.util.NoSuchElementException;
     56 
     57 /** Reads and Maintains the ARA access for the Secure Element */
     58 public class AraController {
     59 
     60     public static final byte[] ARA_M_AID =
     61             new byte[]{
     62                     (byte) 0xA0,
     63                     (byte) 0x00,
     64                     (byte) 0x00,
     65                     (byte) 0x01,
     66                     (byte) 0x51,
     67                     (byte) 0x41,
     68                     (byte) 0x43,
     69                     (byte) 0x4C,
     70                     (byte) 0x00
     71             };
     72     private final String mTag = "SecureElement-AraController";
     73     private AccessRuleCache mAccessRuleCache = null;
     74     private Terminal mTerminal = null;
     75     private AccessRuleApplet mApplet = null;
     76 
     77     public AraController(AccessRuleCache cache, Terminal terminal) {
     78         mAccessRuleCache = cache;
     79         mTerminal = terminal;
     80     }
     81 
     82     public static byte[] getAraMAid() {
     83         return ARA_M_AID;
     84     }
     85 
     86     /**
     87      * Initialize the AraController, reads the refresh tag.
     88      * and fetch the access rules
     89      */
     90     public synchronized void initialize() throws IOException, NoSuchElementException {
     91         Channel channel = mTerminal.openLogicalChannelWithoutChannelAccess(getAraMAid());
     92         if (channel == null) {
     93             throw new MissingResourceException("could not open channel", "", "");
     94         }
     95 
     96         // set access conditions to access ARA-M.
     97         ChannelAccess araChannelAccess = new ChannelAccess();
     98         araChannelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, mTag);
     99         araChannelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED);
    100         channel.setChannelAccess(araChannelAccess);
    101 
    102         try {
    103             // set new applet handler since a new channel is used.
    104             mApplet = new AccessRuleApplet(channel);
    105             byte[] tag = mApplet.readRefreshTag();
    106             // if refresh tag is equal to the previous one it is not
    107             // neccessary to read all rules again.
    108             if (mAccessRuleCache.isRefreshTagEqual(tag)) {
    109                 Log.i(mTag, "Refresh tag unchanged. Using access rules from cache.");
    110                 return;
    111             }
    112             Log.i(mTag, "Refresh tag has changed.");
    113             // set new refresh tag and empty cache.
    114             mAccessRuleCache.setRefreshTag(tag);
    115             mAccessRuleCache.clearCache();
    116 
    117             Log.i(mTag, "Read ARs from ARA");
    118             readAllAccessRules();
    119         } catch (IOException e) {
    120             // Some kind of communication problem happened while transmit() was executed.
    121             // IOError shall be notified to the client application in this case.
    122             throw e;
    123         } catch (Exception e) {
    124             Log.i(mTag, "ARA error: " + e.getLocalizedMessage());
    125             throw new AccessControlException(e.getLocalizedMessage());
    126         } finally {
    127             if (channel != null) {
    128                 channel.close();
    129             }
    130         }
    131     }
    132 
    133     private void readAllAccessRules() throws AccessControlException, IOException {
    134         try {
    135             byte[] data = mApplet.readAllAccessRules();
    136             // no data returned, but no exception
    137             // -> no rule.
    138             if (data == null) {
    139                 return;
    140             }
    141 
    142             BerTlv tlv = Response_DO_Factory.createDO(data);
    143             if (tlv == null || !(tlv instanceof Response_ALL_AR_DO)) {
    144                 throw new AccessControlException("No valid data object found");
    145             }
    146             ArrayList<REF_AR_DO> array = ((Response_ALL_AR_DO) tlv).getRefArDos();
    147 
    148             if (array != null && array.size() != 0) {
    149                 Iterator<REF_AR_DO> iter = array.iterator();
    150                 while (iter.hasNext()) {
    151                     REF_AR_DO refArDo = iter.next();
    152                     mAccessRuleCache.putWithMerge(refArDo.getRefDo(), refArDo.getArDo());
    153                 }
    154             }
    155         } catch (ParserException e) {
    156             throw new AccessControlException("Parsing Data Object Exception: "
    157                     + e.getMessage());
    158         }
    159     }
    160 }
    161