vcpe/srcs/libs/protocol/protocol.c

318 lines
11 KiB
C

//
// Created by xajhuang on 2022/12/2.
//
#include <string.h>
#include "config.h"
#include "misc.h"
#include "common.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\"],\"properties\":{\"ver\":{\"type\":\"integer\"}}}",
"Incorrect field [ver]" },
{"{\"type\":\"object\",\"required\":[\"cryptoType\"],\"properties\":{\"cryptoType\":{\"type\":\"integer\","
"\"minimum\":0,\"maximum\":4}}}", "Incorrect field [cryptoType]" },
{"{\"type\":\"object\",\"required\":[\"timeStamp\"],\"properties\":{\"timeStamp\":{\"type\":\"integer\"}}}",
"Incorrect field [timeStamp]"},
{"{\"type\":\"object\",\"required\":[\"msgContent\"]}", "Missing required field [msgContent]" },
};
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));
printf("ERR_JSON_PARSE_OBJ\n");
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;
}