Add rule for 'All devices apps' when access rule is empty.
[platform/core/connectivity/smartcard-service.git] / common / GPARAACL.cpp
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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 #include "Debug.h"
18 #include "GPARAACL.h"
19 #include "GPARAM.h"
20 #include "NumberStream.h"
21 #include "SimpleTLV.h"
22 #include "ISO7816BERTLV.h"
23 #include "AccessCondition.h"
24
25 #ifndef EXTERN_API
26 #define EXTERN_API __attribute__((visibility("default")))
27 #endif
28
29 namespace smartcard_service_api
30 {
31         static unsigned char aid_aram[] = { 0xA0, 0x00, 0x00, 0x01, 0x51, 0x41, 0x43, 0x4C, 0x00 };
32         static ByteArray AID_ARAM(ARRAY_AND_SIZE(aid_aram));
33
34 #define GET_DATA_ALL            0
35 #define GET_DATA_SPECIFIC       1
36 #define GET_DATA_REFRESH_TAG    2
37 #define GET_DATA_NEXT           3
38
39 #define ARAM_TAG_ALL_AR         0x0000FF40
40 #define ARAM_TAG_AR             0x0000FF50
41 #define ARAM_TAG_REFRESH        0x0000DF20
42
43 #define DO_TAG_AID_REF          0x0000004F
44 #define DO_TAG_AID_REF_DEFAULT  0x000000C0
45 #define DO_TAG_HASH_REF         0x000000C1
46 #define DO_TAG_APDU_AR          0x000000D0
47 #define DO_TAG_NFC_AR           0x000000D1
48 #define DO_TAG_REF              0x000000E1
49 #define DO_TAG_REF_AR           0x000000E2
50 #define DO_TAG_AR               0x000000E3
51
52         GPARAACL::GPARAACL() : AccessControlList()
53         {
54         }
55
56         GPARAACL::~GPARAACL()
57         {
58         }
59
60         static ByteArray getAID(SimpleTLV &tlv)
61         {
62                 ByteArray result;
63
64                 _BEGIN();
65
66                 if (tlv.decodeTLV() == true) {
67                         switch (tlv.getTag()) {
68                         case DO_TAG_AID_REF :
69                                 if (tlv.size() > 0) {
70                                         result = tlv.getValue();
71                                 } else {
72                                         result = AccessControlList::ALL_SE_APPS;
73                                 }
74                                 break;
75
76                         case DO_TAG_AID_REF_DEFAULT :
77                                 result = AccessControlList::DEFAULT_SE_APP;
78                                 break;
79
80                         default :
81                                 _ERR("decodeTLV failed, %s", tlv.toString().c_str());
82                                 break;
83                         }
84                 } else {
85                         _ERR("decodeTLV failed, %s", tlv.toString().c_str());
86                 }
87
88                 _END();
89
90                 return result;
91         }
92
93         static ByteArray getHash(SimpleTLV &tlv)
94         {
95                 ByteArray result;
96
97                 _BEGIN();
98
99                 if (tlv.decodeTLV() == true &&
100                         tlv.getTag() == DO_TAG_HASH_REF) {
101                         if (tlv.size() > 0) {
102                                 result = tlv.getValue();
103                         } else {
104                                 result = AccessControlList::ALL_DEVICE_APPS;
105                         }
106                 } else {
107                         _ERR("decodeTLV failed, %s", tlv.toString().c_str());
108                 }
109
110                 _END();
111
112                 return result;
113         }
114
115         static int parseRefDO(SimpleTLV &tlv, ByteArray &aid, ByteArray &hash)
116         {
117                 int result = SCARD_ERROR_OK;
118
119                 _BEGIN();
120
121                 if (tlv.decodeTLV() == true && tlv.getTag() == DO_TAG_REF) {
122                         tlv.enterToValueTLV();
123                         aid = getAID(tlv);
124                         hash = getHash(tlv);
125                         tlv.returnToParentTLV();
126
127                         _DBG("aid : %s, hash : %s", aid.toString().c_str(), hash.toString().c_str());
128                 } else {
129                         _ERR("unknown tag : %s", tlv.toString().c_str());
130                         result = SCARD_ERROR_ILLEGAL_PARAM;
131                 }
132
133                 _END();
134
135                 return result;
136         }
137
138         static int parseARDO(SimpleTLV &tlv, vector<ByteArray> &apduRule,
139                 ByteArray &nfcRule)
140         {
141                 int result = SCARD_ERROR_OK;
142
143                 _BEGIN();
144
145                 if (tlv.decodeTLV() == true && tlv.getTag() == DO_TAG_AR) {
146                         tlv.enterToValueTLV();
147                         while (tlv.decodeTLV() == true) {
148                                 int length = tlv.size();
149
150                                 switch (tlv.getTag()) {
151                                 case DO_TAG_APDU_AR :
152                                         if (length > 1) {
153                                                 int i;
154                                                 ByteArray temp;
155
156                                                 for (i = 0; i < length; i += 8) {
157                                                         temp.assign(tlv.getValue().getBuffer(i), 8);
158                                                         _DBG("apdu rule[%d] : %s", temp.size(), temp.toString().c_str());
159                                                         apduRule.push_back(temp);
160                                                 }
161                                         } else if (length == 1){
162                                                 _DBG("apdu rule : %s", tlv.getValue().toString().c_str());
163                                                 apduRule.push_back(tlv.getValue());
164                                         } else {
165                                                 _ERR("invalid rule, %s", tlv.toString().c_str());
166                                         }
167                                         break;
168
169                                 case DO_TAG_NFC_AR :
170                                         nfcRule = tlv.getValue();
171                                         _DBG("nfc rule : %s", tlv.getValue().toString().c_str());
172                                         break;
173
174                                 default :
175                                         break;
176                                 }
177                         }
178                         tlv.returnToParentTLV();
179                 } else {
180                         result = SCARD_ERROR_ILLEGAL_PARAM;
181                 }
182
183                 _END();
184
185                 return result;
186         }
187
188         void GPARAACL::addCondition(const ByteArray &aid, const ByteArray &hash,
189                 const vector<ByteArray> &apduRule, const ByteArray &nfcRule)
190         {
191                 AccessCondition &condition = getAccessCondition(aid);
192
193                 _BEGIN();
194
195                 condition.addAccessRule(hash);
196
197                 if (apduRule.size() > 0) {
198                         if (apduRule.size() == 1 &&
199                                 apduRule[0].size() == 1) {
200                                 /* apdu grant/deny */
201                                 if (apduRule[0][0] == 1) {
202                                         condition.setAPDUAccessRule(hash, true);
203                                 } else {
204                                         condition.setAPDUAccessRule(hash, false);
205                                 }
206                         } else {
207                                 size_t i;
208
209                                 for (i = 0; i < apduRule.size(); i++) {
210                                         condition.addAPDUAccessRule(hash, apduRule[i]);
211                                 }
212                         }
213                 }
214
215                 if (nfcRule.size() == 1) {
216                         if (nfcRule[0] == 1) {
217                                 condition.setNFCAccessRule(hash, true);
218                         } else {
219                                 condition.setNFCAccessRule(hash, false);
220                         }
221                 }
222
223                 _END();
224         }
225
226         int GPARAACL::updateRule(const ByteArray &data)
227         {
228                 int result = SCARD_ERROR_OK;
229                 SimpleTLV tlv(data);
230
231                 _BEGIN();
232
233                 while (tlv.decodeTLV() == true) {
234                         if (tlv.getTag() == DO_TAG_REF_AR) {
235                                 ByteArray aid, hash, nfcRule;
236                                 vector<ByteArray> apduRule;
237
238                                 tlv.enterToValueTLV();
239                                 result = parseRefDO(tlv, aid, hash);
240
241                                 if (result >= SCARD_ERROR_OK) {
242                                         result = parseARDO(tlv, apduRule, nfcRule);
243                                 }
244                                 tlv.returnToParentTLV();
245
246                                 addCondition(aid, hash, apduRule, nfcRule);
247                         } else {
248                                 _ERR("unknown tag, [%x]", tlv.getTag());
249                                 result = SCARD_ERROR_ILLEGAL_PARAM;
250                                 break;
251                         }
252                 }
253
254                 _END();
255
256                 return result;
257         }
258
259         int GPARAACL::loadACL(GPARAM &aram)
260         {
261                 int result = SCARD_ERROR_OK;
262                 ByteArray refreshTag, response;
263
264                 _BEGIN();
265
266                 if (aram.isClosed() == true) {
267                         return SCARD_ERROR_ILLEGAL_STATE;
268                 }
269
270                 /* get refresh tag */
271                 result = aram.getDataRefreshTag(refreshTag);
272                 if (result >= SCARD_ERROR_OK) {
273                         /* check refresh tag */
274                         if (this->refreshTag.isEmpty() == true ||
275                                 this->refreshTag != refreshTag) {
276                                 result = aram.getDataAll(response);
277                                 if (result >= SCARD_ERROR_OK) {
278                                         result = updateRule(response);
279
280                                         /* update refresh tag */
281                                         this->refreshTag = refreshTag;
282                                 } else {
283                                         _ERR("getDataAll failed, [%x]", result);
284                                 }
285                         }
286                         else
287                         {
288                                 _INFO("access rules are not changed. skip update");
289                         }
290                 } else {
291                         _ERR("transmitSync failed, %x", result);
292                 }
293
294                 _END();
295
296                 return result;
297         }
298
299         int GPARAACL::loadACL(Channel *channel)
300         {
301                 int result = SCARD_ERROR_OK;
302
303                 _BEGIN();
304
305                 if (channel == NULL) {
306                         return SCARD_ERROR_ILLEGAL_PARAM;
307                 }
308
309                 GPARAM aram(channel);
310
311                 result = aram.select();
312                 if (result >= SCARD_ERROR_OK) {
313                         result = loadACL(aram);
314                 } else {
315                         _ERR("select failed, [%x]", result);
316                 }
317
318                 _END();
319
320                 return result;
321         }
322
323         static bool _isAuthorizedAccess(const ByteArray &data, const ByteArray &command)
324         {
325                 vector<ByteArray> apduRule;
326                 ByteArray nfcRule;
327                 SimpleTLV tlv(data);
328                 bool result = false;
329
330                 if (parseARDO(tlv, apduRule, nfcRule) >= SCARD_ERROR_OK) {
331                         if (apduRule.size() > 0) {
332                                 if (apduRule.size() > 1 ||
333                                         apduRule[0].size() != 1) {
334                                         if (command.size() > 0) {
335                                                 /* TODO : check apdu rule */
336                                         } else {
337                                                 /* check hash only */
338                                                 result = true;
339                                         }
340                                 } else {
341                                         result = (apduRule[0][0] == 1 ? true : false);
342                                 }
343                         } else {
344                                 _ERR("unknown data : %s", tlv.toString().c_str());
345                         }
346                 } else {
347                         _ERR("parseARDO failed : %s", tlv.toString().c_str());
348                 }
349
350                 return result;
351         }
352
353         static bool _isAuthorizedNFCAccess(const ByteArray &data)
354         {
355                 vector<ByteArray> apduRule;
356                 ByteArray nfcRule;
357                 SimpleTLV tlv(data);
358                 bool result = false;
359
360                 if (parseARDO(tlv, apduRule, nfcRule) >= SCARD_ERROR_OK) {
361                         if (nfcRule.size() == 1) {
362                                 result = (nfcRule[0] == 1 ? true : false);
363                         } else {
364                                 _ERR("unknown data : %s", nfcRule.toString().c_str());
365                         }
366                 } else {
367                         _ERR("parseARDO failed : %s", tlv.toString().c_str());
368                 }
369
370                 return result;
371         }
372
373         bool GPARAACL::isAuthorizedAccess(GPARAM &aram, const ByteArray &aid,
374                 const ByteArray &certHash) const
375         {
376                 vector<ByteArray> hashes;
377
378                 hashes.push_back(certHash);
379
380                 return isAuthorizedAccess(aram, aid, hashes, ByteArray::EMPTY);
381         }
382
383         bool GPARAACL::isAuthorizedAccess(GPARAM &aram,
384                 const unsigned char *aidBuffer,
385                 unsigned int aidLength,
386                 const unsigned char *certHashBuffer,
387                 unsigned int certHashLength) const
388         {
389                 ByteArray aid(aidBuffer, aidLength);
390                 ByteArray hash(certHashBuffer, certHashLength);
391
392                 return isAuthorizedAccess(aram, aid, hash);
393         }
394
395         bool GPARAACL::isAuthorizedAccess(GPARAM &aram, const ByteArray &aid,
396                 const vector<ByteArray> &certHashes) const
397         {
398                 return isAuthorizedAccess(aram, aid, certHashes, ByteArray::EMPTY);
399         }
400
401         bool GPARAACL::isAuthorizedAccess(GPARAM &aram, const ByteArray &aid,
402                 const vector<ByteArray> &certHashes, const ByteArray &command) const
403         {
404                 bool result = allGranted;
405                 ByteArray data;
406                 vector<ByteArray>::const_reverse_iterator item;
407
408                 if (aram.isClosed() == true)
409                         return result;
410
411                 _BEGIN();
412
413                 if (result == true) {
414                         goto END;
415                 }
416                 /* Step A, find with aid and cert hashes */
417                 for (item = certHashes.rbegin();
418                         result == false && item != certHashes.rend();
419                         item++) {
420                         if (aram.getDataSpecific(aid, *item, data)
421                                 >= SCARD_ERROR_OK && data.size() > 0) {
422                                 result = _isAuthorizedAccess(data, command);
423                                 _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", aid.toString().c_str(), (*item).toString().c_str());
424                                 goto END;
425                         }
426                 }
427
428                 /* Step B, find with aid and ALL_DEVICES_APPS */
429                 if (aram.getDataSpecific(aid, ByteArray::EMPTY, data)
430                         >= SCARD_ERROR_OK && data.size() > 0) {
431                         result = _isAuthorizedAccess(data, command);
432                         _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", aid.toString().c_str(), "All device applications");
433                         goto END;
434                 }
435
436                 /* Step C, find with ALL_SE_APPS and hashes */
437                 for (item = certHashes.rbegin();
438                         result == false && item != certHashes.rend();
439                         item++) {
440                         if (aram.getDataSpecific(ByteArray::EMPTY, *item, data)
441                                 >= SCARD_ERROR_OK && data.size() > 0) {
442                                 result = _isAuthorizedAccess(data, command);
443                                 _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", "All SE Applications", (*item).toString().c_str());
444                                 goto END;
445                         }
446                 }
447
448                 /* Step D, find with ALL_SE_APPS and ALL_DEVICES_APPS */
449                 if (aram.getDataSpecific(ByteArray::EMPTY, ByteArray::EMPTY, data)
450                         >= SCARD_ERROR_OK && data.size() > 0) {
451                         result = _isAuthorizedAccess(data, command);
452                         _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", "All SE Applications", "All device applications");
453                         goto END;
454                 }
455
456         END :
457                 _END();
458
459                 return result;
460         }
461
462         bool GPARAACL::isAuthorizedNFCAccess(GPARAM &aram, const ByteArray &aid,
463                 const vector<ByteArray> &certHashes) const
464         {
465                 bool result = allGranted;
466                 ByteArray data;
467                 vector<ByteArray>::const_reverse_iterator item;
468
469                 if (aram.isClosed() == true)
470                         return result;
471
472                 _BEGIN();
473
474                 if (result == true) {
475                         goto END;
476                 }
477                 /* Step A, find with aid and cert hashes */
478                 for (item = certHashes.rbegin();
479                         result == false && item != certHashes.rend();
480                         item++) {
481                         if (aram.getDataSpecific(aid, *item, data)
482                                 >= SCARD_ERROR_OK && data.size() > 0) {
483                                 result = _isAuthorizedNFCAccess(data);
484                                 _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", aid.toString().c_str(), (*item).toString().c_str());
485                                 goto END;
486                         }
487                 }
488
489                 /* Step B, find with aid and ALL_DEVICES_APPS */
490                 if (aram.getDataSpecific(aid, ByteArray::EMPTY, data)
491                         >= SCARD_ERROR_OK && data.size() > 0) {
492                         result = _isAuthorizedNFCAccess(data);
493                         _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", aid.toString().c_str(), "All device applications");
494                         goto END;
495                 }
496
497                 /* Step C, find with ALL_SE_APPS and hashes */
498                 for (item = certHashes.rbegin();
499                         result == false && item != certHashes.rend();
500                         item++) {
501                         if (aram.getDataSpecific(ByteArray::EMPTY, *item, data)
502                                 >= SCARD_ERROR_OK && data.size() > 0) {
503                                 result = _isAuthorizedNFCAccess(data);
504                                 _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", "All SE Applications", (*item).toString().c_str());
505                                 goto END;
506                         }
507                 }
508
509                 /* Step D, find with ALL_SE_APPS and ALL_DEVICES_APPS */
510                 if (aram.getDataSpecific(ByteArray::EMPTY, ByteArray::EMPTY, data)
511                         >= SCARD_ERROR_OK && data.size() > 0) {
512                         result = _isAuthorizedNFCAccess(data);
513                         _INFO("rule found (%s): [%s:%s]", result ? "accept" : "deny", "All SE Applications", "All device applications");
514                         goto END;
515                 }
516
517         END :
518                 _END();
519
520                 return result;
521         }
522 } /* namespace smartcard_service_api */