1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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 #include "ocpayloadcbor.h"
30 #include "oic_malloc.h"
31 #include "oic_string.h"
32 #include "crlresource.h"
33 #include "ocpayloadcbor.h"
37 #define TAG "OIC_SRM_CRL"
40 #define SEPARATOR_LEN (1)
41 #define CBOR_CRL_NAME "\"CRL\""
42 #define CBOR_CRL_NAME_LEN (5)
43 #define OIC_CBOR_CRL_NAME "crl"
44 #define OIC_CBOR_CRL_ID "CRLId"
45 #define OIC_CBOR_CRL_THIS_UPDATE "ThisUpdate"
46 #define OIC_CBOR_CRL_DATA "CRLData"
47 #define CRL_DEFAULT_CRL_ID (1)
48 #define CRL_DEFAULT_THIS_UPDATE "150101000000Z"
49 #define CRL_DEFAULT_LAST_UPDATE "20150701000000"
50 #define CRL_DEFAULT_CRL_DATA "-"
51 #define CRL_MAP_SIZE (3)
53 static OCResourceHandle gCrlHandle = NULL;
54 static OicSecCrl_t *gCrl = NULL;
56 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
57 * The value of payload size is increased until reaching below max cbor size. */
58 static const uint16_t CBOR_SIZE = 1024;
60 // Max cbor size payload.
61 static const uint16_t CBOR_MAX_SIZE = 4400;
63 void DeleteCrl(OicSecCrl_t *crl)
68 OICFree(crl->ThisUpdate.data);
71 OICFree(crl->CrlData.data);
78 void printCrl(const OicSecCrl_t *crl)
82 OIC_LOG(INFO, TAG, "Received NULL CRL");
86 OIC_LOG(INFO, TAG, "Crl object contain:");
87 OIC_LOG_V(INFO, TAG, "id = %d", crl->CrlId);
88 OIC_LOG_V(INFO, TAG, "this update = %s", crl->ThisUpdate.data);
90 OIC_LOG(INFO, TAG, "crl:");
91 OIC_LOG_V(INFO, TAG, "encoding = %d", crl->CrlData.encoding);
92 OIC_LOG_V(INFO, TAG, "data (length = %zu):", crl->CrlData.len);
93 OIC_LOG_BUFFER(INFO, TAG, crl->CrlData.data, crl->CrlData.len);
96 static bool copyByteArray(const uint8_t *in, size_t in_len, uint8_t **out, size_t *out_len)
99 uint8_t *tmp = OICMalloc(in_len);
104 memcpy(tmp, in, in_len);
110 static bool copyCrl(const OicSecCrl_t *in, OicSecCrl_t *out)
116 OIC_LOG(ERROR, TAG, "in or out crl is NULL");
120 out->CrlId = in->CrlId;
122 result = copyByteArray(in->ThisUpdate.data, in->ThisUpdate.len, &out->ThisUpdate.data, &out->ThisUpdate.len);
125 OIC_LOG(ERROR, TAG, "Can't allocate memory for ThisUpdate");
129 result = copyByteArray(in->CrlData.data, in->CrlData.len, &out->CrlData.data, &out->CrlData.len);
132 OIC_LOG(ERROR, TAG, "Can't allocate memory for CrlData");
139 static CborError setPubDataType(CborEncoder *out, const char *name, const OicSecKey_t *value)
141 if (!out || !name || !value)
143 OIC_LOG_V(ERROR, TAG, "%s: null input params", __func__);
144 return CborErrorInternalError;
149 const char *encoding = NULL;
150 bool binary_field = false;
155 switch(value->encoding)
157 case OIC_ENCODING_RAW:
159 encoding = OIC_SEC_ENCODING_RAW;
161 case OIC_ENCODING_BASE64:
162 encoding = OIC_SEC_ENCODING_BASE64;
164 case OIC_ENCODING_DER:
166 encoding = OIC_SEC_ENCODING_DER;
168 case OIC_ENCODING_PEM:
169 encoding = OIC_SEC_ENCODING_PEM;
172 OIC_LOG(ERROR, TAG, "Received UNKNOWN encoding, exit!");
173 return CborErrorInternalError;
181 CborError result = CborNoError;
182 result = cbor_encode_text_string(out, name, strlen(name));
183 VERIFY_CBOR_SUCCESS(TAG, result, "Failed Adding name Tag.");
185 result = cbor_encoder_create_map(out, &map, mapSize);
186 VERIFY_CBOR_SUCCESS(TAG, result, "Failed creating name map");
190 result = cbor_encode_text_string(&map, OIC_JSON_ENCODING_NAME,
191 strlen(OIC_JSON_ENCODING_NAME));
192 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to add encoding tag.")
193 result = cbor_encode_text_string(&map, encoding, strlen(encoding));
194 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to add encoding value.");
199 result = cbor_encode_text_string(&map, OIC_JSON_DATA_NAME, strlen(OIC_JSON_DATA_NAME));
200 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to add data tag.");
203 result = cbor_encode_byte_string(&map, value->data, value->len);
207 result = cbor_encode_text_string(&map, (const char *)value->data, value->len);
209 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to add data value.");
212 result = cbor_encoder_close_container(out, &map);
213 VERIFY_CBOR_SUCCESS(TAG, result, "Failed Closing PrivateData Map.");
219 static CborError getPubDataType(CborValue *in, const char *name, OicSecKey_t *value)
221 if (!in || !name || !value)
223 OIC_LOG_V(ERROR, TAG, "%s: null input params", __func__);
224 return CborErrorInternalError;
227 CborError result = CborNoError;
228 char *encoding = NULL;
230 CborValue crlNode = { .parser = NULL };
231 result = cbor_value_map_find_value(in, name, &crlNode);
232 if (CborNoError == result && cbor_value_is_map(&crlNode))
234 CborValue crlMap = { .parser = NULL };
235 result = cbor_value_enter_container(&crlNode, &crlMap);
237 while(cbor_value_is_valid(&crlMap) && cbor_value_is_text_string(&crlMap))
239 char *property = NULL;
241 result = cbor_value_dup_text_string(&crlMap, &property, &length, NULL);
242 VERIFY_CBOR_SUCCESS(TAG, result, "Failed Get first crl ojbject tag.");
243 result = cbor_value_advance(&crlMap);
244 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to advance crlMap");
246 if (0 == strcmp(OIC_JSON_DATA_NAME, property))
248 if (cbor_value_is_byte_string(&crlMap))
250 result = cbor_value_dup_byte_string(&crlMap, &value->data, &value->len, NULL);
252 else if(cbor_value_is_text_string(&crlMap))
255 result = cbor_value_dup_text_string(&crlMap, &buffer, &value->len, NULL);
256 value->data = (uint8_t *)buffer;
260 result = CborErrorUnknownType;
261 OIC_LOG(ERROR, TAG, "Unknown type for crl->data.");
263 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to read crl->data");
265 else if (0 == strcmp(OIC_JSON_ENCODING_NAME, property))
267 size_t encoding_len = 0;
268 result = cbor_value_dup_text_string(&crlMap, &encoding, &encoding_len, NULL);
269 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to read crl->encdoing");
274 VERIFY_CBOR_SUCCESS(TAG, result, "Failed to find root node");
278 OicEncodingType_t type = OIC_ENCODING_UNKNOW;
279 if (0 == strcmp(encoding, OIC_SEC_ENCODING_BASE64)) type = OIC_ENCODING_BASE64;
280 else if (0 == strcmp(encoding, OIC_SEC_ENCODING_DER)) type = OIC_ENCODING_DER;
281 else if (0 == strcmp(encoding, OIC_SEC_ENCODING_PEM)) type = OIC_ENCODING_PEM;
282 else if (0 == strcmp(encoding, OIC_SEC_ENCODING_RAW)) type = OIC_ENCODING_RAW;
284 value->encoding = type;
290 OCStackResult CrlToCBORPayload(const OicSecCrl_t *crl, uint8_t **payload, size_t *size, char *lastUpdate)
292 if (NULL == crl || NULL == payload || NULL != *payload || NULL == size)
294 return OC_STACK_INVALID_PARAM;
297 size_t cborLen = *size;
306 size_t mapSize = CRL_MAP_SIZE;
314 OCStackResult ret = OC_STACK_ERROR;
319 CborError cborEncoderResult = CborNoError;
321 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
322 VERIFY_NON_NULL(TAG, outPayload, ERROR);
323 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
325 cborEncoderResult = cbor_encoder_create_map(&encoder, &crlMap, mapSize);
326 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to create CRL Map");
329 cborEncoderResult = cbor_encode_text_string(&crlMap, OC_RSRVD_CRL_ID,
330 strlen(OC_RSRVD_CRL_ID));
331 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add CRL ID");
332 cborEncoderResult = cbor_encode_int(&crlMap, crl->CrlId);
333 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add CRL Id value");
335 //ThisUpdate -- Mandatory
336 cborEncoderResult = cbor_encode_text_string(&crlMap, OC_RSRVD_THIS_UPDATE,
337 strlen(OC_RSRVD_THIS_UPDATE));
338 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add Crl update");
339 cborEncoderResult = cbor_encode_text_string(&crlMap, (const char *)crl->ThisUpdate.data,
340 crl->ThisUpdate.len);
341 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add Crl Update value");
343 //CRLData -- Mandatory
344 cborEncoderResult = setPubDataType(&crlMap, OC_RSRVD_CRL, &crl->CrlData);
345 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add CRLData object");
347 //lastUpdate - internal field
350 cborEncoderResult = cbor_encode_text_string(&crlMap, OC_RSRVD_LAST_UPDATE,
351 strlen(OC_RSRVD_LAST_UPDATE));
352 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add last Update tag");
353 cborEncoderResult = cbor_encode_text_string(&crlMap, lastUpdate, strlen(lastUpdate));
354 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add last Update value");
357 cborEncoderResult = cbor_encoder_close_container(&encoder, &crlMap);
358 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed to add close Crl map");
360 *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
361 *payload = outPayload;
365 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
371 ret = OC_STACK_ERROR;
372 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
374 // Since the allocated initial memory failed, double the memory.
375 cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
376 cborEncoderResult = CborNoError;
377 ret = CrlToCBORPayload(crl, payload, &cborLen, lastUpdate);
384 OCStackResult CBORPayloadToCrl(const uint8_t *cborPayload, const size_t size,
385 OicSecCrl_t **secCrl)
387 if (NULL == cborPayload || NULL == secCrl || NULL != *secCrl || 0 == size)
389 return OC_STACK_INVALID_PARAM;
392 OCStackResult ret = OC_STACK_ERROR;
393 OicSecCrl_t *crl = NULL;
395 CborValue crlCbor = {.parser = NULL};
396 CborParser parser = {.end = NULL};
397 CborError cborFindResult = CborNoError;
399 cbor_parser_init(cborPayload, size, 0, &parser, &crlCbor);
400 CborValue crlMap = { .parser = NULL};
401 cborFindResult = cbor_value_enter_container(&crlCbor, &crlMap);
402 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to enter Crl map");
404 crl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
405 VERIFY_NON_NULL(TAG, crl, ERROR);
407 cborFindResult = cbor_value_map_find_value(&crlCbor, OC_RSRVD_CRL_ID, &crlMap);
408 if (CborNoError == cborFindResult && cbor_value_is_integer(&crlMap))
412 cborFindResult = cbor_value_get_int(&crlMap, &CrlId);
413 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CrlId.");
414 crl->CrlId = (uint16_t)CrlId;
417 cborFindResult = cbor_value_map_find_value(&crlCbor, OC_RSRVD_THIS_UPDATE, &crlMap);
418 if (CborNoError == cborFindResult && cbor_value_is_text_string(&crlMap))
420 cborFindResult = cbor_value_dup_text_string(&crlMap,
421 (char **)&crl->ThisUpdate.data, &crl->ThisUpdate.len, NULL);
422 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Byte Array.");
425 cborFindResult = getPubDataType(&crlCbor, OC_RSRVD_CRL, &crl->CrlData);
426 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read CRL.");
433 if (CborNoError != cborFindResult)
435 // PUT/POST CBOR may not have mandatory values set default values.
436 OIC_LOG (DEBUG, TAG, "Set default values");
438 if (copyCrl(gCrl, crl))
447 ret = OC_STACK_ERROR;
448 OIC_LOG (ERROR, TAG, "Can't set default crl");
454 static void getCurrentUTCTime(char *out, size_t len)
456 //TODO: how to implement it in cross-platform way?
458 struct tm * timeinfo = NULL;
461 timeinfo = localtime ( &rawtime );
463 if (NULL == timeinfo)
468 snprintf(out, len, "%04d%02d%02d%02d%02d%02d",
469 timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
470 timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
473 OCStackResult UpdateCRLResource(OicSecCrl_t *crl)
475 static uint16_t crlid = 0;
476 uint8_t *payload = NULL;
479 crl->CrlId = crlid++;
481 if (!copyCrl(crl, gCrl))
483 OIC_LOG(ERROR, TAG, "Can't update global crl");
484 return OC_STACK_ERROR;
487 char currentTime[32] = {0};
488 getCurrentUTCTime(currentTime, sizeof(currentTime));
490 OCStackResult res = CrlToCBORPayload((const OicSecCrl_t *) crl, &payload, &size, currentTime);
491 if (OC_STACK_OK != res)
496 return UpdateSecureResourceInPS(OIC_CBOR_CRL_NAME, payload, size);
499 static OCEntityHandlerResult HandleCRLPostRequest(const OCEntityHandlerRequest *ehRequest)
501 OCEntityHandlerResult ehRet = OC_EH_ERROR;
502 OicSecCrl_t *crl = NULL;
503 uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
504 size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
508 OIC_LOG(INFO, TAG, "Update SVR DB...");
509 CBORPayloadToCrl(payload, size, &crl);
510 VERIFY_NON_NULL(TAG, crl, ERROR);
512 if (OC_STACK_OK == UpdateCRLResource(crl))
514 ehRet = OC_EH_RESOURCE_CREATED;
521 // Send payload to request originator
522 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
525 OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandleCRLPostRequest");
528 OIC_LOG_V(INFO, TAG, "%s RetVal %d", __func__, ehRet);
534 * This internal method is the entity handler for CRL resource and
535 * will handle REST request (GET/PUT/POST/DEL) for them.
537 static OCEntityHandlerResult CRLEntityHandler(OCEntityHandlerFlag flag,
538 OCEntityHandlerRequest *ehRequest,
539 void *callbackParameter)
541 OCEntityHandlerResult ehRet = OC_EH_ERROR;
542 (void)callbackParameter;
549 OIC_LOG(INFO, TAG, "Handle CRL resource");
551 if (flag & OC_REQUEST_FLAG)
553 // TODO : Handle PUT and DEL methods
554 OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
555 switch (ehRequest->method)
558 OIC_LOG (INFO, TAG, "Not implemented request method.");
559 //ehRet = HandleCRLGetRequest(ehRequest);
563 ehRet = HandleCRLPostRequest(ehRequest);
568 SendSRMResponse(ehRequest, ehRet, NULL, 0);
576 * This internal method is used to create '/oic/sec/crl' resource.
578 static OCStackResult CreateCRLResource()
580 OCStackResult ret = OCCreateResource(&gCrlHandle,
581 OIC_RSRC_TYPE_SEC_CRL,
582 OC_RSRVD_INTERFACE_DEFAULT,
588 if (OC_STACK_OK != ret)
590 OIC_LOG(FATAL, TAG, "Unable to instantiate CRL resource");
597 * Get the default value.
598 * @return defaultCrl for now.
600 static OicSecCrl_t *GetCrlDefault()
602 OicSecCrl_t *defaultCrl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
603 if (NULL == defaultCrl)
608 defaultCrl->CrlId = CRL_DEFAULT_CRL_ID;
609 defaultCrl->CrlData.encoding = OIC_ENCODING_DER;
611 bool result1 = copyByteArray((const uint8_t *)CRL_DEFAULT_CRL_DATA,
612 strlen(CRL_DEFAULT_CRL_DATA),
613 &defaultCrl->CrlData.data,
614 &defaultCrl->CrlData.len);
616 bool result2 = copyByteArray((const uint8_t *)CRL_DEFAULT_THIS_UPDATE,
617 strlen(CRL_DEFAULT_THIS_UPDATE),
618 &defaultCrl->ThisUpdate.data,
619 &defaultCrl->ThisUpdate.len);
621 if (!result1 || !result2)
623 DeleteCrl(defaultCrl);
631 * Initialize CRL resource by loading data from persistent storage.
634 * OC_STACK_OK - no errors
635 * OC_STACK_ERROR - stack process error
637 OCStackResult InitCRLResource()
639 OCStackResult ret = OC_STACK_ERROR;
640 // Read Crl resource from PS
641 uint8_t *data = NULL;
643 ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
644 // If database read failed
645 if (OC_STACK_OK != ret)
647 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
651 // Read ACL resource from PS
652 ret = CBORPayloadToCrl(data, size, &gCrl);
656 * If SVR database in persistent storage got corrupted or
657 * is not available for some reason, a default CrlResource is created
658 * which allows user to initiate CrlResource provisioning again.
660 if ((OC_STACK_OK != ret) || !data || !gCrl)
662 gCrl = GetCrlDefault();
665 ret = CreateCRLResource();
671 * Perform cleanup for ACL resources.
673 OCStackResult DeInitCRLResource()
675 OCStackResult result = OCDeleteResource(gCrlHandle);
682 OicSecCrl_t *GetCRLResource()
684 OicSecCrl_t *crl = NULL;
686 //Read CRL resource from PS
687 uint8_t *data = NULL;
689 OCStackResult ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
692 //Convert CBOR CRL into binary format
693 ret = CBORPayloadToCrl(data, size, &crl);
696 * If SVR database in persistent storage got corrupted or
697 * is not available for some reason, a default CrlResource is created
698 * which allows user to initiate CrlResource provisioning again.
700 if ((OC_STACK_OK != ret) || !data || !crl)
702 crl = GetCrlDefault();
709 OCStackResult getLastUpdateFromDB(char **lastUpdate)
711 OCStackResult result = OC_STACK_OK;
713 OCPayload *payload = NULL;
714 uint8_t *data = NULL;
719 return OC_STACK_INVALID_PARAM;
722 result = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
723 if (result != OC_STACK_OK)
725 OIC_LOG(ERROR, TAG, "Can't get crl data from database");
729 result = OCParsePayload(&payload, PAYLOAD_TYPE_REPRESENTATION, data, size);
730 if (result != OC_STACK_OK)
732 OIC_LOG(ERROR, TAG, "Can't parse cbor data from DB");
736 if (!OCRepPayloadGetPropString((const OCRepPayload*)payload, OC_RSRVD_LAST_UPDATE, lastUpdate))
738 OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_LAST_UPDATE);
739 result = OC_STACK_ERROR;
743 if (result != OC_STACK_OK)
745 OIC_LOG(DEBUG, TAG, "Assume you are first time get Crl, and it can be absent in database");
746 OIC_LOG_V(DEBUG, TAG, "Return default last update time %s", CRL_DEFAULT_LAST_UPDATE);
748 *lastUpdate = OICStrdup(CRL_DEFAULT_LAST_UPDATE);
749 result = OC_STACK_OK;
751 OCPayloadDestroy((OCPayload *)payload);
758 uint8_t *data = NULL;
760 OicSecCrl_t *crl = NULL;
761 if (OC_STACK_OK == GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size) && data &&
762 OC_STACK_OK == CBORPayloadToCrl(data, size, &crl))
764 return crl->CrlData.data;
769 void GetDerCrl(ByteArray_t* out)
776 OicSecCrl_t *crlRes = GetCRLResource();
783 OicSecKey_t *crl = &crlRes->CrlData;
785 if (OIC_ENCODING_BASE64 == crl->encoding)
787 size_t outSize = B64DECODE_OUT_SAFESIZE((crl->len + 1));
788 uint8_t *out = OICCalloc(1, outSize);
791 OIC_LOG(ERROR, TAG, "Can't allocate memory for base64 str");
796 if(B64_OK == b64Decode((char*)crl->data, crl->len, out, outSize, &len))
798 memcpy(crl->data, out, len);
799 crl->len = (size_t)len;
801 OIC_LOG (ERROR, TAG, "Crl successfully decoded to base64.");
805 OIC_LOG (ERROR, TAG, "Base64 decoding failed.");
812 out->data = OICRealloc(out->data, crl->len);
815 memcpy(out->data, crl->data, crl->len);
820 OIC_LOG(ERROR, TAG, "Can't allocate memory for out->data");