// // Created by xajhuang on 2022/12/2. // #include #include "config.h" #include "misc.h" #include "proto.h" #include "crypto.h" #include "user_errno.h" #include "zlog_module.h" #ifdef JSON_SCHEMA_ON #include "json_schema/jsoncdaccord.h" #endif #define CURRENT_PROTOCOL_VERSION (1) typedef struct { unsigned int ver; unsigned int cryptoType; unsigned long long timeStamp; unsigned int code; cJSON *msgContend; } PROTOCOL_WARP, *PPROTOCOL_WARP; #ifdef JSON_SCHEMA_ON typedef struct { const char *pSchJson; const char *pErrMsg; } JSON_SCHEMA_CTX, *PJSON_SCHEMA_CTX; static JSON_SCHEMA_CTX g_json_sch[] = { {"{\"type\":\"object\",\"required\":[\"ver\"]}", "Missing required field [ver]" }, {"{\"type\":\"object\",\"required\":[\"cryptoType\"]}", "Missing required field [cryptoType]" }, {"{\"type\":\"object\",\"required\":[\"timeStamp\"]}", "Missing required field [timeStamp]" }, {"{\"type\":\"object\",\"required\":[\"msgContent\"]}", "Missing required field [msgContent]" }, {"{\"properties\":{\"ver\":{\"type\":\"integer\"}}}", "[ver] should be an integer value" }, {"{\"properties\":{\"cryptoType\":{\"type\":\"integer\"}}}", "[cryptoType] should be an integer value"}, {"{\"properties\":{\"cryptoType\":{\"minimum\":0,\"maximum\":4}}}", "Undefined type in field [cryptoType]" }, {"{\"properties\":{\"timeStamp\":{\"type\":\"integer\"}}}", "[timeStamp] should be an integer value" }, }; const char *proto_schema_validation(const char *pJsonStr) { int i; json_object *pJs = json_tokener_parse(pJsonStr); if (!pJs) { cJSON *pRspRoot = cJSON_CreateObject(); cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_PARSE_OBJ); cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_PARSE_OBJ)); return proto_create_new(pRspRoot, 200); } for (i = 0; i < ARRAY_SIZE(g_json_sch); i++) { json_object *pSc = json_tokener_parse(g_json_sch[i].pSchJson); if (!pSc) { LOG_MOD(error, ZLOG_MOD_PROTO, "Json schema format error: [%s]\n", g_json_sch[i].pSchJson); continue; } if (jdac_validate(pJs, pSc) != JDAC_ERR_VALID) { cJSON *pRspRoot = cJSON_CreateObject(); cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_VALID_SCH); cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_VALID_SCH)); cJSON_AddStringToObject(pRspRoot, "details", g_json_sch[i].pErrMsg); json_object_put(pSc); json_object_put(pJs); return proto_create_new(pRspRoot, 200); } json_object_put(pSc); } json_object_put(pJs); return NULL; } const char *proto_msg_validation(const char *pJsonStr, const char *msgJson) { json_object *pJs = json_tokener_parse(pJsonStr); if (!pJs) { cJSON *pRspRoot = cJSON_CreateObject(); cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_PARSE_OBJ); cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_PARSE_OBJ)); return proto_create_new(pRspRoot, 200); } json_object *pSc = json_tokener_parse(msgJson); if (!pSc) { LOG_MOD(error, ZLOG_MOD_PROTO, "Json schema format error: [%s]\n", msgJson); } if (jdac_validate(pJs, pSc) != JDAC_ERR_VALID) { cJSON *pRspRoot = cJSON_CreateObject(); cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_VALID_SCH); cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_VALID_SCH)); cJSON_AddStringToObject(pRspRoot, "details", getErrorEnumDesc(ERR_MSG_CONTENT)); json_object_put(pSc); json_object_put(pJs); return proto_create_new(pRspRoot, 200); } json_object_put(pSc); json_object_put(pJs); return NULL; } #endif const char *proto_decode_context(const char *pString, unsigned int *pVer, unsigned long long *pTm, int *pErrCode) { cJSON *pMsgCtx; unsigned char *pBase64; int decodeSize; unsigned int outSize = 0; char *pMsgContent = NULL; cJSON *pRoot; #ifdef JSON_SCHEMA_ON const char *pSchJson; #endif if (pErrCode == NULL) { return NULL; } if (pString == NULL || strlen(pString) == 0) { *pErrCode = ERR_INPUT_PARAMS; return NULL; } LOG_MOD(debug, ZLOG_MOD_PROTO, "Request: %s\n", pString); #ifdef JSON_SCHEMA_ON pSchJson = proto_schema_validation(pString); if (pSchJson != NULL && strlen(pSchJson) > 0) { *pErrCode = ERR_JSON_VALID_SCH; return pSchJson; } #endif pRoot = cJSON_Parse(pString); if (!pRoot) { return NULL; } cJSON *pCrypto = cJSON_GetObjectItem(pRoot, "cryptoType"); if (!pCrypto) { cJSON_Delete(pRoot); return NULL; } if (pVer) { cJSON *pObj = cJSON_GetObjectItem(pRoot, "ver"); if (pObj) { *pVer = pObj->valueint; } } if (pTm) { cJSON *pObj = cJSON_GetObjectItem(pRoot, "timeStamp"); if (pObj) { *pTm = (unsigned long long)pObj->valuedouble; } } pMsgCtx = cJSON_GetObjectItem(pRoot, "msgContent"); if (!pMsgCtx) { cJSON_Delete(pRoot); return NULL; } switch (pCrypto->valueint) { case CRYPTO_NONE: pMsgContent = cJSON_Print(pMsgCtx); break; case CRYPTO_BASE64: pMsgContent = (char *)base64_decode(pMsgCtx->valuestring, (unsigned int *)&outSize); break; case CRYPTO_AES128: case CRYPTO_AES256: case CRYPTO_3DES: { int cryptoType; const char *pKey = config_get_proto_crypto_key(); if (pCrypto->valueint == CRYPTO_AES128) { cryptoType = AES128_ECB_PKCS7PADDING; } else if (pCrypto->valueint == CRYPTO_AES256) { cryptoType = AES256_ECB_PKCS7PADDING; } else if (pCrypto->valueint == CRYPTO_3DES) { cryptoType = DES3_ECB_PKCS7PADDING; } else { cJSON_Delete(pRoot); return NULL; } pBase64 = (unsigned char *)base64_decode(pMsgCtx->valuestring, (unsigned int *)&outSize); if (symmetric_decrypto(cryptoType, pBase64, outSize, (unsigned char **)(&pMsgContent), &decodeSize, pKey) != ERR_SUCCESS) { free((void *)pBase64); if (pMsgContent) { free(pMsgContent); } cJSON_Delete(pRoot); return NULL; } else { pMsgContent[decodeSize] = 0; } free((void *)pBase64); } break; } cJSON_Delete(pRoot); return pMsgContent; } const char *proto_create_new(cJSON *pMsgCtx, int httpCode) { const char *pStrProto; cJSON *pRoot; PROTOCOL_WARP pro = {.ver = CURRENT_PROTOCOL_VERSION, .cryptoType = config_get_proto_crypto_type(), .timeStamp = get_current_time_ms(), .code = httpCode}; pRoot = cJSON_CreateObject(); if (pRoot == NULL) { return NULL; } cJSON_AddNumberToObject(pRoot, "ver", pro.ver); cJSON_AddNumberToObject(pRoot, "cryptoType", pro.cryptoType); cJSON_AddNumberToObject(pRoot, "timeStamp", (double)pro.timeStamp); cJSON_AddNumberToObject(pRoot, "code", pro.code); if (pMsgCtx == NULL) { pro.msgContend = cJSON_CreateObject(); } else { pro.msgContend = pMsgCtx; } switch (pro.cryptoType) { case CRYPTO_NONE: cJSON_AddItemToObject(pRoot, "msgContent", pro.msgContend); break; case CRYPTO_BASE64: { const char *pStrMsg = cJSON_Print(pro.msgContend); const char *base64 = base64_encode((unsigned char *)pStrMsg, strlen(pStrMsg)); cJSON_AddStringToObject(pRoot, "msgContent", base64); free((void *)base64); cJSON_free(pro.msgContend); } break; case CRYPTO_AES128: case CRYPTO_AES256: case CRYPTO_3DES: { int cryptoType; const char *pKey = config_get_proto_crypto_key(); const char *base64; const char *pStrMsg = cJSON_Print(pro.msgContend); if (pro.cryptoType == CRYPTO_AES128) { cryptoType = AES128_ECB_PKCS7PADDING; } else if (pro.cryptoType == CRYPTO_AES256) { cryptoType = AES256_ECB_PKCS7PADDING; } else { cryptoType = DES3_ECB_PKCS7PADDING; } if (pKey == NULL || strlen(pKey) == 0) { LOG_MOD(error, ZLOG_MOD_PROTO, "Cryptography key empty of algorithm %d, Used default algorithm BASE64\n", cryptoType); base64 = base64_encode((unsigned char *)pStrMsg, strlen(pStrMsg)); pro.cryptoType = CRYPTO_BASE64; } else { int ret; unsigned char *buf; int outSize = 0; ret = symmetric_encrypto(cryptoType, (unsigned char *)pStrMsg, strlen(pStrMsg), &buf, &outSize, pKey); if (ret != ERR_SUCCESS) { LOG_MOD(error, ZLOG_MOD_PROTO, "Unsupported protocol crypto : %d, Used default algorithm BASE64\n", cryptoType); base64 = base64_encode((unsigned char *)pStrMsg, strlen(pStrMsg)); pro.cryptoType = CRYPTO_BASE64; } else { base64 = base64_encode((unsigned char *)buf, outSize); } } cJSON_AddStringToObject(pRoot, "msgContent", base64); free((void *)base64); cJSON_free(pro.msgContend); } break; default: LOG_MOD(error, ZLOG_MOD_PROTO, "Unsupported protocol crypto algorithms: %d, Used default algorithm BASE64\n", pro.cryptoType); cJSON_free(pro.msgContend); cJSON_Delete(pRoot); return NULL; } pStrProto = cJSON_PrintUnformatted(pRoot); LOG_MOD(debug, ZLOG_MOD_PROTO, "Create: %s\n", pStrProto); cJSON_Delete(pRoot); return pStrProto; }