Commit 31a0ce40 authored by Dmitrii Zhuravlev's avatar Dmitrii Zhuravlev Committed by Sachin Agrawal

Add PKIX resources

It allows to manage certificate, crl through the CoAP resources

Change-Id: Iee019fb872a6cce07e35c3b01cb25800e480fa25
Signed-off-by: default avatarDmytro Zhuravlev <d.zhuravlev@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2450Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarsangsu choi <sangsu.choi@samsung.com>
Reviewed-by: default avatarSachin Agrawal <sachin.agrawal@intel.com>
parent 77d4c599
......@@ -23,6 +23,8 @@
#include "ocsecurityconfig.h"
#include "cainterface.h"
#include "securevirtualresourcetypes.h"
#include "octypes.h"
#ifdef __cplusplus
extern "C" {
......@@ -143,6 +145,18 @@ OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t cre
#endif /* __WITH_DTLS__ */
#ifdef __WITH_X509__
/**
* This function is used toretrieve certificate credentials from RI security layer.
*
* @param credInfo
* binary structure containing certificate credentials
*
* @retval OC_STACK_OK on scuccess
*/
OCStackResult GetDtlsCertCredentials(CADtlsCertCreds_t *credInfo);
#endif /*__WITH_X509__*/
/**
* Function to deallocate allocated memory to OicSecCred_t
*
......
//******************************************************************
//
// Copyright 2015 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#ifndef IOTVT_SRM_CRLR_H
#define IOTVT_SRM_CRLR_H
#include "octypes.h"
#include "securevirtualresourcetypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This function stores CRL in SRM
* @param crl - CRL
*
* @returns OC_STACK_OK for Success, otherwise some error value
*/
OCStackResult UpdateCRLResource(const OicSecCrl_t *crl);
/**
* This function get encoded with base64 CRL from SRM
*
* @returns encoded CRL with base64 format. NULL if error occured (e.g. CRL did not set)
* @note Caller responsible for resulting string memory (use OICFree to remove it)
*/
char* GetBase64CRL();
/**
* This function get CRL from SRM
*
* @param crl [out] - pointer to buffer that contains crl. Shoul be not NULL. Buffer
* will be allocated by the function and content of *crl will be ignored.
* @param outlen [out] - pointer to length of the CRL buffer. Shoul be not NULL.
*
* @returns OC_STACK_OK if success and errorcode otherwise.
* @note Caller responsible for crl buffer memory (use OICFree to free it)
*/
OicSecCrl_t * JSONToCrlBin(const char * jsonStr);
/**
* Initialize CLR resource by loading data from persistent storage.
*
* @returns OC_STACK_OK for Success, otherwise some error value
*/
OCStackResult InitCRLResource();
/**
* Perform cleanup for CRL resources.
*/
void DeInitCRLResource();
OicSecCrl_t *GetCRLResource();
OCEntityHandlerResult CRLEntityHandler(OCEntityHandlerFlag flag,
OCEntityHandlerRequest * ehRequest,
void* callbackParameter);
#ifdef __cplusplus
}
#endif
#endif //IOTVT_SRM_CRLR_H
......@@ -52,6 +52,11 @@ extern const char * OIC_RSRC_TYPE_SEC_CRED;
extern const char * OIC_RSRC_CRED_URI;
extern const char * OIC_JSON_CRED_NAME;
//CRL
extern const char * OIC_RSRC_TYPE_SEC_CRL;
extern const char * OIC_RSRC_CRL_URI;
extern const char * OIC_JSON_CRL_NAME;
//SVC
extern const char * OIC_RSRC_TYPE_SEC_SVC;
extern const char * OIC_RSRC_SVC_URI;
......
......@@ -43,6 +43,9 @@
#include <stdint.h> // for uint8_t typedef
#include <stdbool.h>
#ifdef __WITH_X509__
#include "byte_array.h"
#endif /* __WITH_X509__ */
#ifdef __cplusplus
extern "C" {
......@@ -252,6 +255,10 @@ typedef char *OicUrn_t; //TODO is URN type defined elsewhere?
typedef struct OicUuid OicUuid_t; //TODO is UUID type defined elsewhere?
#ifdef __WITH_X509__
typedef struct OicSecCrl OicSecCrl_t;
#endif /* __WITH_X509__ */
/**
* @brief /oic/uuid (Universal Unique Identifier) data type.
*/
......@@ -428,6 +435,15 @@ struct OicSecSvc
OicSecSvc_t *next;
};
#ifdef __WITH_X509__
struct OicSecCrl
{
uint16_t CrlId;
ByteArray ThisUpdate;
ByteArray CrlData;
};
#endif /* __WITH_X509__ */
#ifdef __cplusplus
}
#endif
......
......@@ -158,17 +158,37 @@ char * BinToCredJSON(const OicSecCred_t * cred)
//CredType -- Mandatory
cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType);
#if 0
#ifdef __WITH_X509__
//PublicData -- Not Mandatory
if(cred->publicData.data)
{
if (SIGNED_ASYMMETRIC_KEY == cred->credType)
{
cJSON_AddItemToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME,
cJSON_Parse(cred->publicData.data));
}
else
{
cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data);
}
}
#endif
#endif /*__WITH_X509__*/
//PrivateData -- Not Mandatory
if(cred->privateData.data)
{
#ifdef __WITH_X509__
if (SIGNED_ASYMMETRIC_KEY == cred->credType)
{
cJSON_AddItemToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME,
cJSON_Parse(cred->privateData.data));
}
else
{
cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
}
#else
cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data);
#endif
}
//Period -- Not Mandatory
......@@ -286,12 +306,56 @@ OicSecCred_t * JSONToCredBin(const char * jsonStr)
VERIFY_NON_NULL(TAG, jsonObj, ERROR);
VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
}
if(jsonObj && cJSON_String == jsonObj->type)
#ifdef __WITH_X509__
else if (cred->credType & SIGNED_ASYMMETRIC_KEY)
{
jsonObjLen = strlen(jsonObj->valuestring) + 1;
cred->privateData.data = (char *)OICMalloc(jsonObjLen);
VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
VERIFY_NON_NULL(TAG, jsonObj, ERROR);
VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
}
#endif // __WITH_X509__
if (NULL != jsonObj)
{
if (cJSON_String == jsonObj->type)
{
jsonObjLen = strlen(jsonObj->valuestring) + 1;
cred->privateData.data = (char *)OICMalloc(jsonObjLen);
VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen);
}
#ifdef __WITH_X509__
else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
{
cred->privateData.data = cJSON_PrintUnformatted(jsonObj);
VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR);
}
#endif // __WITH_X509__
}
//PublicData is mandatory only for SIGNED_ASYMMETRIC_KEY credentials type.
jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PUBLICDATA_NAME);
#ifdef __WITH_X509__
if (cred->credType & SIGNED_ASYMMETRIC_KEY)
{
VERIFY_NON_NULL(TAG, jsonObj, ERROR);
VERIFY_SUCCESS(TAG, cJSON_Object == jsonObj->type, ERROR);
}
#endif // __WITH_X509__
if (NULL != jsonObj)
{
if (cJSON_String == jsonObj->type)
{
jsonObjLen = strlen(jsonObj->valuestring) + 1;
cred->publicData.data = (char *)OICMalloc(jsonObjLen);
VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
strncpy((char *)cred->publicData.data, (char *)jsonObj->valuestring, jsonObjLen);
}
#ifdef __WITH_X509__
else if (SIGNED_ASYMMETRIC_KEY == cred->credType && cJSON_Object == jsonObj->type)
{
cred->publicData.data = cJSON_PrintUnformatted(jsonObj);
VERIFY_NON_NULL(TAG, (cred->publicData.data), ERROR);
}
#endif // __WITH_X509__
}
//Period -- Not Mandatory
......@@ -377,14 +441,14 @@ OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t cr
SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
cred->credType = credType;
#if 0
#ifdef __WITH_X509__
if(publicData)
{
cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1);
VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1);
}
#endif
#endif // __WITH_X509__
if(privateData)
{
......@@ -581,7 +645,6 @@ static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * eh
//list and updating svr database.
ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
}
return ret;
}
......@@ -627,7 +690,6 @@ exit:
return ehRet;
}
/*
* This internal method is the entity handler for Cred resources
* to handle REST request (PUT/POST/DEL)
......@@ -920,3 +982,158 @@ exit:
}
#endif /* __WITH_DTLS__ */
#ifdef __WITH_X509__
#define CERT_LEN_PREFIX (3)
#define BYTE_SIZE (8) //bits
#define PUB_KEY_X_COORD ("x")
#define PUB_KEY_Y_COORD ("y")
#define CERTIFICATE ("x5c")
#define PRIVATE_KEY ("d")
static void WriteCertPrefix(uint8_t *prefix, uint32_t certLen)
{
for (size_t i = 0; i < CERT_LEN_PREFIX; ++i)
{
prefix[i] = (certLen >> (BYTE_SIZE * (CERT_LEN_PREFIX - 1 - i))) & 0xFF;
}
}
static uint32_t ParseCertPrefix(uint8_t *prefix)
{
uint32_t res = 0;
if(NULL != prefix)
{
for(int i=0; i < CERT_LEN_PREFIX; ++i)
{
res |= (((uint32_t) prefix[i]) << ((CERT_LEN_PREFIX - 1 -i) * BYTE_SIZE));
}
}
return res;
}
static uint32_t appendCert2Chain(uint8_t *appendPoint, char *cert, uint32_t max_len)
{
uint32_t ret = 0;
VERIFY_NON_NULL(TAG, appendPoint, ERROR);
VERIFY_NON_NULL(TAG, cert, ERROR);
uint32_t certLen;
VERIFY_SUCCESS(TAG, B64_OK == b64Decode(cert, strlen(cert), appendPoint + CERT_LEN_PREFIX,
max_len - CERT_LEN_PREFIX, &certLen), ERROR);
WriteCertPrefix(appendPoint, certLen);
ret = certLen + CERT_LEN_PREFIX;
exit:
return ret;
}
static OCStackResult GetCAPublicKeyData(CADtlsCertCreds_t *credInfo){
OCStackResult ret = OC_STACK_ERROR;
uint8_t *ccPtr = credInfo->certificateChain;
for(uint32_t i =0; i < credInfo->chainLen - 1; ++i)
{
ccPtr += CERT_LEN_PREFIX + ParseCertPrefix(ccPtr);
}
ByteArray cert = {
.data = ccPtr + CERT_LEN_PREFIX,
.len = ParseCertPrefix(ccPtr)
};
CertificateX509 certStruct;
VERIFY_SUCCESS(TAG, PKI_SUCCESS == DecodeCertificate(cert, &certStruct), ERROR);
INC_BYTE_ARRAY(certStruct.pubKey, 2);
memcpy(credInfo->rootPublicKeyX, certStruct.pubKey.data, PUBLIC_KEY_SIZE / 2);
memcpy(credInfo->rootPublicKeyY, certStruct.pubKey.data + PUBLIC_KEY_SIZE / 2, PUBLIC_KEY_SIZE / 2);
ret = OC_STACK_OK;
exit:
return ret;
}
static OCStackResult GetCertCredPublicData(CADtlsCertCreds_t *credInfo, OicSecCred_t *cred)
{
OCStackResult ret = OC_STACK_ERROR;
VERIFY_NON_NULL(TAG, credInfo, ERROR);
VERIFY_NON_NULL(TAG, cred, ERROR);
VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
//VERIFY_SUCCESS(TAG, NULL == credInfo->certificateChain.data, ERROR);
cJSON *jsonRoot = cJSON_Parse(cred->publicData.data);
VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
//Get certificate chain
cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, CERTIFICATE);//TODO define field names constants
VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_Array == jsonObj->type, ERROR);
size_t certChainLen = cJSON_GetArraySize(jsonObj);
credInfo->chainLen = certChainLen;
VERIFY_SUCCESS(TAG, MAX_CHAIN_LEN >= certChainLen, ERROR);
uint32_t len = 0;
for (size_t i = 0; i < certChainLen; ++i)
{
cJSON *item = cJSON_GetArrayItem(jsonObj, i);
VERIFY_SUCCESS(TAG, cJSON_String == item->type, ERROR);
uint32_t appendedLen = appendCert2Chain(credInfo->certificateChain + len, item->valuestring,
MAX_REQUEST_LENGTH - len);
VERIFY_SUCCESS(TAG, 0 != appendedLen, ERROR);
len += appendedLen;
}
credInfo->certificateChainLen = len;
VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCAPublicKeyData(credInfo), ERROR);
ret = OC_STACK_OK;
exit:
cJSON_Delete(jsonRoot);
return ret;
}
static OCStackResult GetCertCredPrivateData(CADtlsCertCreds_t *credInfo, OicSecCred_t *cred)
{
OCStackResult ret = OC_STACK_ERROR;
VERIFY_NON_NULL(TAG, credInfo, ERROR);
VERIFY_NON_NULL(TAG, cred, ERROR);
VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
cJSON *jsonRoot = cJSON_Parse(cred->privateData.data);
VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
cJSON *jsonObj = cJSON_GetObjectItem(jsonRoot, PRIVATE_KEY);//TODO define field names constants
VERIFY_SUCCESS(TAG, NULL != jsonObj && cJSON_String == jsonObj->type, ERROR);
uint32_t read = 0u;
VERIFY_SUCCESS(TAG, B64_OK == b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring),
credInfo->devicePrivateKey, PRIVATE_KEY_SIZE, &read)
&& PRIVATE_KEY_SIZE == read, ERROR);
ret = OC_STACK_OK;
exit:
cJSON_Delete(jsonRoot);
return ret;
}
OCStackResult GetDtlsCertCredentials(CADtlsCertCreds_t *credInfo)
{
OCStackResult ret = OC_STACK_ERROR;
VERIFY_NON_NULL(TAG, credInfo, ERROR);
if (NULL == gCred)
{
VERIFY_SUCCESS(TAG, OC_STACK_OK == InitCredResource(), ERROR);
}
OicSecCred_t *cred = NULL;
LL_SEARCH_SCALAR(gCred, cred, credType, SIGNED_ASYMMETRIC_KEY);
VERIFY_NON_NULL(TAG, cred, ERROR);
VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPrivateData(credInfo, cred), ERROR);
VERIFY_SUCCESS(TAG, OC_STACK_OK == GetCertCredPublicData(credInfo, cred), ERROR);
ret = OC_STACK_OK;
exit:
return ret;
}
#undef CERT_LEN_PREFIX
#endif /* __WITH_X509__ */
//******************************************************************
//
// Copyright 2015 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <stdlib.h>
#include <string.h>
#include "ocstack.h"
#include "logger.h"
#include "oic_malloc.h"
#include "cJSON.h"
#include "base64.h"
#include "resourcemanager.h"
#include "psinterface.h"
#include "utlist.h"
#include "srmresourcestrings.h"
#include "doxmresource.h"
#include "srmutility.h"
#ifdef __WITH_X509__
#include "crlresource.h"
#include "crl.h"
#include "ckm_info.h"
#endif /* __WITH_X509__ */
#define TAG PCF("SRM-CRL")
#define SEPARATOR ":"
#define SEPARATOR_LEN (1)
#define JSON_CRL_NAME "\"CRL\""
#define JSON_CRL_NAME_LEN (5)
#define OIC_JSON_CRL_NAME "crl"
#define OIC_JSON_CRL_ID "CRLId"
#define OIC_JSON_CRL_THIS_UPDATE "ThisUpdate"
#define OIC_JSON_CRL_DATA "CRLData"
#define CRL_DEFAULT_CRL_ID 1
#define CRL_DEFAULT_THIS_UPDATE "150101000000Z"
#define CRL_DEFAULT_CRL_DATA "-"
static OCResourceHandle gCrlHandle = NULL;
static OicSecCrl_t *gCrl = NULL;
void DeleteCrlBinData(OicSecCrl_t *crl)
{
if (crl)
{
//Clean ThisUpdate
OICFree(crl->ThisUpdate.data);
//clean CrlData
OICFree(crl->CrlData.data);
//Clean crl itself
OICFree(crl);
}
}
char *BinToCrlJSON(const OicSecCrl_t *crl)
{
if (NULL == crl)
{
return NULL;
}
char *base64Buff = NULL;
uint32_t outLen = 0;
uint32_t base64CRLLen = 0;
B64Result b64Ret = B64_OK;
char *jsonStr = NULL;
cJSON *jsonRoot = cJSON_CreateObject();
VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
cJSON *jsonCrl = cJSON_CreateObject();
VERIFY_NON_NULL(TAG, jsonCrl, ERROR);
cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRL_NAME, jsonCrl);
//CRLId -- Mandatory
cJSON_AddNumberToObject(jsonCrl, OIC_JSON_CRL_ID, (int)crl->CrlId);
//ThisUpdate -- Mandatory
outLen = 0;
base64CRLLen = B64ENCODE_OUT_SAFESIZE(crl->ThisUpdate.len);
base64Buff = OICMalloc(base64CRLLen);
b64Ret = b64Encode(crl->ThisUpdate.data, crl->ThisUpdate.len, base64Buff,
base64CRLLen, &outLen);
VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
cJSON_AddStringToObject(jsonCrl, OIC_JSON_CRL_THIS_UPDATE, base64Buff);
OICFree(base64Buff);
//CRLData -- Mandatory
outLen = 0;
base64CRLLen = B64ENCODE_OUT_SAFESIZE(crl->CrlData.len);
base64Buff = OICMalloc(base64CRLLen);
b64Ret = b64Encode(crl->CrlData.data, crl->CrlData.len, base64Buff,
base64CRLLen, &outLen);
VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
cJSON_AddStringToObject(jsonCrl, OIC_JSON_CRL_DATA, base64Buff);
jsonStr = cJSON_PrintUnformatted(jsonRoot);
exit:
OICFree(base64Buff);
if (jsonRoot)
{
cJSON_Delete(jsonRoot);
}
return jsonStr;
}
OicSecCrl_t *JSONToCrlBin(const char * jsonStr)
{
if (NULL == jsonStr)
{
return NULL;
}
OCStackResult ret = OC_STACK_ERROR;
OicSecCrl_t *crl = NULL;
cJSON *jsonCrl = NULL;
cJSON *jsonObj = NULL;
unsigned char *base64Buff = NULL;
uint32_t base64CRLLen = 0;
uint32_t outLen = 0;
B64Result b64Ret = B64_OK;
cJSON *jsonRoot = cJSON_Parse(jsonStr);
VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
jsonCrl = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRL_NAME);
VERIFY_NON_NULL(TAG, jsonCrl, ERROR);
crl = (OicSecCrl_t *)OICCalloc(1, sizeof(OicSecCrl_t));
VERIFY_NON_NULL(TAG, crl, ERROR);
//CRLId -- Mandatory
jsonObj = cJSON_GetObjectItem(jsonCrl, OIC_JSON_CRL_ID);
if(jsonObj)
{
VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
crl->CrlId = (uint16_t)jsonObj->valueint;
}
else // PUT/POST JSON may not have CRLId so set it to the gCRList->CRLId
{
VERIFY_NON_NULL(TAG, gCrl, ERROR);
crl->CrlId = gCrl->CrlId;
}
//ThisUpdate -- Mandatory
jsonObj = cJSON_GetObjectItem(jsonCrl, OIC_JSON_CRL_THIS_UPDATE);
if(jsonObj)
{
VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
if(cJSON_String == jsonObj->type)
{
//Check for empty string, in case ThisUpdate field has not been set yet
if (jsonObj->valuestring[0])
{
base64CRLLen = B64ENCODE_OUT_SAFESIZE(strlen(jsonObj->valuestring));
base64Buff = OICMalloc(base64CRLLen);
b64Ret = b64Decode(jsonObj->valuestring,