Security CBOR conversion
[platform/upstream/iotivity.git] / resource / csdk / security / src / crlresource.c
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "utlist.h"
22 #include "payload_logging.h"
23 #include "psinterface.h"
24 #include "resourcemanager.h"
25 #include "srmresourcestrings.h"
26 #include "srmutility.h"
27 #include "doxmresource.h"
28 #include "ocpayload.h"
29 #ifdef __WITH_X509__
30 #include "crlresource.h"
31 #include "crl.h"
32 #endif /* __WITH_X509__ */
33
34 #define TAG  "SRM-CRL"
35
36 #define SEPARATOR                   ":"
37 #define SEPARATOR_LEN               (1)
38 #define CBOR_CRL_NAME               "\"CRL\""
39 #define CBOR_CRL_NAME_LEN           (5)
40 #define OIC_CBOR_CRL_NAME           "crl"
41 #define OIC_CBOR_CRL_ID             "CRLId"
42 #define OIC_CBOR_CRL_THIS_UPDATE    "ThisUpdate"
43 #define OIC_CBOR_CRL_DATA           "CRLData"
44 #define CRL_DEFAULT_CRL_ID           1
45 #define CRL_DEFAULT_THIS_UPDATE     "150101000000Z"
46 #define CRL_DEFAULT_CRL_DATA        "-"
47
48 static OCResourceHandle     gCrlHandle  = NULL;
49 static OicSecCrl_t         *gCrl        = NULL;
50
51 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
52  * The value of payload size is increased until reaching below max cbor size. */
53 static const uint8_t CBOR_SIZE = 255;
54
55 // Max cbor size payload.
56 static const uint16_t CBOR_MAX_SIZE = 4400;
57
58 // PSTAT Map size - Number of mandatory items
59 static const uint8_t CRL_MAP_SIZE = 3;
60
61 void DeleteCrlBinData(OicSecCrl_t *crl)
62 {
63     if (crl)
64     {
65         //Clean ThisUpdate
66         OICFree(crl->ThisUpdate.data);
67
68         //clean CrlData
69         OICFree(crl->CrlData.data);
70
71         //Clean crl itself
72         OICFree(crl);
73     }
74 }
75
76 OCStackResult CrlToCBORPayload(const OicSecCrl_t *crl, uint8_t **payload, size_t *size)
77 {
78     if (NULL == crl || NULL == payload || NULL != *payload || NULL == size)
79     {
80         return OC_STACK_INVALID_PARAM;
81     }
82
83     size_t cborLen = *size;
84     if (0 == cborLen)
85     {
86         cborLen = CBOR_SIZE;
87     }
88
89     *payload = NULL;
90     *size = 0;
91
92     OCStackResult ret = OC_STACK_ERROR;
93
94     CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
95     CborEncoder crlMap = { {.ptr = NULL }, .end = 0 };
96
97     CborError cborEncoderResult = CborNoError;
98
99     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
100     VERIFY_NON_NULL(TAG, outPayload, ERROR);
101     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
102
103     cborEncoderResult = cbor_encoder_create_map(&encoder, &crlMap, CRL_MAP_SIZE);
104     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
105
106     //CRLId -- Mandatory
107     cborEncoderResult = cbor_encode_text_string(&crlMap, OIC_CBOR_CRL_ID,
108         strlen(OIC_CBOR_CRL_ID));
109     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
110     cborEncoderResult = cbor_encode_int(&crlMap, crl->CrlId);
111     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
112
113     //ThisUpdate -- Mandatory
114     cborEncoderResult = cbor_encode_text_string(&crlMap, OIC_CBOR_CRL_THIS_UPDATE,
115         strlen(OIC_CBOR_CRL_THIS_UPDATE));
116     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
117     cborEncoderResult = cbor_encode_byte_string(&crlMap, crl->ThisUpdate.data,
118                                                 crl->ThisUpdate.len);
119     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
120
121     //CRLData -- Mandatory
122     cborEncoderResult = cbor_encode_text_string(&crlMap, OIC_CBOR_CRL_DATA,
123         strlen(OIC_CBOR_CRL_DATA));
124     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
125     cborEncoderResult = cbor_encode_byte_string(&crlMap, crl->CrlData.data,
126                                                 crl->CrlData.len);
127     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
128
129     cborEncoderResult = cbor_encoder_close_container(&encoder, &crlMap);
130     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, ERROR);
131
132     *size = encoder.ptr - outPayload;
133     *payload = outPayload;
134     ret = OC_STACK_OK;
135
136 exit:
137     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
138     {
139         // reallocate and try again!
140         OICFree(outPayload);
141         // Since the allocated initial memory failed, double the memory.
142         cborLen += encoder.ptr - encoder.end;
143         cborEncoderResult = CborNoError;
144         ret = CrlToCBORPayload(crl, payload, &cborLen);
145     }
146
147     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
148     {
149         OICFree(outPayload);
150         outPayload = NULL;
151         *payload = NULL;
152         *size = 0;
153         ret = OC_STACK_ERROR;
154     }
155
156     return ret;
157 }
158
159 OCStackResult CBORPayloadToCrl(const uint8_t *cborPayload, const size_t size,
160                                OicSecCrl_t **secCrl)
161 {
162     if (NULL == cborPayload || NULL == secCrl || NULL != *secCrl)
163     {
164         return OC_STACK_INVALID_PARAM;
165     }
166
167     OCStackResult ret = OC_STACK_ERROR;
168     *secCrl = NULL;
169
170     CborValue crlCbor = { .parser = NULL };
171     CborParser parser = { .end = NULL };
172     CborError cborFindResult = CborNoError;
173     int cborLen = size;
174     if (0 == size)
175     {
176         cborLen = CBOR_SIZE;
177     }
178     cbor_parser_init(cborPayload, cborLen, 0, &parser, &crlCbor);
179     CborValue crlMap = { .parser = NULL } ;
180     OicSecCrl_t *crl = NULL;
181     char *name = NULL;
182     size_t outLen = 0;
183     cborFindResult = cbor_value_enter_container(&crlCbor, &crlMap);
184     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
185
186     crl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
187     VERIFY_NON_NULL(TAG, crl, ERROR);
188
189     while (cbor_value_is_valid(&crlMap))
190     {
191         size_t len = 0;
192         cborFindResult = cbor_value_dup_text_string(&crlMap, &name, &len, NULL);
193         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
194         cborFindResult = cbor_value_advance(&crlMap);
195         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
196
197         CborType type = cbor_value_get_type(&crlMap);
198
199         if (0 == strcmp(OIC_CBOR_CRL_ID, name))
200         {
201             cborFindResult = cbor_value_get_int(&crlMap, (int *) &crl->CrlId);
202             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
203         }
204         if (0 == strcmp(OIC_CBOR_CRL_THIS_UPDATE, name))
205         {
206             uint8_t *crlByte = NULL;
207             cborFindResult = cbor_value_dup_byte_string(&crlMap, &crlByte, &len, NULL);
208             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
209             crl->ThisUpdate.data = (uint8_t*) OICMalloc(len);
210             VERIFY_NON_NULL(TAG, crl->ThisUpdate.data, ERROR);
211             memcpy(crl->ThisUpdate.data, crlByte, len);
212             crl->ThisUpdate.len = len;
213             OICFree(crlByte);
214         }
215         if (0 == strcmp(OIC_CBOR_CRL_DATA, name))
216         {
217             uint8_t *crlByte = NULL;
218             cborFindResult = cbor_value_dup_byte_string(&crlMap, &crlByte, &len, NULL);
219             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
220             crl->CrlData.data = (uint8_t*) OICMalloc(len);
221             VERIFY_NON_NULL(TAG, crl->CrlData.data, ERROR);
222             memcpy(crl->CrlData.data, crlByte, len);
223             crl->CrlData.len = len;
224             OICFree(crlByte);
225         }
226         if (CborMapType != type && cbor_value_is_valid(&crlMap))
227         {
228             cborFindResult = cbor_value_advance(&crlMap);
229             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, ERROR);
230         }
231         OICFree(name);
232         name = NULL;
233     }
234     // PUT/POST CBOR may not have mandatory values set default values.
235     if (!crl->CrlId)
236     {
237         VERIFY_NON_NULL(TAG, gCrl, ERROR);
238         crl->CrlId = gCrl->CrlId;
239     }
240     if (!crl->ThisUpdate.data)
241     {
242         VERIFY_NON_NULL(TAG, gCrl, ERROR);
243         outLen = gCrl->ThisUpdate.len;
244         crl->ThisUpdate.data = (uint8_t*) OICMalloc(outLen);
245         VERIFY_NON_NULL(TAG, crl->ThisUpdate.data, ERROR);
246         memcpy(crl->ThisUpdate.data, gCrl->ThisUpdate.data, outLen);
247         crl->ThisUpdate.len = outLen;
248     }
249     if (!crl->CrlData.data)
250     {
251         VERIFY_NON_NULL(TAG, gCrl, ERROR);
252         outLen = gCrl->CrlData.len;
253         crl->CrlData.data = (uint8_t*) OICMalloc(outLen);
254         VERIFY_NON_NULL(TAG, crl->CrlData.data, ERROR);
255         memcpy(crl->CrlData.data, gCrl->CrlData.data, outLen);
256         crl->CrlData.len = outLen;
257     }
258
259     *secCrl = crl;
260     ret = OC_STACK_OK;
261 exit:
262     if (CborNoError != cborFindResult)
263     {
264         OIC_LOG (ERROR, TAG, "CBORPayloadToCrl failed");
265         DeleteCrlBinData(crl);
266         crl = NULL;
267         ret = OC_STACK_ERROR;
268     }
269     if (name)
270     {
271         OICFree(name);
272     }
273     return ret;
274 }
275
276 OCStackResult UpdateCRLResource(const OicSecCrl_t *crl)
277 {
278     uint8_t *payload = NULL;
279     size_t size = 0;
280
281     OCStackResult res = CrlToCBORPayload((OicSecCrl_t *) crl, &payload, &size);
282     if (OC_STACK_OK != res)
283     {
284         return res;
285     }
286
287     return UpdateSecureResourceInPS(OIC_CBOR_CRL_NAME, payload, size);
288 }
289
290 static OCEntityHandlerResult HandleCRLPostRequest(const OCEntityHandlerRequest *ehRequest)
291 {
292     OCEntityHandlerResult ehRet = OC_EH_ERROR;
293     OicSecCrl_t *crl = NULL;
294     uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData1;
295
296     if (payload)
297     {
298         OIC_LOG(INFO, TAG, "UpdateSVRDB...");
299         CBORPayloadToCrl(payload, CBOR_SIZE, &crl);
300         VERIFY_NON_NULL(TAG, crl, ERROR);
301
302         gCrl->CrlId = crl->CrlId;
303
304         OICFree(gCrl->ThisUpdate.data);
305         gCrl->ThisUpdate.data = NULL;
306         gCrl->ThisUpdate.data = OICMalloc(crl->ThisUpdate.len);
307         VERIFY_NON_NULL(TAG, gCrl->ThisUpdate.data, ERROR);
308         memcpy(gCrl->ThisUpdate.data, crl->ThisUpdate.data, crl->ThisUpdate.len);
309         gCrl->ThisUpdate.len = crl->ThisUpdate.len;
310
311         OICFree(gCrl->CrlData.data);
312         gCrl->CrlData.data = OICMalloc(crl->CrlData.len);
313         VERIFY_NON_NULL(TAG, gCrl->CrlData.data, ERROR);
314         memcpy(gCrl->CrlData.data, crl->CrlData.data, crl->CrlData.len);
315         gCrl->CrlData.len = crl->CrlData.len;
316
317         size_t size = 0;
318         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_CBOR_CRL_NAME, payload, size))
319         {
320             ehRet = OC_EH_OK;
321         }
322
323         DeleteCrlBinData(crl);
324         OICFree(payload);
325     }
326
327 exit:
328     // Send payload to request originator
329     SendSRMResponse(ehRequest, ehRet, NULL);
330
331     OIC_LOG_V(INFO, TAG, "%s RetVal %d", __func__, ehRet);
332     return ehRet;
333 }
334
335
336 /**
337  * This internal method is the entity handler for CRL resource and
338  * will handle REST request (GET/PUT/POST/DEL) for them.
339  */
340 static OCEntityHandlerResult CRLEntityHandler(OCEntityHandlerFlag flag,
341                                               OCEntityHandlerRequest *ehRequest,
342                                               void *callbackParameter)
343 {
344     OCEntityHandlerResult ehRet = OC_EH_ERROR;
345     (void)callbackParameter;
346
347     if (!ehRequest)
348     {
349         return ehRet;
350     }
351
352     OIC_LOG(INFO, TAG, "Handle CRL resource");
353
354     if (flag & OC_REQUEST_FLAG)
355     {
356         // TODO :  Handle PUT and DEL methods
357         OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
358         switch (ehRequest->method)
359         {
360             case OC_REST_GET:
361                 OIC_LOG (INFO, TAG, "Not implemented request method.");
362                 //ehRet = HandleCRLGetRequest(ehRequest);
363                 break;
364
365             case OC_REST_POST:
366                 ehRet = HandleCRLPostRequest(ehRequest);
367                 break;
368
369             default:
370                 ehRet = OC_EH_ERROR;
371                 SendSRMResponse(ehRequest, ehRet, NULL);
372         }
373     }
374
375     return ehRet;
376 }
377
378 /**
379  * This internal method is used to create '/oic/sec/crl' resource.
380  */
381 static OCStackResult CreateCRLResource()
382 {
383     OCStackResult ret = OCCreateResource(&gCrlHandle,
384                                          OIC_RSRC_TYPE_SEC_CRL,
385                                          OIC_MI_DEF,
386                                          OIC_RSRC_CRL_URI,
387                                          CRLEntityHandler,
388                                          NULL,
389                                          OC_OBSERVABLE);
390
391     if (OC_STACK_OK != ret)
392     {
393         OIC_LOG(FATAL, TAG, "Unable to instantiate CRL resource");
394         DeInitCRLResource();
395     }
396     return ret;
397 }
398
399 /**
400  * Get the default value.
401  * @return defaultCrl for now.
402  */
403 static OicSecCrl_t *GetCrlDefault()
404 {
405     OicSecCrl_t *defaultCrl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
406     if (NULL == defaultCrl)
407     {
408         return NULL;
409     }
410     defaultCrl->CrlId = CRL_DEFAULT_CRL_ID;
411
412     defaultCrl->CrlData.len = strlen(CRL_DEFAULT_CRL_DATA);
413     defaultCrl->CrlData.data = (uint8_t*) OICMalloc(defaultCrl->CrlData.len);
414     if (defaultCrl->CrlData.data)
415     {
416         memcpy(defaultCrl->CrlData.data, CRL_DEFAULT_CRL_DATA, defaultCrl->CrlData.len);
417     }
418     else
419     {
420         defaultCrl->CrlData.len = 0;
421     }
422
423     defaultCrl->ThisUpdate.len = strlen(CRL_DEFAULT_THIS_UPDATE);
424     defaultCrl->ThisUpdate.data = (uint8_t*) OICMalloc(defaultCrl->ThisUpdate.len);
425     if (defaultCrl->ThisUpdate.data)
426     {
427         memcpy(defaultCrl->ThisUpdate.data, CRL_DEFAULT_THIS_UPDATE, defaultCrl->ThisUpdate.len);
428     }
429     else
430     {
431         defaultCrl->ThisUpdate.len = 0;
432     }
433
434     return defaultCrl;
435 }
436
437 /**
438  * Initialize CRL resource by loading data from persistent storage.
439  *
440  * @retval
441  *     OC_STACK_OK    - no errors
442  *     OC_STACK_ERROR - stack process error
443  */
444 OCStackResult InitCRLResource()
445 {
446     OCStackResult ret = OC_STACK_ERROR;
447     // Read Crl resource from PS
448     uint8_t *data = NULL;
449     size_t size = 0;
450     ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
451     // If database read failed
452     if (OC_STACK_OK != ret)
453     {
454         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
455     }
456     if (data)
457     {
458         // Read ACL resource from PS
459         ret = CBORPayloadToCrl(data, size, &gCrl);
460     }
461
462     /*
463      * If SVR database in persistent storage got corrupted or
464      * is not available for some reason, a default CrlResource is created
465      * which allows user to initiate CrlResource provisioning again.
466      */
467     if ((OC_STACK_OK != ret) || !data || !gCrl)
468     {
469         gCrl = GetCrlDefault();
470     }
471
472     ret = CreateCRLResource();
473     OICFree(data);
474     return ret;
475 }
476
477 /**
478  * Perform cleanup for ACL resources.
479  */
480 void DeInitCRLResource()
481 {
482     OCDeleteResource(gCrlHandle);
483     gCrlHandle = NULL;
484     DeleteCrlBinData(gCrl);
485     gCrl = NULL;
486 }
487
488 OicSecCrl_t *GetCRLResource()
489 {
490     OicSecCrl_t *crl =  NULL;
491
492     //Read CRL resource from PS
493     uint8_t *data = NULL;
494     size_t size = 0;
495     OCStackResult ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
496     if (data)
497     {
498         //Convert CBOR CRL into binary format
499         ret = CBORPayloadToCrl(data, size, &crl);
500     }
501     /*
502      * If SVR database in persistent storage got corrupted or
503      * is not available for some reason, a default CrlResource is created
504      * which allows user to initiate CrlResource provisioning again.
505      */
506     if ((OC_STACK_OK != ret) || !data || !crl)
507     {
508         crl = GetCrlDefault();
509     }
510     OICFree(data);
511
512     return crl;
513 }
514
515 uint8_t *GetCrl()
516 {
517     uint8_t *data = NULL;
518     size_t size = 0;
519     OicSecCrl_t *crl = NULL;
520     if (OC_STACK_OK == GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size) && data &&
521         OC_STACK_OK == CBORPayloadToCrl(data, size, &crl))
522     {
523         return crl->CrlData.data;
524     }
525     return NULL;
526 }
527
528 void  GetDerCrl(ByteArray crlArray)
529 {
530     OicSecCrl_t * crlRes = GetCRLResource();
531     if (crlRes && crlRes->CrlData.len <= crlArray.len)
532     {
533         memcpy(crlArray.data, crlRes->CrlData.data, crlRes->CrlData.len);
534         crlArray.len = crlRes->CrlData.len;
535     }
536     else
537     {
538         crlArray.len = 0;
539     }
540     DeleteCrlBinData(crlRes);
541 }