blob: 8c9d65b9aa53c76fa844f7f1f9b120e935529e50 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (c) 2017, The Linux Foundation.
*/
/*
* Copyright 2012 Giesecke & Devrient GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.se.security.gpac;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* APDU-AR-DO: An APDU access rule data object defines an access rule for APDU access. The APDU
* access can either be restricted by a general rule based on an access is NEVER/ ALWAYS allowed
* policy or by a specific rule based on APDU filters which defines the range of allowed APDUs more
* precisely.
*/
public class APDU_AR_DO extends BerTlv {
public static final int TAG = 0xD0;
private boolean mApduAllowed = false;
private ArrayList<byte[]> mApduHeader = new ArrayList<byte[]>();
private ArrayList<byte[]> mFilterMask = new ArrayList<byte[]>();
public APDU_AR_DO(byte[] rawData, int valueIndex, int valueLength) {
super(rawData, TAG, valueIndex, valueLength);
}
public APDU_AR_DO(boolean allowed) {
super(null, TAG, 0, 0);
mApduAllowed = allowed;
}
public APDU_AR_DO(ArrayList<byte[]> apduHeader, ArrayList<byte[]> filterMask) {
super(null, TAG, 0, 0);
mApduHeader = apduHeader;
mFilterMask = filterMask;
}
public boolean isApduAllowed() {
return mApduAllowed;
}
public ArrayList<byte[]> getApduHeaderList() {
return mApduHeader;
}
public ArrayList<byte[]> getFilterMaskList() {
return mFilterMask;
}
@Override
/**
* Tag: D0 Length: 1 or n*8 1 if value contains a general APDU access rule. n*8 if value
* contains
* a specific APDU access rule.
*
* <p>Value: Contains a general APDU access rule: NEVER (00): APDU access is not allowed
* ALWAYS(01): APDU access is allowed or contains a specific APDU access rule based on one or
* more
* APDU filter(s): APDU filter: 8 bytes APDU filter mask consists of: 4 bytes APDU header
* (defines
* the header of allowed APDUs) 4 bytes APDU mask (bit set defines the bits which shall be
* considered for the APDU header comparison) An APDU filter has to be applied as follows:
* if((APDUHeader & FilterMask) == FilterAPDUHeader) then allow APDU
*/
public void interpret() throws ParserException {
mApduAllowed = false;
mApduHeader.clear();
mFilterMask.clear();
byte[] data = getRawData();
int index = getValueIndex();
if (index + getValueLength() > data.length) {
throw new ParserException("Not enough data for APDU_AR_DO!");
}
// APDU-AR-DO contains either a flag which allows/disallows APDU communication
// or
// it contains APDU filter (APDUHeader | FilterMask) which should have length n*8.
if (getValueLength() == 1) {
if ((data[index] != 0x00) && (data[index] != 0x01)) {
// Undefined value cannot be treated as a general APDU access rule.
// Access to the SE shall not be allowed when the interpretation error occurs.
throw new ParserException("Invalid value of APDU-AR-DO : " + String.format("%02x",
data[index] & 0xff));
}
mApduAllowed = (data[index] == 0x01);
} else if ((getValueLength() % 8 == 0) && (getValueLength() != 0)) {
mApduAllowed = true;
for (int i = index; i < index + getValueLength(); i += 8) {
byte[] apduHeader = new byte[4];
byte[] filterMask = new byte[4];
apduHeader[0] = data[i + 0];
apduHeader[1] = data[i + 1];
apduHeader[2] = data[i + 2];
apduHeader[3] = data[i + 3];
filterMask[0] = data[i + 4];
filterMask[1] = data[i + 5];
filterMask[2] = data[i + 6];
filterMask[3] = data[i + 7];
mApduHeader.add(apduHeader);
mFilterMask.add(filterMask);
}
} else if (getValueLength() == 0) {
mApduAllowed = false;
} else {
throw new ParserException("Invalid length of APDU-AR-DO!");
}
}
@Override
/**
* Tag: D0 Length: 1 or n*8 1 if value contains a general APDU access rule. n*8 if value
* contains
* a specific APDU access rule.
*
* <p>Value: Contains a general APDU access rule: NEVER (00): APDU access is not allowed
* ALWAYS(01): APDU access is allowed or contains a specific APDU access rule based on one or
* more
* APDU filter(s): APDU filter: 8 bytes APDU filter mask consists of: 4 bytes APDU header
* (defines
* the header of allowed APDUs) 4 bytes APDU mask (bit set defines the bits which shall be
* considered for the APDU header comparison) An APDU filter has to be applied as follows:
* if((APDUHeader & FilterMask) == FilterAPDUHeader) then allow APDU
*/
public void build(ByteArrayOutputStream stream) throws DO_Exception {
// APDU header and filter mask has to have the same size
// even if they are not used (then size() == 0 ).
if (mApduHeader.size() != this.mFilterMask.size()) {
throw new DO_Exception("APDU filter is invalid");
}
// write tag
stream.write(getTag());
// check if APDU Flag shall be written
if (mApduHeader.size() == 0) {
stream.write(0x01);
stream.write(this.mApduAllowed ? 0x01 : 0x00);
} else {
ByteArrayOutputStream temp = new ByteArrayOutputStream();
for (int i = 0; i < mApduHeader.size(); i++) {
byte[] apduHeader = mApduHeader.get(i);
byte[] filterMask = mFilterMask.get(i);
if (apduHeader.length != 4 || filterMask.length != 4) {
throw new DO_Exception("APDU filter is invalid!");
}
try {
temp.write(apduHeader);
temp.write(filterMask);
} catch (IOException e) {
throw new DO_Exception("APDU Filter Memory IO problem! " + e.getMessage());
}
}
BerTlv.encodeLength(temp.size(), stream);
try {
stream.write(temp.toByteArray());
} catch (IOException e) {
throw new DO_Exception("APDU Filter Memory IO problem! " + e.getMessage());
}
}
}
}