| /* |
| * 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 org.simalliance.openmobileapi.service.security.gpac.dataobjects; |
| |
| 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 final static 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. |
| |
| * 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 ){ |
| mApduAllowed = (data[index] == 0x01); |
| } else if(getValueLength() % 8 == 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 { |
| 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. |
| |
| * 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()); |
| } |
| } |
| } |
| } |