1 /** Mobicore Driver Registry.
2  *
3  * Implements the MobiCore driver registry which maintains trustlets.
4  *
5  * @file
6  * @ingroup MCD_MCDIMPL_DAEMON_REG
7  * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote
18  *    products derived from this software without specific prior
19  *    written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "MobiCoreRegistry.h"
35 #include <stdlib.h>
36 #include <dirent.h>
37 #include <stdio.h>
38 #include <sys/stat.h>
39 #include <assert.h>
40 #include <string>
41 #include <cstring>
42 #include <cstddef>
43 #include "mcLoadFormat.h"
44 #include "mcSpid.h"
45 #include "mcVersionHelper.h"
46 
47 #include "log.h"
48 
49 MC_CHECK_DATA_OBJECT_VERSION(MCLF, 2, 0);
50 MC_CHECK_DATA_OBJECT_VERSION(CONTAINER, 2, 0);
51 
52 // Asserts expression at compile-time (to be used within a function body).
53 #define ASSERT_STATIC(e) do { enum { assert_static__ = 1 / (e) }; } while (0)
54 
55 using namespace std;
56 
57 static const string MC_REGISTRY_DEFAULT_PATH = "/data/app/mcRegistry";
58 static const string AUTH_TOKEN_FILE_NAME = "00000000.authtokcont";
59 static const string ROOT_FILE_NAME = "00000000.rootcont";
60 static const string SP_CONT_FILE_EXT = ".spcont";
61 static const string TL_CONT_FILE_EXT = ".tlcont";
62 static const string TL_BIN_FILE_EXT = ".tlbin";
63 static const string DATA_CONT_FILE_EXT = ".datacont";
64 
65 static const string ENV_MC_REGISTRY_PATH = "MC_REGISTRY_PATH";
66 static const string ENV_MC_REGISTRY_FALLBACK_PATH = "MC_REGISTRY_FALLBACK_PATH";
67 static const string ENV_MC_AUTH_TOKEN_PATH = "MC_AUTH_TOKEN_PATH";
68 
69 static const string getRegistryPath();
70 static const string getAuthTokenFilePath();
71 static const string getRootContFilePath();
72 static const string getSpDataPath(mcSpid_t spid);
73 static const string getSpContFilePath(mcSpid_t spid);
74 static const string getTlContFilePath(const mcUuid_t *uuid);
75 static const string getTlDataPath(const mcUuid_t *uuid);
76 static const string getTlDataFilePath(const mcUuid_t *uuid, mcPid_t pid);
77 static const string getTlBinFilePath(const mcUuid_t *uuid);
78 
79 static const string uint32ToString(mcSpid_t spid);
80 static const string byteArrayToString(const void *bytes, size_t elems);
81 static bool doesDirExist(const char *path);
82 
83 //------------------------------------------------------------------------------
mcRegistryStoreAuthToken(const mcSoAuthTokenCont_t * so)84 mcResult_t mcRegistryStoreAuthToken(
85     const mcSoAuthTokenCont_t *so
86 )
87 {
88     if (NULL == so) {
89         LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
90         return MC_DRV_ERR_INVALID_PARAMETER;
91     }
92     if (CONT_TYPE_SOC != so->coSoc.type) {
93         LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
94         return MC_DRV_ERR_INVALID_PARAMETER;
95     }
96     const string &authTokenFilePath = getAuthTokenFilePath();
97     LOG_I("store AuthToken: %s", authTokenFilePath.c_str());
98 
99     FILE *fs = fopen(authTokenFilePath.c_str(), "wb");
100     if (!fs) {
101         LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
102         return MC_DRV_ERR_INVALID_DEVICE_FILE;
103     }
104     fseek(fs, 0, SEEK_SET);
105     fwrite((char *)so, 1, sizeof(mcSoAuthTokenCont_t), fs);
106     fflush(fs);
107     fclose(fs);
108 
109     return MC_DRV_OK;
110 }
111 
112 
113 //------------------------------------------------------------------------------
mcRegistryReadAuthToken(mcSoAuthTokenCont_t * so)114 mcResult_t mcRegistryReadAuthToken(
115     mcSoAuthTokenCont_t *so
116 )
117 {
118     if (NULL == so) {
119         LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
120         return MC_DRV_ERR_INVALID_PARAMETER;
121     }
122     const string &authTokenFilePath = getAuthTokenFilePath();
123     LOG_I("read AuthToken: %s", authTokenFilePath.c_str());
124 
125     FILE *fs = fopen(authTokenFilePath.c_str(), "rb");
126     if (!fs) {
127         LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
128         return MC_DRV_ERR_INVALID_DEVICE_FILE;
129     }
130     fseek(fs, 0, SEEK_END);
131     int32_t filesize = ftell(fs);
132     if (sizeof(mcSoAuthTokenCont_t) != filesize) {
133         fclose(fs);
134         LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
135         return MC_DRV_ERR_OUT_OF_RESOURCES;
136     }
137     fseek(fs, 0, SEEK_SET);
138     fread((char *)so, 1, sizeof(mcSoAuthTokenCont_t), fs);
139     fclose(fs);
140 
141     return MC_DRV_OK;
142 }
143 
144 //------------------------------------------------------------------------------
mcRegistryDeleteAuthToken(void)145 mcResult_t mcRegistryDeleteAuthToken(
146     void
147 )
148 {
149     remove(getAuthTokenFilePath().c_str());
150     // @TODO: is return to check ?
151     return MC_DRV_OK;
152 }
153 
154 
155 //------------------------------------------------------------------------------
mcRegistryStoreRoot(const mcSoRootCont_t * so)156 mcResult_t mcRegistryStoreRoot(
157     const mcSoRootCont_t *so
158 )
159 {
160     if (NULL == so) {
161         LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
162         return MC_DRV_ERR_INVALID_PARAMETER;
163     }
164     if (CONT_TYPE_ROOT != so->cont.type) {
165         LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
166         return MC_DRV_ERR_INVALID_PARAMETER;
167     }
168     const string &rootContFilePath = getRootContFilePath();
169     LOG_I("store Root: %s", rootContFilePath.c_str());
170 
171     FILE *fs = fopen(rootContFilePath.c_str(), "wb");
172     if (!fs) {
173         LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
174         return MC_DRV_ERR_INVALID_DEVICE_FILE;
175     }
176     fseek(fs, 0, SEEK_SET);
177     fwrite((char *)so, 1, sizeof(mcSoRootCont_t), fs);
178     fflush(fs);
179     fclose(fs);
180 
181     return MC_DRV_OK;
182 }
183 
184 
185 //------------------------------------------------------------------------------
mcRegistryReadRoot(mcSoRootCont_t * so)186 mcResult_t mcRegistryReadRoot(
187     mcSoRootCont_t *so
188 )
189 {
190     if (NULL == so) {
191         LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
192         return MC_DRV_ERR_INVALID_PARAMETER;
193     }
194     const string &rootContFilePath = getRootContFilePath();
195     LOG_I("read Root: %s", rootContFilePath.c_str());
196 
197     FILE *fs = fopen(rootContFilePath.c_str(), "rb");
198     if (!fs) {
199         LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
200         return MC_DRV_ERR_INVALID_DEVICE_FILE;
201     }
202     fseek(fs, 0, SEEK_END);
203     int32_t filesize = ftell(fs);
204     if (sizeof(mcSoRootCont_t) != filesize) {
205         fclose(fs);
206         LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
207         return MC_DRV_ERR_OUT_OF_RESOURCES;
208     }
209     fseek(fs, 0, SEEK_SET);
210     fread((char *)so, 1, sizeof(mcSoRootCont_t), fs);
211     fclose(fs);
212 
213     return MC_DRV_OK;
214 }
215 
216 
217 //------------------------------------------------------------------------------
mcRegistryStoreSp(mcSpid_t spid,const mcSoSpCont_t * so)218 mcResult_t mcRegistryStoreSp(
219     mcSpid_t            spid,
220     const mcSoSpCont_t  *so
221 )
222 {
223     if ((0 == spid) || (NULL == so)) {
224         LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
225         return MC_DRV_ERR_INVALID_PARAMETER;
226     }
227     if (CONT_TYPE_SP != so->cont.type) {
228         LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
229         return MC_DRV_ERR_INVALID_PARAMETER;
230     }
231     const string &spContFilePath = getSpContFilePath(spid);
232     LOG_I("store SP: %s", spContFilePath.c_str());
233 
234     FILE *fs = fopen(spContFilePath.c_str(), "wb");
235     if (!fs) {
236         LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
237         return MC_DRV_ERR_INVALID_DEVICE_FILE;
238     }
239     fseek(fs, 0, SEEK_SET);
240     fwrite((char *)so, 1, sizeof(mcSoSpCont_t), fs);
241     fflush(fs);
242     fclose(fs);
243 
244     return MC_DRV_OK;
245 }
246 
247 
248 //------------------------------------------------------------------------------
mcRegistryReadSp(mcSpid_t spid,mcSoSpCont_t * so)249 mcResult_t mcRegistryReadSp(
250     mcSpid_t        spid,
251     mcSoSpCont_t    *so
252 )
253 {
254     if ((0 == spid) || (NULL == so)) {
255         LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
256         return MC_DRV_ERR_INVALID_PARAMETER;
257     }
258     const string &spContFilePath = getSpContFilePath(spid);
259     LOG_I("read SP: %s", spContFilePath.c_str());
260 
261     FILE *fs = fopen(spContFilePath.c_str(), "rb");
262     if (!fs) {
263         LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
264         return MC_DRV_ERR_INVALID_DEVICE_FILE;
265     }
266     fseek(fs, 0, SEEK_END);
267     int32_t filesize = ftell(fs);
268     if (sizeof(mcSoSpCont_t) != filesize) {
269         fclose(fs);
270         LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
271         return MC_DRV_ERR_OUT_OF_RESOURCES;
272     }
273     fseek(fs, 0, SEEK_SET);
274     fread((char *)so, 1, sizeof(mcSoSpCont_t), fs);
275     fclose(fs);
276 
277     return MC_DRV_OK;
278 }
279 
280 
281 //------------------------------------------------------------------------------
mcRegistryStoreTrustletCon(const mcUuid_t * uuid,const mcSoTltCont_t * so)282 mcResult_t mcRegistryStoreTrustletCon(
283     const mcUuid_t      *uuid,
284     const mcSoTltCont_t *so
285 )
286 {
287     if ((NULL == uuid) || (NULL == so)) {
288         LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
289         return MC_DRV_ERR_INVALID_PARAMETER;
290     }
291     if (CONT_TYPE_TLCON != so->cont.type) {
292         LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
293         return MC_DRV_ERR_INVALID_PARAMETER;
294     }
295     const string &tlContFilePath = getTlContFilePath(uuid);
296     LOG_I("store TLc: %s", tlContFilePath.c_str());
297 
298     FILE *fs = fopen(tlContFilePath.c_str(), "wb");
299     if (!fs) {
300         LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
301         return MC_DRV_ERR_INVALID_DEVICE_FILE;
302     }
303     fseek(fs, 0, SEEK_SET);
304     fwrite((char *)so, 1, sizeof(mcSoTltCont_t), fs);
305     fflush(fs);
306     fclose(fs);
307 
308     return MC_DRV_OK;
309 }
310 
311 
312 //------------------------------------------------------------------------------
mcRegistryReadTrustletCon(const mcUuid_t * uuid,mcSoTltCont_t * so)313 mcResult_t mcRegistryReadTrustletCon(
314     const mcUuid_t  *uuid,
315     mcSoTltCont_t   *so
316 )
317 {
318     if ((NULL == uuid) || (NULL == so)) {
319         LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
320         return MC_DRV_ERR_INVALID_PARAMETER;
321     }
322     const string &tlContFilePath = getTlContFilePath(uuid);
323     LOG_I("read TLc: %s", tlContFilePath.c_str());
324 
325     FILE *fs = fopen(tlContFilePath.c_str(), "rb");
326     if (!fs) {
327         LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
328         return MC_DRV_ERR_INVALID_DEVICE_FILE;
329     }
330     fseek(fs, 0, SEEK_END);
331     int32_t filesize = ftell(fs);
332     if (sizeof(mcSoTltCont_t) != filesize) {
333         fclose(fs);
334         LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d. Size=%i, expected=%i", MC_DRV_ERR_OUT_OF_RESOURCES, filesize, sizeof(mcSoTltCont_t));
335         return MC_DRV_ERR_OUT_OF_RESOURCES;
336     }
337     fseek(fs, 0, SEEK_SET);
338     fread((char *)so, 1, sizeof(mcSoTltCont_t), fs);
339     fclose(fs);
340 
341     return MC_DRV_OK;
342 }
343 
344 
345 //------------------------------------------------------------------------------
mcRegistryStoreData(const mcSoDataCont_t * so)346 mcResult_t mcRegistryStoreData(
347     const mcSoDataCont_t *so
348 )
349 {
350     if (NULL == so) {
351         LOG_E("mcRegistry store So.Data failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
352         return MC_DRV_ERR_INVALID_PARAMETER;
353     }
354     string pathname, filename;
355 
356     switch (so->cont.type) {
357     case CONT_TYPE_SPDATA:
358         LOG_E("SPDATA not supported");
359         return MC_DRV_ERR_INVALID_PARAMETER;
360         break;
361     case CONT_TYPE_TLDATA:
362         pathname = getTlDataPath(&so->cont.uuid);
363         filename = getTlDataFilePath(&so->cont.uuid, so->cont.pid);
364         break;
365     default:
366         LOG_E("mcRegistry store So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
367         return MC_DRV_ERR_INVALID_PARAMETER;
368     }
369     mkdir(pathname.c_str(), 0777);
370 
371     LOG_I("store DT: %s", filename.c_str());
372 
373     FILE *fs = fopen(filename.c_str(), "wb");
374     if (!fs) {
375         LOG_E("mcRegistry store So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
376         return MC_DRV_ERR_INVALID_DEVICE_FILE;
377     }
378     fseek(fs, 0, SEEK_SET);
379     fwrite((char *)so, 1, MC_SO_SIZE(so->soHeader.plainLen, so->soHeader.encryptedLen), fs);
380     fflush(fs);
381     fclose(fs);
382 
383     return MC_DRV_OK;
384 }
385 
386 
387 //------------------------------------------------------------------------------
mcRegistryReadData(uint32_t context,const mcCid_t * cid,mcPid_t pid,mcSoDataCont_t * so,uint32_t maxLen)388 mcResult_t mcRegistryReadData(
389     uint32_t        context,
390     const mcCid_t   *cid,
391     mcPid_t         pid,
392     mcSoDataCont_t  *so,
393     uint32_t        maxLen
394 )
395 {
396     if ((NULL == cid) || (NULL == so)) {
397         LOG_E("mcRegistry read So.Data failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
398         return MC_DRV_ERR_INVALID_PARAMETER;
399     }
400     string filename;
401     switch (context) {
402     case 0:
403         LOG_E("SPDATA not supported");
404         return MC_DRV_ERR_INVALID_PARAMETER;
405         break;
406     case 1:
407         filename = getTlDataFilePath(&so->cont.uuid, so->cont.pid);
408         break;
409     default:
410         LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
411         return MC_DRV_ERR_INVALID_PARAMETER;
412     }
413     LOG_I("read DT: %s", filename.c_str());
414 
415     FILE *fs = fopen(filename.c_str(), "rb");
416     if (!fs) {
417         LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
418         return MC_DRV_ERR_INVALID_DEVICE_FILE;
419     }
420     fseek(fs, 0, SEEK_END);
421     uint32_t filesize = ftell(fs);
422     if (maxLen < filesize) {
423         fclose(fs);
424         LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
425         return MC_DRV_ERR_OUT_OF_RESOURCES;
426     }
427     fseek(fs, 0, SEEK_SET);
428     char *p = (char *) so;
429     fread(p, 1, sizeof(mcSoHeader_t), fs);
430     p += sizeof(mcSoHeader_t);
431     fread(p, 1, MC_SO_SIZE(so->soHeader.plainLen, so->soHeader.encryptedLen) - sizeof(mcSoHeader_t), fs);
432     fclose(fs);
433 
434     return MC_DRV_OK;
435 }
436 
437 
438 //------------------------------------------------------------------------------
mcRegistryCleanupTrustlet(const mcUuid_t * uuid)439 mcResult_t mcRegistryCleanupTrustlet(
440     const mcUuid_t *uuid
441 )
442 {
443     DIR            *dp;
444     struct dirent  *de;
445     int             e;
446 
447     if (NULL == uuid) {
448         LOG_E("mcRegistry cleanupTrustlet(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
449         return MC_DRV_ERR_INVALID_PARAMETER;
450     }
451     string pathname = getTlDataPath(uuid);
452     if (NULL != (dp = opendir(pathname.c_str()))) {
453         while (NULL != (de = readdir(dp))) {
454             if (de->d_name[0] != '.') {
455                 string dname = pathname + "/" + string (de->d_name);
456                 LOG_I("delete DT: %s", dname.c_str());
457                 if (0 != (e = remove(dname.c_str()))) {
458                     LOG_E("remove UUID-data %s failed! error: %d", dname.c_str(), e);
459                     return MC_DRV_ERR_UNKNOWN;
460                 }
461             }
462         }
463         LOG_I("delete dir: %s", pathname.c_str());
464         if (0 != (e = rmdir(pathname.c_str()))) {
465             LOG_E("remove UUID-dir failed! errno: %d", e);
466             return MC_DRV_ERR_UNKNOWN;
467         }
468     }
469     string tlBinFilePath = getTlBinFilePath(uuid);
470     LOG_I("delete Tlb: %s", tlBinFilePath.c_str());
471     if (0 != (e = remove(tlBinFilePath.c_str()))) {
472         LOG_E("remove Tlb failed! errno: %d", e);
473 //        return MC_DRV_ERR_UNKNOWN;     // a trustlet-binary must not be present ! (registered but not usable)
474     }
475     string tlContFilePath = getTlContFilePath(uuid);
476     LOG_I("delete Tlc: %s", tlContFilePath.c_str());
477     if (0 != (e = remove(tlContFilePath.c_str()))) {
478         LOG_E("remove Tlc failed! errno: %d", e);
479         return MC_DRV_ERR_UNKNOWN;
480     }
481     return MC_DRV_OK;
482 }
483 
484 
485 //------------------------------------------------------------------------------
mcRegistryCleanupSp(mcSpid_t spid)486 mcResult_t mcRegistryCleanupSp(
487     mcSpid_t spid
488 )
489 {
490     mcResult_t      ret;
491     mcSoSpCont_t    data;
492     uint32_t        i;
493     DIR            *dp;
494     struct dirent  *de;
495     int             e;
496 
497     if (0 == spid) {
498         LOG_E("mcRegistry cleanupSP(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
499         return MC_DRV_ERR_INVALID_PARAMETER;
500     }
501     ret = mcRegistryReadSp(spid, &data);
502     if (MC_DRV_OK != ret) {
503         LOG_E("read SP->UUID aborted! Return code: %d", ret);
504         return ret;
505     }
506     for (i = 0; (i < MC_CONT_CHILDREN_COUNT) && (ret == MC_DRV_OK); i++) {
507         if (0 != strncmp((const char *) & (data.cont.children[i]), (const char *)&MC_UUID_FREE, sizeof(mcUuid_t))) {
508             ret = mcRegistryCleanupTrustlet(&(data.cont.children[i]));
509         }
510     }
511     if (MC_DRV_OK != ret) {
512         LOG_E("delete SP->UUID failed! Return code: %d", ret);
513         return ret;
514     }
515     string pathname = getSpDataPath(spid);
516 
517     if (NULL != (dp = opendir(pathname.c_str()))) {
518         while (NULL != (de = readdir(dp))) {
519             if (de->d_name[0] != '.') {
520                 string dname = pathname + "/" + string (de->d_name);
521                 LOG_I("delete DT: %s", dname.c_str());
522                 if (0 != (e = remove(dname.c_str()))) {
523                     LOG_E("remove SPID-data %s failed! error: %d", dname.c_str(), e);
524                     return MC_DRV_ERR_UNKNOWN;
525                 }
526             }
527         }
528         LOG_I("delete dir: %s", pathname.c_str());
529         if (0 != (e = rmdir(pathname.c_str()))) {
530             LOG_E("remove SPID-dir failed! error: %d", e);
531             return MC_DRV_ERR_UNKNOWN;
532         }
533     }
534     string spContFilePath = getSpContFilePath(spid);
535     LOG_I("delete Sp: %s", spContFilePath.c_str());
536     if (0 != (e = remove(spContFilePath.c_str()))) {
537         LOG_E("remove SP failed! error: %d", e);
538         return MC_DRV_ERR_UNKNOWN;
539     }
540     return MC_DRV_OK;
541 }
542 
543 
544 //------------------------------------------------------------------------------
mcRegistryCleanupRoot(void)545 mcResult_t mcRegistryCleanupRoot(void)
546 {
547     mcResult_t ret;
548     mcSoRootCont_t data;
549     uint32_t i;
550     int e;
551 
552     ret = mcRegistryReadRoot(&data);
553     if (MC_DRV_OK != ret) {
554         LOG_E("read Root aborted! Return code: %d", ret);
555         return ret;
556     }
557     for (i = 0; (i < MC_CONT_CHILDREN_COUNT) && (ret == MC_DRV_OK); i++) {
558         mcSpid_t spid = data.cont.children[i];
559         if (spid != MC_SPID_FREE) {
560             ret = mcRegistryCleanupSp(spid);
561             if (MC_DRV_OK != ret) {
562                 LOG_E("Cleanup SP failed! Return code: %d", ret);
563                 return ret;
564             }
565         }
566     }
567 
568     string rootContFilePath = getRootContFilePath();
569     LOG_I("Delete root: %s", rootContFilePath.c_str());
570     if (0 != (e = remove(rootContFilePath.c_str()))) {
571         LOG_E("Delete root failed! error: %d", e);
572         return MC_DRV_ERR_UNKNOWN;
573     }
574     return MC_DRV_OK;
575 }
576 
577 
578 //------------------------------------------------------------------------------
mcRegistryGetServiceBlob(const mcUuid_t * uuid)579 regObject_t *mcRegistryGetServiceBlob(
580     const mcUuid_t *uuid
581 )
582 {
583     regObject_t *regobj = NULL;
584 
585     // Ensure that a UUID is provided.
586     if (NULL == uuid) {
587         LOG_E("No UUID given");
588         return NULL;
589     }
590 
591     // Open service blob file.
592     string tlBinFilePath = getTlBinFilePath(uuid);
593     LOG_I(" Loading %s", tlBinFilePath.c_str());
594 
595     FILE *fs = fopen(tlBinFilePath.c_str(), "rb");
596     if (!fs) {
597         LOG_E("Cannot open %s", tlBinFilePath.c_str());
598         return NULL;
599     }
600 
601     // Determine and check service blob size.
602     fseek(fs, 0, SEEK_END);
603     int32_t tlSize = ftell(fs);
604     fseek(fs, 0, SEEK_SET);
605     if (MAX_TL_SIZE < tlSize) {
606         LOG_E("mcRegistryGetServiceBlob() failed: service blob too big: %d", tlSize);
607         return NULL;
608     }
609 
610     // Check TL magic value.
611     fseek(fs, offsetof(mclfIntro_t, magic), SEEK_SET);
612     uint32_t magic;
613     fread((char *)&magic, 1, sizeof(magic), fs);
614     if (magic != MC_SERVICE_HEADER_MAGIC_BE) {
615         fclose(fs);
616         LOG_E("mcRegistryGetServiceBlob() failed: wrong header magic value: %d", magic);
617         return NULL;
618     }
619 
620     // Check header version.
621     fseek(fs, offsetof(mclfIntro_t, version), SEEK_SET);
622     uint32_t version;
623     fread((char *)&version, 1, sizeof(version), fs);
624 
625     char *msg;
626     if (!checkVersionOkDataObjectMCLF(version, &msg)) {
627         fclose(fs);
628         LOG_E("%s", msg);
629         return NULL;
630     }
631 
632     // Get service type.
633     fseek(fs, offsetof(mclfHeaderV2_t, serviceType), SEEK_SET);
634     serviceType_t serviceType;
635     fread((char *)&serviceType, 1, sizeof(serviceType), fs);
636     fseek(fs, 0, SEEK_SET);
637 
638 #ifndef NDEBUG
639     {
640         const char *service_types[] = {
641             "illegal", "Driver", "Trustlet", "System Trustlet"
642         };
643         int serviceType_safe = serviceType > SERVICE_TYPE_SYSTEM_TRUSTLET ? SERVICE_TYPE_ILLEGAL : serviceType;
644         LOG_I(" Service is a %s (service type %d)", service_types[serviceType_safe], serviceType);
645     }
646 #endif
647 
648     // If loadable driver or system trustlet.
649     if (SERVICE_TYPE_DRIVER == serviceType || SERVICE_TYPE_SYSTEM_TRUSTLET == serviceType) {
650         // Take trustlet blob 'as is'.
651         if (NULL == (regobj = (regObject_t *) (malloc(sizeof(regObject_t) + tlSize)))) {
652             fclose(fs);
653             LOG_E("mcRegistryGetServiceBlob() failed: Out of memory");
654             return NULL;
655         }
656         regobj->len = tlSize;
657         fread((char *)regobj->value, 1, tlSize, fs);
658         fclose(fs);
659         // If user trustlet.
660     } else if (SERVICE_TYPE_SP_TRUSTLET == serviceType) {
661         // Take trustlet blob and append root, sp, and tl container.
662         size_t regObjValueSize = tlSize + sizeof(mcSoContainerPath_t);
663 
664         // Prepare registry object.
665         if (NULL == (regobj = (regObject_t *) malloc(sizeof(regObject_t) + regObjValueSize))) {
666             fclose(fs);
667             LOG_E("mcRegistryGetServiceBlob() failed: Out of memory");
668             return NULL;
669         }
670         regobj->len = regObjValueSize;
671 
672         // Read and fill in trustlet blob at beginning.
673         fread((char *)regobj->value, 1, tlSize, fs);
674         fclose(fs);
675 
676         // Goto end of allocated space and fill in tl container, sp container,
677         // and root container from back to front. Final registry object value
678         // looks like this:
679         //
680         //    +---------------------------+-----------+---------+---------+
681         //    | TL-Header TL-Code TL-Data | Root Cont | SP Cont | TL Cont |
682         //    +---------------------------+-----------+-------------------+
683         //    /------ Trustlet BLOB ------/
684         //
685         //    /------------------ regobj->header.len ---------------------/
686 
687         uint8_t *p = regobj->value + regobj->len;
688         mcResult_t ret;
689         do {
690             char *msg;
691 
692             // Fill in TL container.
693             p -= sizeof(mcSoTltCont_t);
694             mcSoTltCont_t *soTlt = (mcSoTltCont_t *)p;
695             if (MC_DRV_OK != (ret = mcRegistryReadTrustletCon(uuid, soTlt))) {
696                 break;
697             }
698             mcTltCont_t *tltCont = &soTlt->cont;
699             if (!checkVersionOkDataObjectCONTAINER(tltCont->version, &msg)) {
700                 LOG_E("Tlt container %s", msg);
701                 ret = MC_DRV_ERR_CONTAINER_VERSION;
702                 break;
703             }
704 
705             // Fill in SP container.
706             mcSpid_t spid = tltCont->parent;
707             p -= sizeof(mcSoSpCont_t);
708             mcSoSpCont_t *soSp = (mcSoSpCont_t *)p;
709             if (MC_DRV_OK != (ret = mcRegistryReadSp(spid, soSp))) {
710                 break;
711             }
712             mcSpCont_t *spCont = &soSp->cont;
713             if (!checkVersionOkDataObjectCONTAINER(spCont->version, &msg)) {
714                 LOG_E("SP container %s", msg);
715                 ret = MC_DRV_ERR_CONTAINER_VERSION;
716                 break;
717             }
718 
719             // Fill in root container.
720             p -= sizeof(mcSoRootCont_t);
721             mcSoRootCont_t *soRoot = (mcSoRootCont_t *)p;
722             if (MC_DRV_OK != (ret = mcRegistryReadRoot(soRoot))) {
723                 break;
724             }
725             mcRootCont_t *rootCont = &soRoot->cont;
726             if (!checkVersionOkDataObjectCONTAINER(rootCont->version, &msg)) {
727                 LOG_E("Root container %s", msg);
728                 ret = MC_DRV_ERR_CONTAINER_VERSION;
729                 break;
730             }
731 
732             // Ensure order of elements in registry object value.
733             assert(p - tlSize - sizeof(regObject_t) == (uint8_t *)regobj);
734         } while (false);
735 
736         if (MC_DRV_OK != ret) {
737             LOG_E("mcRegistryGetServiceBlob() failed: Error code: %d", ret);
738             free(regobj);
739             return NULL;
740         }
741         // Any other service type.
742     } else {
743         fclose(fs);
744         LOG_E("mcRegistryGetServiceBlob() failed: Unsupported service type %u", serviceType);
745     }
746 
747     return regobj;
748 }
749 
750 //------------------------------------------------------------------------------
mcRegistryGetDriverBlob(const char * driverFilename)751 regObject_t *mcRegistryGetDriverBlob(
752     const char *driverFilename
753 )
754 {
755     regObject_t *regobj = NULL;
756 
757     // Open service blob file.
758     FILE *fs = fopen(driverFilename, "rb");
759     if (!fs) {
760         LOG_E("mcRegistryGetDriverBlob() failed: cannot open %s", driverFilename);
761         return NULL;
762     }
763 
764     // Determine and check service blob size.
765     fseek(fs, 0, SEEK_END);
766     int32_t tlSize = ftell(fs);
767     fseek(fs, 0, SEEK_SET);
768     if (MAX_TL_SIZE < tlSize) {
769         LOG_E("mcRegistryGetDriverBlob() failed: service blob too big: %d", tlSize);
770         fclose(fs);
771         return NULL;
772     }
773 
774     // Check TL magic value.
775     fseek(fs, offsetof(mclfIntro_t, magic), SEEK_SET);
776     uint32_t magic;
777     fread((char *)&magic, 1, sizeof(magic), fs);
778     if (magic != MC_SERVICE_HEADER_MAGIC_BE) {
779         LOG_E("mcRegistryGetDriverBlob() failed: wrong header magic value: %d", magic);
780         fclose(fs);
781         return NULL;
782     }
783 
784     // Check header version.
785     fseek(fs, offsetof(mclfIntro_t, version), SEEK_SET);
786     uint32_t version;
787     fread((char *)&version, 1, sizeof(version), fs);
788 
789     char *msg;
790     if (!checkVersionOkDataObjectMCLF(version, &msg)) {
791         LOG_E("%s", msg);
792         fclose(fs);
793         return NULL;
794     }
795 
796     // Get service type.
797     fseek(fs, offsetof(mclfHeaderV2_t, serviceType), SEEK_SET);
798     serviceType_t serviceType;
799     fread((char *)&serviceType, 1, sizeof(serviceType), fs);
800     fseek(fs, 0, SEEK_SET);
801 
802     LOG_I("mcRegistryGetDriverBlob() Service is of type: %d", serviceType);
803 
804     // If loadable driver or system trustlet.
805     if (SERVICE_TYPE_DRIVER == serviceType) {
806         // Take trustlet blob 'as is'.
807         if (NULL == (regobj = (regObject_t *) (malloc(sizeof(regObject_t) + tlSize)))) {
808             LOG_E("mcRegistryGetDriverBlob() failed: Out of memory");
809             fclose(fs);
810             return NULL;
811         }
812         regobj->len = tlSize;
813         fread((char *)regobj->value, 1, tlSize, fs);
814         // Otherwise we are not interested
815     } else {
816         LOG_E("mcRegistryGetServiceBlob() failed: Unsupported service type %u", serviceType);
817     }
818 
819     fclose(fs);
820 
821     return regobj;
822 }
823 
824 //------------------------------------------------------------------------------
getRegistryPath()825 static const string getRegistryPath()
826 {
827     const char *path;
828     string registryPath;
829 
830     // First, attempt to use regular registry environment variable.
831     path = getenv(ENV_MC_REGISTRY_PATH.c_str());
832     if (doesDirExist(path)) {
833         LOG_I("getRegistryPath(): Using MC_REGISTRY_PATH %s", path);
834         registryPath = path;
835     } else {
836         // Second, attempt to use fallback registry environment variable.
837         path = getenv(ENV_MC_REGISTRY_FALLBACK_PATH.c_str());
838         if (doesDirExist(path)) {
839             LOG_I("getRegistryPath(): Using MC_REGISTRY_FALLBACK_PATH %s", path);
840             registryPath = path;
841         }
842     }
843 
844     // As a last resort, use the default registry path.
845     if (registryPath.length() == 0) {
846         registryPath = MC_REGISTRY_DEFAULT_PATH;
847         LOG_I(" Using default registry path %s", registryPath.c_str());
848     }
849 
850     assert(registryPath.length() != 0);
851 
852     return registryPath;
853 }
854 
855 //------------------------------------------------------------------------------
getAuthTokenFilePath()856 static const string getAuthTokenFilePath()
857 {
858     const char *path;
859     string authTokenPath;
860 
861     // First, attempt to use regular auth token path environment variable.
862     path = getenv(ENV_MC_AUTH_TOKEN_PATH.c_str());
863     if (doesDirExist(path)) {
864         LOG_I("getAuthTokenFilePath(): Using MC_AUTH_TOKEN_PATH %s", path);
865         authTokenPath = path;
866     } else {
867         authTokenPath = getRegistryPath();
868         LOG_I("getAuthTokenFilePath(): Using path %s", authTokenPath.c_str());
869     }
870 
871     return authTokenPath + "/" + AUTH_TOKEN_FILE_NAME;
872 }
873 
874 //------------------------------------------------------------------------------
getRootContFilePath()875 static const string getRootContFilePath()
876 {
877     return getRegistryPath() + "/" + ROOT_FILE_NAME;
878 }
879 
880 //------------------------------------------------------------------------------
getSpDataPath(mcSpid_t spid)881 static const string getSpDataPath(mcSpid_t spid)
882 {
883     return getRegistryPath() + "/" + uint32ToString(spid);
884 }
885 
886 //------------------------------------------------------------------------------
getSpContFilePath(mcSpid_t spid)887 static const string getSpContFilePath(mcSpid_t spid)
888 {
889     return getRegistryPath() + "/" + uint32ToString(spid) + SP_CONT_FILE_EXT;
890 }
891 
892 //------------------------------------------------------------------------------
getTlContFilePath(const mcUuid_t * uuid)893 static const string getTlContFilePath(const mcUuid_t *uuid)
894 {
895     return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid)) + TL_CONT_FILE_EXT;
896 }
897 
898 //------------------------------------------------------------------------------
getTlDataPath(const mcUuid_t * uuid)899 static const string getTlDataPath(const mcUuid_t *uuid)
900 {
901     return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid));
902 }
903 
904 //------------------------------------------------------------------------------
getTlDataFilePath(const mcUuid_t * uuid,mcPid_t pid)905 static const string getTlDataFilePath(const mcUuid_t *uuid, mcPid_t pid)
906 {
907     return getTlDataPath(uuid) + "/" + uint32ToString(pid.data) + DATA_CONT_FILE_EXT;
908 }
909 
910 //------------------------------------------------------------------------------
getTlBinFilePath(const mcUuid_t * uuid)911 static const string getTlBinFilePath(const mcUuid_t *uuid)
912 {
913     return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid)) + TL_BIN_FILE_EXT;
914 }
915 
916 //------------------------------------------------------------------------------
byteArrayToString(const void * bytes,size_t elems)917 static const string byteArrayToString(const void *bytes, size_t elems)
918 {
919     char hx[elems * 2 + 1];
920 
921     for (size_t i = 0; i < elems; i++) {
922         sprintf(&hx[i * 2], "%02x", ((uint8_t *)bytes)[i]);
923     }
924     return string(hx);
925 }
926 
927 //------------------------------------------------------------------------------
uint32ToString(uint32_t value)928 static const string uint32ToString(
929     uint32_t value
930 )
931 {
932     char hx[sizeof(uint32_t) * 2 + 1];
933     uint32_t i;
934 
935     for (i = 0; i < (2 * sizeof(value)); i++) {
936         hx[i] = (value >> (28 - (i * 4))) & 0x0F;
937         if (hx[i] > 9) {
938             hx[i] = (hx[i] - 9) | 0x40;
939         } else {
940             hx[i] |= 0x30;
941         }
942     }
943     hx[i] = '\0';
944     return string(hx);
945 }
946 
947 //------------------------------------------------------------------------------
doesDirExist(const char * path)948 static bool doesDirExist(const char *path)
949 {
950     struct stat ss;
951     if (path != NULL && stat(path, &ss) == 0 && S_ISDIR(ss.st_mode)) {
952         return true;
953     }
954     return false;
955 }
956 
957 
958 /** @} */
959