| /* |
| * 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.util.Arrays; |
| |
| /** |
| * REF-DO: The REF-DO contains a reference to uniquely assign or identify an access rule for an SE |
| * application (with an AID reference) and for a device application (with a hash reference). |
| */ |
| public class REF_DO extends BerTlv { |
| |
| public static final int TAG = 0xE1; |
| |
| private AID_REF_DO mAidDo = null; |
| private Hash_REF_DO mHashDo = null; |
| private PKG_REF_DO mPkgDo = null; |
| |
| public REF_DO(byte[] rawData, int valueIndex, int valueLength) { |
| super(rawData, TAG, valueIndex, valueLength); |
| } |
| |
| public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo, PKG_REF_DO pkgRefDo) { |
| super(null, TAG, 0, 0); |
| mAidDo = aidRefDo; |
| mHashDo = hashRefDo; |
| mPkgDo = pkgRefDo; |
| } |
| |
| public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo) { |
| super(null, TAG, 0, 0); |
| mAidDo = aidRefDo; |
| mHashDo = hashRefDo; |
| mPkgDo = null; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder b = new StringBuilder(); |
| b.append("REF_DO: "); |
| if (mAidDo != null) { |
| b.append(mAidDo.toString()); |
| b.append(' '); |
| } |
| if (mHashDo != null) { |
| b.append(mHashDo.toString()); |
| b.append(' '); |
| } |
| if (mPkgDo != null) { |
| b.append(mPkgDo.toString()); |
| } |
| return b.toString(); |
| } |
| |
| public AID_REF_DO getAidDo() { |
| return mAidDo; |
| } |
| |
| public Hash_REF_DO getHashDo() { |
| return mHashDo; |
| } |
| |
| public PKG_REF_DO getPkgDo() { |
| return mPkgDo; |
| } |
| |
| /** |
| * Interpret data. |
| * |
| * <p>Tags: E1 -> Length: n |
| * |
| * <p>Value: |
| * 1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO. |
| * 2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a |
| * PKG-REF-DO. |
| * |
| * <p>Length: n bytes. |
| */ |
| @Override |
| public void interpret() throws ParserException { |
| |
| mAidDo = null; |
| mHashDo = null; |
| mPkgDo = null; |
| |
| byte[] data = getRawData(); |
| int index = getValueIndex(); |
| |
| if (index + getValueLength() > data.length) { |
| throw new ParserException("Not enough data for AR_DO!"); |
| } |
| |
| do { |
| BerTlv temp = BerTlv.decode(data, index); |
| |
| if (temp.getTag() == AID_REF_DO.TAG |
| || temp.getTag() == AID_REF_DO.TAG_DEFAULT_APPLICATION) { // AID-REF-DO |
| mAidDo = new AID_REF_DO(data, temp.getTag(), temp.getValueIndex(), |
| temp.getValueLength()); |
| mAidDo.interpret(); |
| } else if (temp.getTag() == Hash_REF_DO.TAG) { // Hash-REF-DO |
| mHashDo = new Hash_REF_DO(data, temp.getValueIndex(), temp.getValueLength()); |
| mHashDo.interpret(); |
| } else if (temp.getTag() == PKG_REF_DO.TAG) { // PKG-REF-DO |
| mPkgDo = new PKG_REF_DO(data, temp.getValueIndex(), temp.getValueLength()); |
| mPkgDo.interpret(); |
| } else { |
| // uncomment following line if a more restrictive |
| // behaviour is necessary. |
| // throw new ParserException("Invalid DO in REF-DO!"); |
| } |
| index = temp.getValueIndex() + temp.getValueLength(); |
| } while (getValueIndex() + getValueLength() > index); |
| |
| if (mAidDo != null && !mAidDo.isCarrierPrivilege() && mHashDo != null && mPkgDo != null) { |
| throw new ParserException("Unexpected combination of SEAC DOs and DAC DO"); |
| } |
| |
| // A rule without AID is a Carrier Privilege Rule. |
| // Enforces the AID to be the Carrier Privilege AID to avoid a null AID. |
| if (mAidDo == null && mHashDo != null) { |
| mAidDo = AID_REF_DO.createCarrierPrivilegeAid(); |
| } |
| |
| // check if there is a AID-REF-DO |
| if (mAidDo == null) { |
| throw new ParserException("Missing AID-REF-DO in REF-DO!"); |
| } |
| // check if there is a Hash-REF-DO |
| if (mHashDo == null) { |
| throw new ParserException("Missing Hash-REF-DO in REF-DO!"); |
| } |
| } |
| |
| /** |
| * Tag: E1 Length: n Value: |
| * 1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO. |
| * 2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a |
| * PKG-REF-DO. |
| */ |
| @Override |
| public void build(ByteArrayOutputStream stream) throws DO_Exception { |
| ByteArrayOutputStream temp = new ByteArrayOutputStream(); |
| |
| if (mHashDo == null) { |
| throw new DO_Exception("REF-DO: Required DO missing!"); |
| } |
| |
| if (mAidDo != null) { |
| mAidDo.build(temp); |
| } |
| |
| if (mHashDo != null) { |
| mHashDo.build(temp); |
| } |
| |
| if (mPkgDo != null) { |
| mPkgDo.build(temp); |
| } |
| |
| byte[] data = temp.toByteArray(); |
| BerTlv tlv = new BerTlv(data, getTag(), 0, data.length); |
| tlv.build(stream); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof REF_DO) { |
| REF_DO ref_do = (REF_DO) obj; |
| if (getTag() == ref_do.getTag()) { |
| if (AID_REF_DO.equals(mAidDo, ref_do.mAidDo)) { |
| if (Hash_REF_DO.equals(mHashDo, ref_do.mHashDo)) { |
| if (PKG_REF_DO.equals(mPkgDo, ref_do.mPkgDo)) { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
| try { |
| this.build(stream); |
| } catch (DO_Exception e) { |
| return 1; |
| } |
| byte[] data = stream.toByteArray(); |
| int hash = Arrays.hashCode(data); |
| // int hash = data.hashCode(); |
| return hash; |
| } |
| |
| public boolean isCarrierPrivilegeRefDo() { |
| return (mAidDo != null && mAidDo.isCarrierPrivilege()); |
| } |
| } |