123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- /*
- * Tencent is pleased to support the open source community by making IoT Hub
- available.
- * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
- * Licensed under the MIT License (the "License"); you may not use this file
- except in
- * compliance with the License. You may obtain a copy of the License at
- * http://opensource.org/licenses/MIT
- * 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 <stdbool.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "lite-utils.h"
- #include "qcloud_iot_ca.h"
- #include "qcloud_iot_common.h"
- #include "qcloud_iot_device.h"
- #include "qcloud_iot_export.h"
- #include "qcloud_iot_import.h"
- #include "utils_aes.h"
- #include "utils_base64.h"
- #include "utils_hmac.h"
- #include "utils_httpc.h"
- #include "ql_fs.h"
- #define REG_URL_MAX_LEN (128)
- #define DYN_REG_SIGN_LEN (64)
- #define DYN_BUFF_DATA_MORE (10)
- #define BASE64_ENCODE_OUT_LEN(x) (((x + 3) * 4) / 3)
- #define DYN_REG_RES_HTTP_TIMEOUT_MS (2000)
- #ifdef AUTH_MODE_CERT
- #define DYN_RESPONSE_BUFF_LEN (5 * 1024)
- #define DECODE_BUFF_LEN (5 * 1024)
- #else
- #define DYN_RESPONSE_BUFF_LEN (256)
- #define DECODE_BUFF_LEN (256)
- #endif
- /* Knuth's TAOCP section 3.6 */
- #define M ((1U << 31) - 1)
- #define A 48271
- #define Q 44488 // M/A
- #define R 3399 // M%A; R < Q !!!
- #define CODE_RESAULT "code"
- #define ENCRYPT_TYPE "encryptionType"
- #define PSK_DATA "psk"
- #define CERT_DATA "clientCert"
- #define KEY_DATA "clientKey"
- typedef enum {
- eCERT_TYPE = 1,
- ePSK_TYPE = 2,
- } eAuthType;
- /*Global value*/
- static unsigned int _seed = 1;
- #ifndef AUTH_MODE_CERT
- static char *_get_json_psk(char *json)
- {
- char *psk = LITE_json_value_of(PSK_DATA, json);
- if (psk == NULL) {
- Log_e("Get psk fail: %s", json);
- }
- return psk;
- }
- #else
- static char *_get_json_cert_data(char *json)
- {
- char *cert = LITE_json_value_of(CERT_DATA, json);
- if (cert == NULL) {
- Log_e("Get clientCert fail: %s", json);
- }
- return cert;
- }
- static char *_get_json_key_data(char *json)
- {
- char *key = LITE_json_value_of(KEY_DATA, json);
- if (key == NULL) {
- Log_e("Get clientCert fail: %s", json);
- }
- return key;
- }
- /*\\n in data change to '\n'*/
- static void _deal_transfer(char *data, uint32_t dataLen)
- {
- int i;
- for (i = 0; i < dataLen; i++) {
- if ((data[i] == '\\') && (data[i + 1] == 'n')) {
- data[i] = ' ';
- data[i + 1] = '\n';
- }
- }
- }
- static int _cert_file_save(const char *fileName, char *data, uint32_t dataLen)
- {
-
- QFILE fp;
- char filePath[FILE_PATH_MAX_LEN];
- uint32_t len;
- int Ret = QCLOUD_ERR_FAILURE;
- memset(filePath, 0, FILE_PATH_MAX_LEN);
- HAL_Snprintf(filePath, FILE_PATH_MAX_LEN, "./certs/%s", fileName);
- fp = ql_fopen(fileName, "w+");
- if (fp<0) {
- Log_e("fail to open file %s", fileName);
- goto exit;
- }
- _deal_transfer(data, dataLen);
- len = ql_fwrite(data, dataLen, 1, fp);
- ql_fclose(fp);
- if (len == dataLen) {
- Log_d("save %s file succes", fileName);
- Ret = QCLOUD_RET_SUCCESS;
- }
- exit:
- return Ret;
- }
- #endif
- int rand_r(unsigned int *seed)
- {
- int32_t X;
- X = *seed;
- X = A * (X % Q) - R * (int32_t)(X / Q);
- if (X < 0)
- X += M;
- *seed = X;
- return X;
- }
- int rand_d(void)
- {
- return rand_r(&_seed);
- }
- void srand_d(unsigned int i)
- {
- _seed = i;
- }
- static int _get_json_result_code(char *json)
- {
- int32_t resault = -1;
- char *v = LITE_json_value_of(CODE_RESAULT, json);
- if (v == NULL) {
- Log_e("Invalid json content: %s", json);
- return -1;
- }
- if (LITE_get_int32(&resault, v) != QCLOUD_RET_SUCCESS) {
- Log_e("Invalid json content: %s", json);
- HAL_Free(v);
- return -1;
- }
- HAL_Free(v);
- return resault;
- }
- static int _get_json_encry_type(char *json)
- {
- int32_t type = -1;
- char *v = LITE_json_value_of(ENCRYPT_TYPE, json);
- if (v == NULL) {
- Log_e("Get encry type fail, %s", json);
- return -1;
- }
- if (LITE_get_int32(&type, v) != QCLOUD_RET_SUCCESS) {
- Log_e("Invalid json content: %s", json);
- HAL_Free(v);
- return -1;
- }
- HAL_Free(v);
- return type;
- }
- static int _parse_devinfo(char *jdoc, DeviceInfo *pDevInfo)
- {
- int ret = 0;
- size_t len;
- int datalen;
- int enType;
- unsigned int keybits;
- char key[UTILS_AES_BLOCK_LEN + 1];
- char decodeBuff[DECODE_BUFF_LEN] = {0};
- unsigned char iv[16];
- char * payload = NULL;
- #ifdef AUTH_MODE_CERT
- char *clientCert;
- char *clientKey;
- #else
- char *psk;
- #endif
- Log_d("recv: %s", jdoc);
- ret = _get_json_result_code(jdoc);
- if (QCLOUD_RET_SUCCESS != ret) {
- Log_e("response err, ret:%d", ret);
- goto exit;
- }
- payload = LITE_json_value_of("payload", jdoc);
- if (payload == NULL) {
- Log_e("Invalid json content: %s", jdoc);
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- } else {
- Log_d("payload:%s", payload);
- }
- ret = qcloud_iot_utils_base64decode((uint8_t *)decodeBuff, sizeof(decodeBuff), &len, (uint8_t *)payload,
- strlen(payload));
- if (ret != QCLOUD_RET_SUCCESS) {
- Log_e("Response decode err, response:%s", payload);
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- }
- datalen = len + (UTILS_AES_BLOCK_LEN - len % UTILS_AES_BLOCK_LEN);
- keybits = AES_KEY_BITS_128;
- memset(key, 0, UTILS_AES_BLOCK_LEN);
- strncpy(key, pDevInfo->product_secret, UTILS_AES_BLOCK_LEN);
- memset(iv, '0', UTILS_AES_BLOCK_LEN);
- ret = utils_aes_cbc((uint8_t *)decodeBuff, datalen, (uint8_t *)decodeBuff, DECODE_BUFF_LEN, UTILS_AES_DECRYPT,
- (uint8_t *)key, keybits, iv);
- if (QCLOUD_RET_SUCCESS == ret) {
- // Log_d("The decrypted data is:%s", decodeBuff);
- } else {
- Log_e("data decry err,ret:%d", ret);
- goto exit;
- }
- enType = _get_json_encry_type(decodeBuff);
- if (enType < 0) {
- Log_e("invlid encryt type, decrypt maybe faild");
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- }
- #ifdef AUTH_MODE_CERT
- if (eCERT_TYPE != enType) {
- Log_e("encryt type should be cert type");
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- }
- clientCert = _get_json_cert_data(decodeBuff);
- if (NULL != clientCert) {
- memset(pDevInfo->dev_cert_file_name, 0, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME);
- HAL_Snprintf(pDevInfo->dev_cert_file_name, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME, "%s_cert.crt",
- pDevInfo->device_name);
- if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_cert_file_name, clientCert, strlen(clientCert))) {
- Log_e("save %s file fail", pDevInfo->dev_cert_file_name);
- ret = QCLOUD_ERR_FAILURE;
- }
- HAL_Free(clientCert);
- } else {
- Log_e("Get clientCert data fail");
- ret = QCLOUD_ERR_FAILURE;
- }
- clientKey = _get_json_key_data(decodeBuff);
- if (NULL != clientKey) {
- memset(pDevInfo->dev_key_file_name, 0, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME);
- HAL_Snprintf(pDevInfo->dev_key_file_name, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME, "%s_private.key",
- pDevInfo->device_name);
- if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_key_file_name, clientKey, strlen(clientKey))) {
- Log_e("save %s file fail", pDevInfo->dev_key_file_name);
- ret = QCLOUD_ERR_FAILURE;
- }
- HAL_Free(clientKey);
- } else {
- Log_e("Get clientCert data fail");
- ret = QCLOUD_ERR_FAILURE;
- }
- #else
- if (ePSK_TYPE != enType) {
- Log_e("encryt type should be psk type");
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- }
- psk = _get_json_psk(decodeBuff);
- if (NULL != psk) {
- if (strlen(psk) > MAX_SIZE_OF_DEVICE_SECRET) {
- Log_e("psk exceed max len,%s", psk);
- strcpy(pDevInfo->device_secret, psk);
- } else {
- strncpy(pDevInfo->device_secret, psk, MAX_SIZE_OF_DEVICE_SECRET);
- pDevInfo->device_secret[MAX_SIZE_OF_DEVICE_SECRET] = '\0';
- }
- HAL_Free(psk);
- } else {
- Log_e("Get psk data fail");
- }
- #endif
- exit:
- if (payload) {
- HAL_Free(payload);
- }
- return ret;
- }
- static int _post_reg_request_by_http(unsigned char profile_idx, char *request_buf, DeviceInfo *pDevInfo)
- {
- int Ret = 0;
- HTTPClient http_client; /* http client */
- HTTPClientData http_data; /* http client data */
- const char *url_format = "%s://%s/register/dev";
- char url[REG_URL_MAX_LEN] = {0};
- int port;
- const char *ca_crt = NULL;
- char respbuff[DYN_RESPONSE_BUFF_LEN];
- /*format URL*/
- #ifndef AUTH_WITH_NOTLS
- HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "https", iot_get_dyn_reg_domain(pDevInfo->region));
- port = DYN_REG_SERVER_PORT_TLS;
- ca_crt = iot_ca_get();
- #else
- HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "http", iot_get_dyn_reg_domain(pDevInfo->region));
- port = DYN_REG_SERVER_PORT;
- #endif
- memset((char *)&http_client, 0, sizeof(HTTPClient));
- memset((char *)&http_data, 0, sizeof(HTTPClientData));
- http_client.header = "Accept: text/xml,application/json;*/*\r\n";
- http_client.profile_idx = profile_idx;
- http_data.post_content_type = "application/x-www-form-urlencoded";
- http_data.post_buf = request_buf;
- http_data.post_buf_len = strlen(request_buf);
- Ret = qcloud_http_client_common(&http_client, url, port, ca_crt, HTTP_POST, &http_data);
- if (QCLOUD_RET_SUCCESS != Ret) {
- Log_e("qcloud_http_client_common failed, Ret = %d", Ret);
- return Ret;
- }
- memset(respbuff, 0, DYN_RESPONSE_BUFF_LEN);
- http_data.response_buf_len = DYN_RESPONSE_BUFF_LEN;
- http_data.response_buf = respbuff;
- Ret = qcloud_http_recv_data(&http_client, DYN_REG_RES_HTTP_TIMEOUT_MS, &http_data);
- if (QCLOUD_RET_SUCCESS != Ret) {
- Log_e("dynamic register response fail, Ret = %d", Ret);
- } else {
- /*Parse dev info*/
- Ret = _parse_devinfo(http_data.response_buf, pDevInfo);
- if (QCLOUD_RET_SUCCESS != Ret) {
- Log_e("parse device info err");
- }
- }
- qcloud_http_client_close(&http_client);
- return Ret;
- }
- static int _cal_dynreg_sign(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, uint32_t timestamp)
- {
- int sign_len;
- size_t olen = 0;
- char * pSignSource = NULL;
- const char *sign_fmt = "deviceName=%s&nonce=%d&productId=%s×tamp=%d";
- char sign[DYN_REG_SIGN_LEN] = {0};
- /*format sign data*/
- sign_len = strlen(sign_fmt) + strlen(pDevInfo->device_name) + strlen(pDevInfo->product_id) + sizeof(int) +
- sizeof(uint32_t) + DYN_BUFF_DATA_MORE;
- pSignSource = HAL_Malloc(sign_len);
- if (pSignSource == NULL) {
- Log_e("malloc sign source buff fail");
- return QCLOUD_ERR_FAILURE;
- }
- memset(pSignSource, 0, sign_len);
- HAL_Snprintf((char *)pSignSource, sign_len, sign_fmt, pDevInfo->device_name, nonce, pDevInfo->product_id,
- timestamp);
- /*cal hmac sha1*/
- utils_hmac_sha1(pSignSource, strlen(pSignSource), sign, pDevInfo->product_secret, strlen(pDevInfo->product_secret));
- /*base64 encode*/
- qcloud_iot_utils_base64encode((uint8_t *)signout, max_signlen, &olen, (const uint8_t *)sign, strlen(sign));
- HAL_Free(pSignSource);
- return (olen > max_signlen) ? QCLOUD_ERR_FAILURE : QCLOUD_RET_SUCCESS;
- }
- int IOT_DynReg_Device(unsigned char profile_idx, DeviceInfo *pDevInfo)
- {
- const char *para_format =
- "{\"deviceName\":\"%s\",\"nonce\":%d,\"productId\":"
- "\"%s\",\"timestamp\":%d,\"signature\":\"%s\"}";
- int nonce;
- int Ret;
- uint32_t timestamp;
- int len;
- char sign[DYN_REG_SIGN_LEN] = {0};
- char * pRequest = NULL;
- if (strlen(pDevInfo->product_secret) < UTILS_AES_BLOCK_LEN) {
- Log_e("product key inllegal");
- return QCLOUD_ERR_FAILURE;
- }
- srand_d(HAL_GetTimeMs());
- nonce = rand_d();
- timestamp = HAL_GetTimeMs();
- /*cal sign*/
- if (QCLOUD_RET_SUCCESS == _cal_dynreg_sign(pDevInfo, sign, DYN_REG_SIGN_LEN, nonce, timestamp)) {
- Log_d("sign:%s", sign);
- } else {
- Log_e("cal sign fail");
- return QCLOUD_ERR_FAILURE;
- }
- /*format http request*/
- len = strlen(para_format) + strlen(pDevInfo->product_id) + strlen(pDevInfo->device_name) + sizeof(int) +
- sizeof(uint32_t) + strlen(sign) + DYN_BUFF_DATA_MORE;
- pRequest = HAL_Malloc(len);
- if (!pRequest) {
- Log_e("malloc request memory fail");
- return QCLOUD_ERR_FAILURE;
- }
- memset(pRequest, 0, len);
- HAL_Snprintf(pRequest, len, para_format, pDevInfo->device_name, nonce, pDevInfo->product_id, timestamp, sign);
- Log_d("request:%s", pRequest);
- Log_d("resbuff len:%d", DYN_RESPONSE_BUFF_LEN);
- /*post request*/
- Ret = _post_reg_request_by_http(profile_idx, pRequest, pDevInfo);
- if (QCLOUD_RET_SUCCESS == Ret) {
- Log_d("request dev info success");
- } else {
- Log_e("request dev info fail");
- }
- HAL_Free(pRequest);
- return Ret;
- }
- #ifdef __cplusplus
- }
- #endif
|