blob: 0400e96d77f444e7eb87e01c96c02aa579849c36 [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.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());
}
}