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) 2015-2017, The Linux Foundation.
18  */
19 
20 /*
21  * Copyright (C) 2011 Deutsche Telekom, A.G.
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 
36 /*
37  * Contributed by: Giesecke & Devrient GmbH.
38  */
39 
40 package com.android.se.security.arf.pkcs15;
41 
42 import android.util.Log;
43 
44 import com.android.se.internal.Util;
45 import com.android.se.security.ApduFilter;
46 import com.android.se.security.ChannelAccess;
47 import com.android.se.security.arf.ASN1;
48 import com.android.se.security.arf.DERParser;
49 import com.android.se.security.arf.SecureElement;
50 import com.android.se.security.gpac.AID_REF_DO;
51 import com.android.se.security.gpac.Hash_REF_DO;
52 
53 import java.io.IOException;
54 import java.util.Vector;
55 
56 /** EF_ACConditions related features ************************************************* */
57 public class EFACConditions extends EF {
58 
59     public static final String TAG = "ACE ARF EF_ACConditions";
60 
61     // Identification of the cardlet
62     private AID_REF_DO mAidRefDo = null;
63 
64     private byte[] mData = null;
65 
66     /**
67      * Constructor
68      *
69      * @param secureElement SE on which ISO7816 commands are applied
70      * @param AID           Identification of the applet
71      */
EFACConditions(SecureElement handle, AID_REF_DO aidRefDo)72     public EFACConditions(SecureElement handle, AID_REF_DO aidRefDo) {
73         super(handle);
74         mAidRefDo = aidRefDo;
75     }
76 
77     /**
78      * Decodes EF_ACConditions file
79      *
80      * @param buffer ASN.1 data
81      */
decodeDER(byte[] buffer)82     private void decodeDER(byte[] buffer) throws PKCS15Exception {
83         byte[] certificateHash = null;
84         DERParser der = new DERParser(buffer);
85 
86         // the default channelAccess will deny every access.
87         ChannelAccess channelAccess = new ChannelAccess();
88         Hash_REF_DO hash_ref_do = new Hash_REF_DO();
89 
90         // empty condition file
91         if (der.isEndofBuffer()) {
92             channelAccess.setAccess(ChannelAccess.ACCESS.DENIED, "Empty ACCondition");
93             channelAccess.setNFCEventAccess(ChannelAccess.ACCESS.DENIED);
94             channelAccess.setApduAccess(ChannelAccess.ACCESS.DENIED);
95             channelAccess.setUseApduFilter(false);
96             channelAccess.setApduFilter(null);
97             Log.i(TAG, "Empty ACCondition: Access Deny for all apps");
98 
99             mSEHandle.putAccessRule(mAidRefDo, hash_ref_do, channelAccess);
100             return;
101         }
102 
103         // ----
104         // 2012-04-16
105     /*
106       Condition ::= SEQUENCE {
107              cert   CertHash OPTIONAL,
108              accessRules    [0]AccessRules OPTIONAL
109        }
110 
111        AccessRules ::= SEQUENCE OF AccessRule
112 
113        AccessRule ::=CHOICE {
114            apduAccessRule    [0]APDUAccessRule,
115            nfcAccessRule    [1]NFCAccessRule
116        }
117 
118        APDUAccessRule ::= CHOICE {
119               apduPermission [0] APDUPermission,
120               apduFilter [1] APDUFilter
121        }
122 
123        APDUFilters ::= SEQUENCE OF APDUFilter
124 
125        NFCAccessRule ::= CHOICE {
126               nfcPermission [0] NFCPermission
127        }
128     */
129         while (!der.isEndofBuffer()) {
130 
131             // if a hash value was found then access is allowed
132             // even if NO more access rule is given.
133             // missing APDU Permission will always allow APDU access
134             // missing NFC Permission will always allow NFC event.
135             // See GPAC Chapter 7.1.7
136             // See Examples in Annex C of GPAC
137             channelAccess = new ChannelAccess();
138             channelAccess.setAccess(ChannelAccess.ACCESS.ALLOWED, "");
139             channelAccess.setApduAccess(ChannelAccess.ACCESS.ALLOWED);
140             channelAccess.setNFCEventAccess(ChannelAccess.ACCESS.UNDEFINED);
141             channelAccess.setUseApduFilter(false);
142 
143             if (der.parseTLV(ASN1.TAG_Sequence) > 0) {
144                 byte[] tempTLVData = der.getTLVData();
145                 DERParser derRule = new DERParser(tempTLVData);
146 
147                 if (tempTLVData[0] == ASN1.TAG_OctetString) {
148                     derRule.parseTLV(ASN1.TAG_OctetString);
149                     certificateHash = derRule.getTLVData();
150 
151                     if (certificateHash.length != Hash_REF_DO.SHA1_LEN
152                             && certificateHash.length != Hash_REF_DO.SHA256_LEN
153                             && certificateHash.length != 0) {
154                         // other hash than SHA-1 and SHA-256 hash values are not supported.
155                         throw new PKCS15Exception("Invalid hash found!");
156                     } else {
157                         hash_ref_do = new Hash_REF_DO(certificateHash);
158                     }
159                 } else if (tempTLVData[0] == ASN1.TAG_Padding) {
160                     throw new PKCS15Exception("Invalid hash found!");
161                 } else {
162                     Log.i(TAG, "No hash included");
163                     // Let's put a null hash, to prioritize any more specific rule.
164                     hash_ref_do = new Hash_REF_DO(null);
165                 }
166 
167                 // 2012-04-16
168                 // parse optional Access Rule.
169                 if (!derRule.isEndofBuffer()) {
170 
171                     if (derRule.parseTLV() == (byte) 0xA0) {
172 
173                         DERParser derAccessRules = new DERParser(derRule.getTLVData());
174 
175                         while (!derAccessRules.isEndofBuffer()) {
176                             switch (derAccessRules.parseTLV()) {
177                                 // APDU Access Rule
178                                 case (byte) 0xA0:
179                                     DERParser derApduRule = new DERParser(
180                                             derAccessRules.getTLVData());
181                                     byte tagApduAccessRule = derApduRule.parseTLV();
182 
183                                     if (tagApduAccessRule
184                                             == (byte) 0x80) { // APDU Permission  (primitive)
185 
186                                         channelAccess.setApduAccess(
187                                                 derApduRule.getTLVData()[0] == 0x01
188                                                         ? ChannelAccess.ACCESS.ALLOWED
189                                                         : ChannelAccess.ACCESS.DENIED);
190 
191                                     } else if (tagApduAccessRule
192                                             == (byte) 0xA1) { // APDU Filter (constructed)
193 
194                                         DERParser derApduFilter = new DERParser(
195                                                 derApduRule.getTLVData());
196                                         byte tag = derApduFilter.parseTLV();
197 
198                                         if (tag == ASN1.TAG_OctetString) {
199 
200                                             Vector<ApduFilter> apduFilter =
201                                                     new Vector<ApduFilter>();
202 
203                                             // collect all apdu filter tlvs.
204                                             apduFilter.add(
205                                                     new ApduFilter(derApduFilter.getTLVData()));
206 
207                                             while (!derApduFilter.isEndofBuffer()) {
208                                                 if (derApduFilter.parseTLV()
209                                                         == ASN1.TAG_OctetString) {
210                                                     apduFilter.add(new ApduFilter(
211                                                             derApduFilter.getTLVData()));
212                                                 }
213                                             }
214                                             channelAccess.setUseApduFilter(true);
215                                             channelAccess.setApduFilter(
216                                                     apduFilter.toArray(
217                                                             new ApduFilter[apduFilter.size()]));
218                                         } else {
219                                             throw new PKCS15Exception("Invalid element found!");
220                                         }
221 
222                                     } else {
223                                         throw new PKCS15Exception("Invalid element found!");
224                                     }
225                                     break;
226                                 // NFC Access Rule
227                                 case (byte) 0xA1:
228                                     DERParser derNfc = new DERParser(derAccessRules.getTLVData());
229 
230                                     if (derNfc.parseTLV()
231                                             == (byte) 0x80) { // NFC Permission (primitive)
232                                         channelAccess.setNFCEventAccess(
233                                                 derNfc.getTLVData()[0] == (byte) 0x01
234                                                         ? ChannelAccess.ACCESS.ALLOWED
235                                                         : ChannelAccess.ACCESS.DENIED);
236                                     } else {
237                                         throw new PKCS15Exception("Invalid element found!");
238                                     }
239                                     break;
240                                 default:
241                                     throw new PKCS15Exception("Invalid element found!");
242                             }
243                         }
244                     } else {
245                         // no explicit access rule given.
246                     }
247                 }
248             } else {
249                 // coding 30 00 -> empty hash value given (all applications)
250                 if ((channelAccess.getNFCEventAccess() == ChannelAccess.ACCESS.UNDEFINED)
251                         && (channelAccess.getApduAccess() != ChannelAccess.ACCESS.UNDEFINED)) {
252                     channelAccess.setNFCEventAccess(channelAccess.getApduAccess());
253                 }
254             }
255             // ----
256             mSEHandle.putAccessRule(mAidRefDo, hash_ref_do, channelAccess);
257         }
258     }
259 
260     /**
261      * Stores a restricted list of certificate hashes
262      *
263      * @param path Path of the "EF_ACConditions" file
264      */
addRestrictedHashes(byte[] path)265     public void addRestrictedHashes(byte[] path) throws IOException, PKCS15Exception {
266         try {
267             Log.i(TAG, "Reading and analysing EF_ACConditions...");
268             if (selectFile(path) == APDU_SUCCESS) {
269                 mData = readBinary(0, Util.END);
270                 decodeDER(mData);
271             } else {
272                 Log.e(TAG, "EF_ACConditions not found!");
273             }
274         } catch (Exception e) {
275             throw new PKCS15Exception(e.getMessage());
276         }
277     }
278 
279     /**
280      * Stores a restricted list of certificate hashes
281      */
addRestrictedHashesFromData(byte[] data)282     public void addRestrictedHashesFromData(byte[] data) throws PKCS15Exception {
283         try {
284             Log.i(TAG, "Analysing cached EF_ACConditions data...");
285             if (data != null) {
286                 mData = data;
287                 decodeDER(mData);
288             } else {
289                 Log.e(TAG, "EF_ACConditions data not available!");
290             }
291         } catch (Exception e) {
292             throw new PKCS15Exception(e.getMessage());
293         }
294     }
295 
getData()296     public byte[] getData() {
297         return mData;
298     }
299 }
300