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 "oic_malloc.h"
30 #include "oic_string.h"
31 #include "crlresource.h"
33 #include "ocpayloadcbor.h"
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(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 = encoder.ptr - outPayload;
361 *payload = outPayload;
365 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
367 // reallocate and try again!
369 // Since the allocated initial memory failed, double the memory.
370 cborLen += encoder.ptr - encoder.end;
371 cborEncoderResult = CborNoError;
372 ret = CrlToCBORPayload(crl, payload, &cborLen, lastUpdate);
375 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
381 ret = OC_STACK_ERROR;
387 OCStackResult CBORPayloadToCrl(const uint8_t *cborPayload, const size_t size,
388 OicSecCrl_t **secCrl)
390 if (NULL == cborPayload || NULL == secCrl || NULL != *secCrl || 0 == size)
392 return OC_STACK_INVALID_PARAM;
395 OCStackResult ret = OC_STACK_ERROR;
396 OicSecCrl_t *crl = NULL;
398 CborValue crlCbor = {.parser = NULL};
399 CborParser parser = {.end = NULL};
400 CborError cborFindResult = CborNoError;
402 cbor_parser_init(cborPayload, size, 0, &parser, &crlCbor);
403 CborValue crlMap = { .parser = NULL};
404 cborFindResult = cbor_value_enter_container(&crlCbor, &crlMap);
405 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to enter Crl map");
407 crl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
408 VERIFY_NON_NULL(TAG, crl, ERROR);
410 cborFindResult = cbor_value_map_find_value(&crlCbor, OC_RSRVD_CRL_ID, &crlMap);
411 if (CborNoError == cborFindResult && cbor_value_is_integer(&crlMap))
415 cborFindResult = cbor_value_get_int(&crlMap, &CrlId);
416 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CrlId.");
417 crl->CrlId = (uint16_t)CrlId;
420 cborFindResult = cbor_value_map_find_value(&crlCbor, OC_RSRVD_THIS_UPDATE, &crlMap);
421 if (CborNoError == cborFindResult && cbor_value_is_text_string(&crlMap))
423 cborFindResult = cbor_value_dup_text_string(&crlMap,
424 (char **)&crl->ThisUpdate.data, &crl->ThisUpdate.len, NULL);
425 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Byte Array.");
428 cborFindResult = getPubDataType(&crlCbor, OC_RSRVD_CRL, &crl->CrlData);
429 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read CRL.");
436 if (CborNoError != cborFindResult)
438 // PUT/POST CBOR may not have mandatory values set default values.
439 OIC_LOG (DEBUG, TAG, "Set default values");
441 if (copyCrl(gCrl, crl))
450 ret = OC_STACK_ERROR;
451 OIC_LOG (ERROR, TAG, "Can't set default crl");
457 static void getCurrentUTCTime(char *out, size_t len)
459 //TODO: how to implement it in cross-platform way?
461 struct tm * timeinfo = NULL;
464 timeinfo = localtime ( &rawtime );
466 if (NULL == timeinfo)
471 snprintf(out, len, "%04d%02d%02d%02d%02d%02d",
472 timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
473 timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
476 OCStackResult UpdateCRLResource(OicSecCrl_t *crl)
478 static uint16_t crlid = 0;
479 uint8_t *payload = NULL;
482 crl->CrlId = crlid++;
484 if (!copyCrl(crl, gCrl))
486 OIC_LOG(ERROR, TAG, "Can't update global crl");
487 return OC_STACK_ERROR;
490 char currentTime[32] = {0};
491 getCurrentUTCTime(currentTime, sizeof(currentTime));
493 OCStackResult res = CrlToCBORPayload((const OicSecCrl_t *) crl, &payload, &size, currentTime);
494 if (OC_STACK_OK != res)
499 return UpdateSecureResourceInPS(OIC_CBOR_CRL_NAME, payload, size);
502 static OCEntityHandlerResult HandleCRLPostRequest(const OCEntityHandlerRequest *ehRequest)
504 OCEntityHandlerResult ehRet = OC_EH_ERROR;
505 OicSecCrl_t *crl = NULL;
506 uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
507 size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
511 OIC_LOG(INFO, TAG, "Update SVR DB...");
512 CBORPayloadToCrl(payload, size, &crl);
513 VERIFY_NON_NULL(TAG, crl, ERROR);
515 if (OC_STACK_OK == UpdateCRLResource(crl))
517 ehRet = OC_EH_RESOURCE_CREATED;
524 // Send payload to request originator
525 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
528 OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandleCRLPostRequest");
531 OIC_LOG_V(INFO, TAG, "%s RetVal %d", __func__, ehRet);
537 * This internal method is the entity handler for CRL resource and
538 * will handle REST request (GET/PUT/POST/DEL) for them.
540 static OCEntityHandlerResult CRLEntityHandler(OCEntityHandlerFlag flag,
541 OCEntityHandlerRequest *ehRequest,
542 void *callbackParameter)
544 OCEntityHandlerResult ehRet = OC_EH_ERROR;
545 (void)callbackParameter;
552 OIC_LOG(INFO, TAG, "Handle CRL resource");
554 if (flag & OC_REQUEST_FLAG)
556 // TODO : Handle PUT and DEL methods
557 OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
558 switch (ehRequest->method)
561 OIC_LOG (INFO, TAG, "Not implemented request method.");
562 //ehRet = HandleCRLGetRequest(ehRequest);
566 ehRet = HandleCRLPostRequest(ehRequest);
571 SendSRMResponse(ehRequest, ehRet, NULL, 0);
579 * This internal method is used to create '/oic/sec/crl' resource.
581 static OCStackResult CreateCRLResource()
583 OCStackResult ret = OCCreateResource(&gCrlHandle,
584 OIC_RSRC_TYPE_SEC_CRL,
585 OC_RSRVD_INTERFACE_DEFAULT,
591 if (OC_STACK_OK != ret)
593 OIC_LOG(FATAL, TAG, "Unable to instantiate CRL resource");
600 * Get the default value.
601 * @return defaultCrl for now.
603 static OicSecCrl_t *GetCrlDefault()
605 OicSecCrl_t *defaultCrl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
606 if (NULL == defaultCrl)
611 defaultCrl->CrlId = CRL_DEFAULT_CRL_ID;
613 bool result1 = copyByteArray((const uint8_t *)CRL_DEFAULT_CRL_DATA,
614 strlen(CRL_DEFAULT_CRL_DATA),
615 &defaultCrl->CrlData.data,
616 &defaultCrl->CrlData.len);
618 bool result2 = copyByteArray((const uint8_t *)CRL_DEFAULT_THIS_UPDATE,
619 strlen(CRL_DEFAULT_THIS_UPDATE),
620 &defaultCrl->ThisUpdate.data,
621 &defaultCrl->ThisUpdate.len);
623 if (!result1 || !result2)
625 DeleteCrl(defaultCrl);
633 * Initialize CRL resource by loading data from persistent storage.
636 * OC_STACK_OK - no errors
637 * OC_STACK_ERROR - stack process error
639 OCStackResult InitCRLResource()
641 OCStackResult ret = OC_STACK_ERROR;
642 // Read Crl resource from PS
643 uint8_t *data = NULL;
645 ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
646 // If database read failed
647 if (OC_STACK_OK != ret)
649 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
653 // Read ACL resource from PS
654 ret = CBORPayloadToCrl(data, size, &gCrl);
658 * If SVR database in persistent storage got corrupted or
659 * is not available for some reason, a default CrlResource is created
660 * which allows user to initiate CrlResource provisioning again.
662 if ((OC_STACK_OK != ret) || !data || !gCrl)
664 gCrl = GetCrlDefault();
667 ret = CreateCRLResource();
673 * Perform cleanup for ACL resources.
675 OCStackResult DeInitCRLResource()
677 OCStackResult result = OCDeleteResource(gCrlHandle);
684 OicSecCrl_t *GetCRLResource()
686 OicSecCrl_t *crl = NULL;
688 //Read CRL resource from PS
689 uint8_t *data = NULL;
691 OCStackResult ret = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
694 //Convert CBOR CRL into binary format
695 ret = CBORPayloadToCrl(data, size, &crl);
698 * If SVR database in persistent storage got corrupted or
699 * is not available for some reason, a default CrlResource is created
700 * which allows user to initiate CrlResource provisioning again.
702 if ((OC_STACK_OK != ret) || !data || !crl)
704 crl = GetCrlDefault();
711 OCStackResult getLastUpdateFromDB(char **lastUpdate)
713 OCStackResult result = OC_STACK_OK;
715 OCPayload *payload = NULL;
716 uint8_t *data = NULL;
721 return OC_STACK_INVALID_PARAM;
724 result = GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size);
725 if (result != OC_STACK_OK)
727 OIC_LOG(ERROR, TAG, "Can't get crl data from database");
731 result = OCParsePayload(&payload, PAYLOAD_TYPE_REPRESENTATION, data, size);
732 if (result != OC_STACK_OK)
734 OIC_LOG(ERROR, TAG, "Can't parse cbor data from DB");
738 if (!OCRepPayloadGetPropString((const OCRepPayload*)payload, OC_RSRVD_LAST_UPDATE, lastUpdate))
740 OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_LAST_UPDATE);
741 result = OC_STACK_ERROR;
745 if (result != OC_STACK_OK)
747 OIC_LOG(DEBUG, TAG, "Assume you are first time get Crl, and it can be absent in database");
748 OIC_LOG_V(DEBUG, TAG, "Return default last update time %s", CRL_DEFAULT_LAST_UPDATE);
750 *lastUpdate = OICStrdup(CRL_DEFAULT_LAST_UPDATE);
751 result = OC_STACK_OK;
753 OCPayloadDestroy((OCPayload *)payload);
760 uint8_t *data = NULL;
762 OicSecCrl_t *crl = NULL;
763 if (OC_STACK_OK == GetSecureVirtualDatabaseFromPS(OIC_CBOR_CRL_NAME, &data, &size) && data &&
764 OC_STACK_OK == CBORPayloadToCrl(data, size, &crl))
766 return crl->CrlData.data;
771 void GetDerCrl(ByteArray* out)
778 OicSecCrl_t *crlRes = GetCRLResource();
785 OicSecKey_t *crl = &crlRes->CrlData;
787 if (OIC_ENCODING_BASE64 == crl->encoding)
789 size_t outSize = B64DECODE_OUT_SAFESIZE((crl->len + 1));
790 uint8_t *out = OICCalloc(1, outSize);
793 OIC_LOG(ERROR, TAG, "Can't allocate memory for base64 str");
798 if(B64_OK == b64Decode((char*)crl->data, crl->len, out, outSize, &len))
800 memcpy(crl->data, out, len);
801 crl->len = (size_t)len;
803 OIC_LOG (ERROR, TAG, "Crl successfully decoded to base64.");
807 OIC_LOG (ERROR, TAG, "Base64 decoding failed.");
814 char *str = "Not enough space in out buffer to store crl!";
815 if (out->data && crl->data && crl->len <= out->len)
817 char *str = "Can't allocate memory for out->data";
818 out->data = OICMalloc(crl->len);
822 memcpy(out->data, crl->data, crl->len);
827 OIC_LOG_V(ERROR, TAG, "%s", str);