Home | History | Annotate | Download | only in gpac
      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 
     55     public APDU_AR_DO(byte[] rawData, int valueIndex, int valueLength) {
     56         super(rawData, TAG, valueIndex, valueLength);
     57     }
     58 
     59     public APDU_AR_DO(boolean allowed) {
     60         super(null, TAG, 0, 0);
     61         mApduAllowed = allowed;
     62     }
     63 
     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 
     70     public boolean isApduAllowed() {
     71         return mApduAllowed;
     72     }
     73 
     74     public ArrayList<byte[]> getApduHeaderList() {
     75         return mApduHeader;
     76     }
     77 
     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      */
     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      */
    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