/* * 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. * *
Tags: 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. * *
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()); } }