1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * Copyright (c) 2017, The Linux Foundation.
18  */
19 
20 /*
21  * Copyright 2012 Giesecke & Devrient GmbH.
22  *
23  * Licensed under the Apache License, Version 2.0 (the "License");
24  * you may not use this file except in compliance with the License.
25  * You may obtain a copy of the License at
26  *
27  *      http://www.apache.org/licenses/LICENSE-2.0
28  *
29  * Unless required by applicable law or agreed to in writing, software
30  * distributed under the License is distributed on an "AS IS" BASIS,
31  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32  * See the License for the specific language governing permissions and
33  * limitations under the License.
34  */
35 package com.android.se.security.gpac;
36 
37 import java.io.ByteArrayOutputStream;
38 import java.util.Arrays;
39 
40 /**
41  * REF-DO: The REF-DO contains a reference to uniquely assign or identify an access rule for an SE
42  * application (with an AID reference) and for a device application (with a hash reference).
43  */
44 public class REF_DO extends BerTlv {
45 
46     public static final int TAG = 0xE1;
47 
48     private AID_REF_DO mAidDo = null;
49     private Hash_REF_DO mHashDo = null;
50     private PKG_REF_DO mPkgDo = null;
51 
REF_DO(byte[] rawData, int valueIndex, int valueLength)52     public REF_DO(byte[] rawData, int valueIndex, int valueLength) {
53         super(rawData, TAG, valueIndex, valueLength);
54     }
55 
REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo, PKG_REF_DO pkgRefDo)56     public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo, PKG_REF_DO pkgRefDo) {
57         super(null, TAG, 0, 0);
58         mAidDo = aidRefDo;
59         mHashDo = hashRefDo;
60         mPkgDo = pkgRefDo;
61     }
62 
REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo)63     public REF_DO(AID_REF_DO aidRefDo, Hash_REF_DO hashRefDo) {
64         super(null, TAG, 0, 0);
65         mAidDo = aidRefDo;
66         mHashDo = hashRefDo;
67         mPkgDo = null;
68     }
69 
70     @Override
toString()71     public String toString() {
72         StringBuilder b = new StringBuilder();
73         b.append("REF_DO: ");
74         if (mAidDo != null) {
75             b.append(mAidDo.toString());
76             b.append(' ');
77         }
78         if (mHashDo != null) {
79             b.append(mHashDo.toString());
80             b.append(' ');
81         }
82         if (mPkgDo != null) {
83             b.append(mPkgDo.toString());
84         }
85         return b.toString();
86     }
87 
getAidDo()88     public AID_REF_DO getAidDo() {
89         return mAidDo;
90     }
91 
getHashDo()92     public Hash_REF_DO getHashDo() {
93         return mHashDo;
94     }
95 
getPkgDo()96     public PKG_REF_DO getPkgDo() {
97         return mPkgDo;
98     }
99 
100     /**
101      * Interpret data.
102      *
103      * <p>Tags: E1 -> Length: n
104      *
105      * <p>Value:
106      *    1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO.
107      *    2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a
108      *       PKG-REF-DO.
109      *
110      * <p>Length: n bytes.
111      */
112     @Override
interpret()113     public void interpret() throws ParserException {
114 
115         mAidDo = null;
116         mHashDo = null;
117         mPkgDo = null;
118 
119         byte[] data = getRawData();
120         int index = getValueIndex();
121 
122         if (index + getValueLength() > data.length) {
123             throw new ParserException("Not enough data for AR_DO!");
124         }
125 
126         do {
127             BerTlv temp = BerTlv.decode(data, index);
128 
129             if (temp.getTag() == AID_REF_DO.TAG
130                     || temp.getTag() == AID_REF_DO.TAG_DEFAULT_APPLICATION) { // AID-REF-DO
131                 mAidDo = new AID_REF_DO(data, temp.getTag(), temp.getValueIndex(),
132                         temp.getValueLength());
133                 mAidDo.interpret();
134             } else if (temp.getTag() == Hash_REF_DO.TAG) { // Hash-REF-DO
135                 mHashDo = new Hash_REF_DO(data, temp.getValueIndex(), temp.getValueLength());
136                 mHashDo.interpret();
137             } else if (temp.getTag() == PKG_REF_DO.TAG) { // PKG-REF-DO
138                 mPkgDo = new PKG_REF_DO(data, temp.getValueIndex(), temp.getValueLength());
139                 mPkgDo.interpret();
140             } else {
141                 // uncomment following line if a more restrictive
142                 // behaviour is necessary.
143                 // throw new ParserException("Invalid DO in REF-DO!");
144             }
145             index = temp.getValueIndex() + temp.getValueLength();
146         } while (getValueIndex() + getValueLength() > index);
147 
148         if (mAidDo != null && !mAidDo.isCarrierPrivilege() && mHashDo != null && mPkgDo != null) {
149             throw new ParserException("Unexpected combination of SEAC DOs and DAC DO");
150         }
151 
152         // A rule without AID is a Carrier Privilege Rule.
153         // Enforces the AID to be the Carrier Privilege AID to avoid a null AID.
154         if (mAidDo == null && mHashDo != null) {
155             mAidDo = AID_REF_DO.createCarrierPrivilegeAid();
156         }
157 
158         // check if there is a AID-REF-DO
159         if (mAidDo == null) {
160             throw new ParserException("Missing AID-REF-DO in REF-DO!");
161         }
162         // check if there is a Hash-REF-DO
163         if (mHashDo == null) {
164             throw new ParserException("Missing Hash-REF-DO in REF-DO!");
165         }
166     }
167 
168     /**
169      * Tag: E1 Length: n Value:
170      *     1. AID-REF-DO | Hash-REF-DO: A concatenation of an AID-REF-DO and a Hash-REF-DO.
171      *     2. Hash-REF-DO or Hash-REF-DO | PKG-REF-DO A concatenation of a Hash-REF-DO and a
172      *        PKG-REF-DO.
173      */
174     @Override
build(ByteArrayOutputStream stream)175     public void build(ByteArrayOutputStream stream) throws DO_Exception {
176         ByteArrayOutputStream temp = new ByteArrayOutputStream();
177 
178         if (mHashDo == null) {
179             throw new DO_Exception("REF-DO: Required DO missing!");
180         }
181 
182         if (mAidDo != null) {
183             mAidDo.build(temp);
184         }
185 
186         if (mHashDo != null) {
187             mHashDo.build(temp);
188         }
189 
190         if (mPkgDo != null) {
191             mPkgDo.build(temp);
192         }
193 
194         byte[] data = temp.toByteArray();
195         BerTlv tlv = new BerTlv(data, getTag(), 0, data.length);
196         tlv.build(stream);
197     }
198 
199     @Override
equals(Object obj)200     public boolean equals(Object obj) {
201         if (obj instanceof REF_DO) {
202             REF_DO ref_do = (REF_DO) obj;
203             if (getTag() == ref_do.getTag()) {
204                 if (AID_REF_DO.equals(mAidDo, ref_do.mAidDo)) {
205                     if (Hash_REF_DO.equals(mHashDo, ref_do.mHashDo)) {
206                         if (PKG_REF_DO.equals(mPkgDo, ref_do.mPkgDo)) {
207                             return true;
208                         }
209                     }
210                 }
211             }
212         }
213         return false;
214     }
215 
216     @Override
hashCode()217     public int hashCode() {
218         ByteArrayOutputStream stream = new ByteArrayOutputStream();
219         try {
220             this.build(stream);
221         } catch (DO_Exception e) {
222             return 1;
223         }
224         byte[] data = stream.toByteArray();
225         int hash = Arrays.hashCode(data);
226         // int hash = data.hashCode();
227         return hash;
228     }
229 
isCarrierPrivilegeRefDo()230     public boolean isCarrierPrivilegeRefDo() {
231         return (mAidDo != null && mAidDo.isCarrierPrivilege());
232     }
233 }
234