Fix path to TA checking
[platform/core/security/tef-simulator.git] / simulatordaemon / src / TABinaryManager / TABinaryManager.cpp
1 /**
2  * Copyright (c) 2015-2017 Samsung Electronics Co., Ltd All Rights Reserved
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 /**
18  * @file
19  * @author CHERYL (cb) (cheryl.b@samsung.com)
20  * @brief  TABinaryManager class
21  */
22
23
24 /*-----------------------------------------------------------------------------
25  *  Include files
26  *-----------------------------------------------------------------------------*/
27 #include "TABinaryManager.h"
28 #include <iostream>
29 #include <fstream>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/file.h>
36 #include <algorithm>
37 #include <boost/filesystem.hpp>
38 /*-----------------------------------------------------------------------------
39  *  Globals
40  *-----------------------------------------------------------------------------*/
41 TABinaryManager *TABinaryManager::instance = NULL;
42 pthread_rwlock_t binaryMapLock;
43 map<string, StructBinaryInfo> binaryMap;
44
45 /*-----------------------------------------------------------------------------
46  *  Member functions
47  *-----------------------------------------------------------------------------*/
48 /**
49  * Checks if a characters is part of base64 encoding character set
50  * @param c character to be verified
51  * @return true if conformant to base64 charset else false
52  */
53 bool TABinaryManager::is_base64(unsigned char c) {
54         return (isalnum(c) || (c == '+') || (c == '/'));
55 }
56
57 /**
58  * Thanks to: René Nyffenegger
59  * Reused from: http://www.adp-gmbh.ch/cpp/common/base64.html
60  * License Notice:
61  * Copyright (C) 2004-2008 René Nyffenegger
62  *
63  *  This source code is provided 'as-is', without any express or implied
64  *  warranty. In no event will the author be held liable for any damages
65  *  arising from the use of this software.
66  *
67  *  Permission is granted to anyone to use this software for any purpose,
68  *  including commercial applications, and to alter it and redistribute it
69  *  freely, subject to the following restrictions:
70  *
71  *  1. The origin of this source code must not be misrepresented; you must not
72  *     claim that you wrote the original source code. If you use this source code
73  *     in a product, an acknowledgment in the product documentation would be
74  *     appreciated but is not required.
75  *
76  *  2. Altered source versions must be plainly marked as such, and must not be
77  *     misrepresented as being the original source code.
78  *
79  *  3. This notice may not be removed or altered from any source distribution.
80  *
81  *  René Nyffenegger rene.nyffenegger@adp-gmbh.ch
82  *
83  * @param encoded_string
84  * @return
85  */
86 string TABinaryManager::base64_decode(std::string const& encoded_string) {
87         int in_len = encoded_string.size();
88         int i = 0;
89         int j = 0;
90         int in_ = 0;
91         unsigned char char_array_4[4], char_array_3[3];
92         std::string ret;
93
94         while (in_len-- && (encoded_string[in_] != '=')
95             && is_base64(encoded_string[in_])) {
96                 char_array_4[i++] = encoded_string[in_];
97                 in_++;
98                 if (i == 4) {
99                         for (i = 0; i < 4; i++)
100                                 char_array_4[i] = base64_chars.find(char_array_4[i]);
101                         char_array_3[0] = (char_array_4[0] << 2)
102                             + ((char_array_4[1] & 0x30) >> 4);
103                         char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
104                             + ((char_array_4[2] & 0x3c) >> 2);
105                         char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
106                         for (i = 0; (i < 3); i++)
107                                 ret += char_array_3[i];
108                         i = 0;
109                 }
110         }
111         if (i) {
112                 for (j = i; j < 4; j++)
113                         char_array_4[j] = 0;
114                 for (j = 0; j < 4; j++)
115                         char_array_4[j] = base64_chars.find(char_array_4[j]);
116                 char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
117                 char_array_3[1] = ((char_array_4[1] & 0xf) << 4)
118                     + ((char_array_4[2] & 0x3c) >> 2);
119                 char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
120                 for (j = 0; (j < i - 1); j++)
121                         ret += char_array_3[j];
122         }
123         return ret;
124 }
125
126
127 /**
128  * This is the constructor of TABinaryManger.
129  */
130 TABinaryManager::TABinaryManager() {
131         //Stat for mod time
132
133         /// Constant charset of base64 encoding
134         base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
135                         "abcdefghijklmnopqrstuvwxyz"
136                         "0123456789+/";
137
138         pthread_rwlock_init(&binaryMapLock, NULL);
139         pthread_mutex_init(&taLock, NULL);
140 }
141
142 /**
143  * This function returns the TA Binary Manager instance if already created
144  * else creates the instance and returns it
145  */
146 TABinaryManager* TABinaryManager::getInstance() {
147         if (NULL == instance) {
148             try {
149                     instance = new TABinaryManager();
150                 }catch (std::bad_alloc &ba) {
151                     return NULL;
152             }
153         }
154         return instance;
155 }
156
157 /**
158  * This function add TA at given path to BinaryManager if it exists.
159  * @return On successful completion of above operations returns true else false.
160  */
161 bool TABinaryManager::initTAatPath(const string &path, const string &uuid) {
162         LOGD(SIM_DAEMON, "");
163
164         pthread_rwlock_wrlock(&binaryMapLock);
165         StructBinaryInfo value;
166         bool res = false;
167         StructBinaryInfo info;
168
169         if (boost::filesystem::exists(path + uuid)) {
170                 pthread_mutex_lock(&taLock);
171                 try {
172                         if (unpackBinary(uuid, path, info)) {
173                                 binaryMap[uuid] = info;
174                                 res = true;
175                         }
176                 } catch (...) {
177                         res = false;
178                 }
179                 pthread_mutex_unlock(&taLock);
180         }
181         pthread_rwlock_unlock(&binaryMapLock);
182         return res;
183 }
184
185
186 /**
187  * This function decrypts the TA Binary image
188  * @param uuid TA UUID in string format
189  * @param info TA Binary info
190  */
191 void TABinaryManager::decryptImage(StructBinaryInfo& info) {
192         string cipher = "-aes-256-cbc";
193         string secret = base64_decode (info.manifest.taencryption.model.plainkeydata);
194         string keyhashFilename = info.imagePath + ".keyhash";
195         secret.erase(secret.size()-2);
196         string keyHash = "echo -n " + secret + " | openssl dgst -sha256 | awk '{print $2}' > " + keyhashFilename;
197         int result = system(keyHash.c_str());
198         if (result != 0) {
199                 LOGE(SIM_DAEMON, "Hashing key failed");
200         }
201
202         string line;
203         ifstream myfile(keyhashFilename.c_str());
204         if (myfile.is_open()) {
205                 getline(myfile, line);
206                 myfile.close();
207         }
208
209         // hash of Keydata is not required.
210         string dec_command = "openssl enc " + cipher + " -d -nopad -nosalt -K " + secret
211                 + " -in " + info.imagePath + " -out " + info.imagePath
212                 + "_dec -iv 0000000000000000";
213         result = system(dec_command.c_str());
214         if (result != 0) {
215                 LOGE(SIM_DAEMON, "Image decryption failed");
216         }
217
218         string removeEncImage = "rm -f " + info.imagePath;
219         result = system(removeEncImage.c_str());
220         if (result != 0) {
221                 LOGE(SIM_DAEMON, "Post decryption operations failed");
222         }
223
224         string renameDecImage = "mv " + info.imagePath + "_dec " + info.imagePath;
225         result = system(renameDecImage.c_str());
226         if (result != 0) {
227                 LOGE(SIM_DAEMON, "Post decryption operations failed");
228         }
229
230         string removeKeyHash = "rm -f " + keyhashFilename;
231         result = system(removeKeyHash.c_str());
232         if (result != 0) {
233                 LOGE(SIM_DAEMON, "Post decryption operations failed");
234         }
235 }
236
237 /**
238  * This function reads unpacks files to their respective locations.
239  * It also reads manifest file and keeps it ready for queries on fields
240  * in manifest.
241  * @param uuid TA UUID in string format
242  * @param info TA Binary info
243  * @return On successful completion of above operations returns true else false.
244  * It is very important to check for return value from this function.
245  */
246
247 bool TABinaryManager::unpackBinary(const string &uuid, const string &path, StructBinaryInfo& info) {
248         TAUnpack* unpacker = TAUnpack::getInstance();
249         bool ret = false;
250         LOGE(SIM_DAEMON, "Unpacking TA %s in %s", uuid.c_str(), path.c_str());
251         if (0 == unpacker->unpackTA(path, uuid)) {
252                 LOGE(SIM_DAEMON, "Unpacked, filling info");
253                 // 1. Set binary info
254                 info.path = path + uuid;
255                 info.extractpath = path + uuid + "-ext/";
256                 info.imagePath = info.extractpath + uuid + ".image";
257                 info.manifestPath = info.extractpath + uuid + ".manifest";
258                 // 2. Parse manifest and store results
259                 info.manifest.processXML(info.manifestPath);
260
261                 LOGE(SIM_DAEMON, "Decrypting");
262                 // 3. Decrypt image using secret value in manifest
263                 if (info.manifest.properties.extension.launchMode == "debug")
264                   decryptImage(info);
265
266                 string s = "chmod +x " + info.imagePath;
267                 int result = system(s.c_str());
268                 if (result != 0) {
269                         LOGE(SIM_DAEMON, "Unpacking executable TA failed");
270                 }
271
272                 ret = true;
273         }
274         return ret;
275 }
276
277 /**
278  * Check if TA is single instance
279  * @param[in] uuid UUID of TA
280  * @param[out] isSingleInstance returns value from this parameter.
281  * @return -1 if uuid is not found else on success 0
282  */
283
284 int TABinaryManager::isSingleInstance(string uuid, bool &SingleInstance) {
285         pthread_rwlock_wrlock(&binaryMapLock);
286         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
287         StructBinaryInfo value;
288         int ret = -1;
289         if (it != binaryMap.end()) {
290                 //element found;
291                 value = it->second;
292                 ret = 0;
293                 SingleInstance = value.manifest.properties.general.singleInstance;
294         }
295         pthread_rwlock_unlock(&binaryMapLock);
296         return ret;
297 }
298
299 /**
300  * Check if TA is KeepAlive
301  * @param[in] uuid UUID of TA
302  * @param[out] isKeepAlive returns value from this parameter.
303  * @return -1 if uuid is not found else on success 0
304  */
305
306 int TABinaryManager::isKeepAlive(string uuid, bool &KeepAlive) {
307         pthread_rwlock_wrlock(&binaryMapLock);
308         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
309         StructBinaryInfo value;
310         int ret = -1;
311         if (it != binaryMap.end()) {
312                 //element found;
313                 value = it->second;
314                 ret = 0;
315                 KeepAlive = value.manifest.properties.general.instanceKeepAlive;
316         }
317         pthread_rwlock_unlock(&binaryMapLock);
318         return ret;
319 }
320
321 /**
322  * Check if TA is multi instance type
323  * @param[in] uuid UUID of TA
324  * @param[out] isMultipleSession returns value from this parameter.
325  * @return -1 if uuid is not found else on success 0
326  */
327 int TABinaryManager::isMultipleSession(string uuid, bool &MultipleSession) {
328         pthread_rwlock_wrlock(&binaryMapLock);
329         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
330         StructBinaryInfo value;
331         int ret = -1;
332         if (it != binaryMap.end()) {
333                 //element found;
334                 value = it->second;
335                 ret = 0;
336                 MultipleSession = value.manifest.properties.general.multiSession;
337         }
338         pthread_rwlock_unlock(&binaryMapLock);
339         return ret;
340 }
341
342 /**
343  * Get TA executable image path
344  * @param uuid UUID of TA
345  * @return Empty string if UUID doesn't exist, else path to TA
346  */
347 string TABinaryManager::getImagePath(string uuid) {
348         pthread_rwlock_wrlock(&binaryMapLock);
349         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
350         StructBinaryInfo value;
351         string ret = "";
352         if (it != binaryMap.end()) {
353                 //element found;
354                 value = it->second;
355                 ret = value.imagePath;
356         }
357         pthread_rwlock_unlock(&binaryMapLock);
358         return ret;
359 }
360
361 /**
362  * Constant to TA Manifest object
363  * @param uuid UUID of TA
364  * @return NULL pointer if
365  */
366 const TAManifest* TABinaryManager::getManifest(string uuid) {
367         pthread_rwlock_wrlock(&binaryMapLock);
368         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
369         TAManifest *returnValue = NULL;
370         if (it != binaryMap.end()) {
371                 //element found;
372                 returnValue = &(it->second.manifest);
373         }
374         pthread_rwlock_unlock(&binaryMapLock);
375         return returnValue;
376 }
377
378 /**
379  * Constant to port string
380  * @param uuid UUID of TA
381  * @return NULL pointer if
382  */
383 string TABinaryManager::getPort(string uuid) {
384         pthread_rwlock_wrlock(&binaryMapLock);
385         map<string, StructBinaryInfo>::iterator it = binaryMap.find(uuid);
386         string returnValue = "";
387         if (it != binaryMap.end()) {
388                 returnValue = it->second.port;
389         }
390         pthread_rwlock_unlock(&binaryMapLock);
391         return returnValue;
392 }
393
394 /**
395  * Converts UUID from TEEC_UUID to a string
396  * @return string of TEEC_UUID
397  */
398 string TABinaryManager::getUUIDAsString(TEEC_UUID uuid) {
399         // E.g. returns a string in the format 79B7778897894a7aA2BEB60155EEF5F3
400         std::stringstream strStream;
401         strStream << IntToHex(uuid.timeLow);
402         strStream << IntToHex(uuid.timeMid);
403         strStream << IntToHex(uuid.timeHiAndVersion);
404         for (int i = 0; i < 8; i++) {
405                 strStream << IntToHex((short)uuid.clockSeqAndNode[i], 2);
406         }
407         return strStream.str();
408 }
409
410
411 TABinaryManager::~TABinaryManager() {
412         pthread_rwlock_destroy(&binaryMapLock);
413         pthread_mutex_destroy(&taLock);
414         delete instance;
415 }