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.io.IOException;
39 import java.util.Arrays;
40 
41 /**
42  * The AID-REF-DO is used for retrieving and storing the corresponding access rules for an SE
43  * application (which is identified by its AID) from and to the ARA. Two different AID reference
44  * data objects exist and one of these can be chosen and applied for a GET DATA and STORE DATA
45  * command
46  */
47 public class AID_REF_DO extends BerTlv {
48 
49     public static final int TAG = 0x4F;
50     public static final int TAG_DEFAULT_APPLICATION = 0xC0;
51 
52     private static final byte[] CARRIER_PRIVILEGE_AID = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
53             (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
54     private byte[] mAid = new byte[0];
55 
AID_REF_DO(byte[] rawData, int tag, int valueIndex, int valueLength)56     public AID_REF_DO(byte[] rawData, int tag, int valueIndex, int valueLength) {
57         super(rawData, tag, valueIndex, valueLength);
58     }
59 
AID_REF_DO(int tag, byte[] aid)60     public AID_REF_DO(int tag, byte[] aid) {
61         super(aid, tag, 0, (aid == null ? 0 : aid.length));
62         if (aid != null) mAid = aid;
63     }
64 
AID_REF_DO(int tag)65     public AID_REF_DO(int tag) {
66         super(null, tag, 0, 0);
67     }
68 
69     /**
70      * Comapares two AID_REF_DO objects and returns true if they are equal
71      */
equals(AID_REF_DO obj1, AID_REF_DO obj2)72     public static boolean equals(AID_REF_DO obj1, AID_REF_DO obj2) {
73         if (obj1 == null) {
74             return (obj2 == null) ? true : false;
75         }
76         return obj1.equals(obj2);
77     }
78 
79     @Override
toString()80     public String toString() {
81         StringBuilder b = new StringBuilder();
82         ByteArrayOutputStream out = new ByteArrayOutputStream();
83         b.append("AID_REF_DO: ");
84         try {
85             this.build(out);
86             b.append(BerTlv.toHex(out.toByteArray()));
87         } catch (Exception e) {
88             b.append(e.getLocalizedMessage());
89         }
90         return b.toString();
91     }
92 
getAid()93     public byte[] getAid() {
94         return mAid;
95     }
96 
97     /**
98      * Tags: C0 -> Length: 0 -> Default selected application (all channels) 4F -> Length: 0 or 5 -
99      * 16
100      * bytes
101      *
102      * <p>Value: AID: identifies a specific application Empty: refers to all SE applications
103      *
104      * <p>Length: 5-16 for an AID according to ISO/IEC7816-5 0 for empty value field
105      */
106     @Override
interpret()107     public void interpret() throws ParserException {
108         byte[] data = getRawData();
109         int index = getValueIndex();
110 
111         if (getTag() == TAG_DEFAULT_APPLICATION) {
112             if (getValueLength() != 0) {
113                 throw new ParserException("Invalid value length for AID-REF-DO!");
114             }
115         } else if (getTag() == TAG) {
116 
117             // sanity checks
118             if ((getValueLength() < 5 || getValueLength() > 16) && getValueLength() != 0) {
119                 throw new ParserException("Invalid value length for AID-REF-DO!");
120             }
121 
122             if (index + getValueLength() > data.length) {
123                 throw new ParserException("Not enough data for AID-REF-DO!");
124             }
125 
126             mAid = new byte[getValueLength()];
127             System.arraycopy(data, index, mAid, 0, getValueLength());
128 
129         } else {
130             throw new ParserException("Invalid Tag for AID-REF-DO!");
131         }
132     }
133 
134     /**
135      * Tags: C0 -> Length: 0 -> Default selected application (all channels) 4F -> Length: 0 or 5 -
136      * 16
137      * bytes
138      *
139      * <p>Value: AID: identifies a specific application Empty: refers to all SE applications
140      *
141      * <p>Length: 5-16 for an AID according to ISO/IEC7816-5 0 for empty value field
142      */
143     @Override
build(ByteArrayOutputStream stream)144     public void build(ByteArrayOutputStream stream) throws DO_Exception {
145 
146         if (getTag() == TAG_DEFAULT_APPLICATION) {
147             if (mAid.length > 0) {
148                 throw new DO_Exception("No value allowed for default selected application!");
149             }
150             stream.write(getTag());
151             stream.write(0x00);
152         } else if (getTag() == TAG) {
153 
154             // sanity check
155             if (getValueLength() != 0) {
156                 if (getValueLength() < 5 || getValueLength() > 16) {
157                     throw new DO_Exception("Invalid length of AID!");
158                 }
159             }
160 
161             stream.write(getTag());
162             stream.write(mAid.length);
163             try {
164                 stream.write(mAid);
165             } catch (IOException ioe) {
166                 throw new DO_Exception("AID could not be written!");
167             }
168         } else {
169             throw new DO_Exception("AID-REF-DO must either be C0 or 4F!");
170         }
171     }
172 
173     @Override
equals(Object obj)174     public boolean equals(Object obj) {
175         if (obj instanceof AID_REF_DO) {
176             AID_REF_DO aid_ref_do = (AID_REF_DO) obj;
177             if (getTag() == aid_ref_do.getTag()) {
178                 return Arrays.equals(mAid, aid_ref_do.mAid);
179             }
180         }
181         return false;
182     }
183 
184     /** Checks if the AID_REF_DO is a Carrier Privilege rule */
isCarrierPrivilege()185     public boolean isCarrierPrivilege() {
186         return Arrays.equals(mAid, CARRIER_PRIVILEGE_AID);
187     }
188 
189     /** Creates a Carrier Privilege AID_REF_DO */
createCarrierPrivilegeAid()190     public static AID_REF_DO createCarrierPrivilegeAid() {
191         return new AID_REF_DO(AID_REF_DO.TAG, CARRIER_PRIVILEGE_AID);
192     }
193 }
194