dynreg.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub
  3. available.
  4. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  5. * Licensed under the MIT License (the "License"); you may not use this file
  6. except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. * http://opensource.org/licenses/MIT
  9. * Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is
  11. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  12. KIND,
  13. * either express or implied. See the License for the specific language
  14. governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #ifdef __cplusplus
  24. extern "C" {
  25. #endif
  26. #include "lite-utils.h"
  27. #include "qcloud_iot_ca.h"
  28. #include "qcloud_iot_common.h"
  29. #include "qcloud_iot_device.h"
  30. #include "qcloud_iot_export.h"
  31. #include "qcloud_iot_import.h"
  32. #include "utils_aes.h"
  33. #include "utils_base64.h"
  34. #include "utils_hmac.h"
  35. #include "utils_httpc.h"
  36. #include "ql_fs.h"
  37. #define REG_URL_MAX_LEN (128)
  38. #define DYN_REG_SIGN_LEN (64)
  39. #define DYN_BUFF_DATA_MORE (10)
  40. #define BASE64_ENCODE_OUT_LEN(x) (((x + 3) * 4) / 3)
  41. #define DYN_REG_RES_HTTP_TIMEOUT_MS (2000)
  42. #ifdef AUTH_MODE_CERT
  43. #define DYN_RESPONSE_BUFF_LEN (5 * 1024)
  44. #define DECODE_BUFF_LEN (5 * 1024)
  45. #else
  46. #define DYN_RESPONSE_BUFF_LEN (256)
  47. #define DECODE_BUFF_LEN (256)
  48. #endif
  49. /* Knuth's TAOCP section 3.6 */
  50. #define M ((1U << 31) - 1)
  51. #define A 48271
  52. #define Q 44488 // M/A
  53. #define R 3399 // M%A; R < Q !!!
  54. #define CODE_RESAULT "code"
  55. #define ENCRYPT_TYPE "encryptionType"
  56. #define PSK_DATA "psk"
  57. #define CERT_DATA "clientCert"
  58. #define KEY_DATA "clientKey"
  59. typedef enum {
  60. eCERT_TYPE = 1,
  61. ePSK_TYPE = 2,
  62. } eAuthType;
  63. /*Global value*/
  64. static unsigned int _seed = 1;
  65. #ifndef AUTH_MODE_CERT
  66. static char *_get_json_psk(char *json)
  67. {
  68. char *psk = LITE_json_value_of(PSK_DATA, json);
  69. if (psk == NULL) {
  70. Log_e("Get psk fail: %s", json);
  71. }
  72. return psk;
  73. }
  74. #else
  75. static char *_get_json_cert_data(char *json)
  76. {
  77. char *cert = LITE_json_value_of(CERT_DATA, json);
  78. if (cert == NULL) {
  79. Log_e("Get clientCert fail: %s", json);
  80. }
  81. return cert;
  82. }
  83. static char *_get_json_key_data(char *json)
  84. {
  85. char *key = LITE_json_value_of(KEY_DATA, json);
  86. if (key == NULL) {
  87. Log_e("Get clientCert fail: %s", json);
  88. }
  89. return key;
  90. }
  91. /*\\n in data change to '\n'*/
  92. static void _deal_transfer(char *data, uint32_t dataLen)
  93. {
  94. int i;
  95. for (i = 0; i < dataLen; i++) {
  96. if ((data[i] == '\\') && (data[i + 1] == 'n')) {
  97. data[i] = ' ';
  98. data[i + 1] = '\n';
  99. }
  100. }
  101. }
  102. static int _cert_file_save(const char *fileName, char *data, uint32_t dataLen)
  103. {
  104. QFILE fp;
  105. char filePath[FILE_PATH_MAX_LEN];
  106. uint32_t len;
  107. int Ret = QCLOUD_ERR_FAILURE;
  108. memset(filePath, 0, FILE_PATH_MAX_LEN);
  109. HAL_Snprintf(filePath, FILE_PATH_MAX_LEN, "./certs/%s", fileName);
  110. fp = ql_fopen(fileName, "w+");
  111. if (fp<0) {
  112. Log_e("fail to open file %s", fileName);
  113. goto exit;
  114. }
  115. _deal_transfer(data, dataLen);
  116. len = ql_fwrite(data, dataLen, 1, fp);
  117. ql_fclose(fp);
  118. if (len == dataLen) {
  119. Log_d("save %s file succes", fileName);
  120. Ret = QCLOUD_RET_SUCCESS;
  121. }
  122. exit:
  123. return Ret;
  124. }
  125. #endif
  126. int rand_r(unsigned int *seed)
  127. {
  128. int32_t X;
  129. X = *seed;
  130. X = A * (X % Q) - R * (int32_t)(X / Q);
  131. if (X < 0)
  132. X += M;
  133. *seed = X;
  134. return X;
  135. }
  136. int rand_d(void)
  137. {
  138. return rand_r(&_seed);
  139. }
  140. void srand_d(unsigned int i)
  141. {
  142. _seed = i;
  143. }
  144. static int _get_json_result_code(char *json)
  145. {
  146. int32_t resault = -1;
  147. char *v = LITE_json_value_of(CODE_RESAULT, json);
  148. if (v == NULL) {
  149. Log_e("Invalid json content: %s", json);
  150. return -1;
  151. }
  152. if (LITE_get_int32(&resault, v) != QCLOUD_RET_SUCCESS) {
  153. Log_e("Invalid json content: %s", json);
  154. HAL_Free(v);
  155. return -1;
  156. }
  157. HAL_Free(v);
  158. return resault;
  159. }
  160. static int _get_json_encry_type(char *json)
  161. {
  162. int32_t type = -1;
  163. char *v = LITE_json_value_of(ENCRYPT_TYPE, json);
  164. if (v == NULL) {
  165. Log_e("Get encry type fail, %s", json);
  166. return -1;
  167. }
  168. if (LITE_get_int32(&type, v) != QCLOUD_RET_SUCCESS) {
  169. Log_e("Invalid json content: %s", json);
  170. HAL_Free(v);
  171. return -1;
  172. }
  173. HAL_Free(v);
  174. return type;
  175. }
  176. static int _parse_devinfo(char *jdoc, DeviceInfo *pDevInfo)
  177. {
  178. int ret = 0;
  179. size_t len;
  180. int datalen;
  181. int enType;
  182. unsigned int keybits;
  183. char key[UTILS_AES_BLOCK_LEN + 1];
  184. char decodeBuff[DECODE_BUFF_LEN] = {0};
  185. unsigned char iv[16];
  186. char * payload = NULL;
  187. #ifdef AUTH_MODE_CERT
  188. char *clientCert;
  189. char *clientKey;
  190. #else
  191. char *psk;
  192. #endif
  193. Log_d("recv: %s", jdoc);
  194. ret = _get_json_result_code(jdoc);
  195. if (QCLOUD_RET_SUCCESS != ret) {
  196. Log_e("response err, ret:%d", ret);
  197. goto exit;
  198. }
  199. payload = LITE_json_value_of("payload", jdoc);
  200. if (payload == NULL) {
  201. Log_e("Invalid json content: %s", jdoc);
  202. ret = QCLOUD_ERR_FAILURE;
  203. goto exit;
  204. } else {
  205. Log_d("payload:%s", payload);
  206. }
  207. ret = qcloud_iot_utils_base64decode((uint8_t *)decodeBuff, sizeof(decodeBuff), &len, (uint8_t *)payload,
  208. strlen(payload));
  209. if (ret != QCLOUD_RET_SUCCESS) {
  210. Log_e("Response decode err, response:%s", payload);
  211. ret = QCLOUD_ERR_FAILURE;
  212. goto exit;
  213. }
  214. datalen = len + (UTILS_AES_BLOCK_LEN - len % UTILS_AES_BLOCK_LEN);
  215. keybits = AES_KEY_BITS_128;
  216. memset(key, 0, UTILS_AES_BLOCK_LEN);
  217. strncpy(key, pDevInfo->product_secret, UTILS_AES_BLOCK_LEN);
  218. memset(iv, '0', UTILS_AES_BLOCK_LEN);
  219. ret = utils_aes_cbc((uint8_t *)decodeBuff, datalen, (uint8_t *)decodeBuff, DECODE_BUFF_LEN, UTILS_AES_DECRYPT,
  220. (uint8_t *)key, keybits, iv);
  221. if (QCLOUD_RET_SUCCESS == ret) {
  222. // Log_d("The decrypted data is:%s", decodeBuff);
  223. } else {
  224. Log_e("data decry err,ret:%d", ret);
  225. goto exit;
  226. }
  227. enType = _get_json_encry_type(decodeBuff);
  228. if (enType < 0) {
  229. Log_e("invlid encryt type, decrypt maybe faild");
  230. ret = QCLOUD_ERR_FAILURE;
  231. goto exit;
  232. }
  233. #ifdef AUTH_MODE_CERT
  234. if (eCERT_TYPE != enType) {
  235. Log_e("encryt type should be cert type");
  236. ret = QCLOUD_ERR_FAILURE;
  237. goto exit;
  238. }
  239. clientCert = _get_json_cert_data(decodeBuff);
  240. if (NULL != clientCert) {
  241. memset(pDevInfo->dev_cert_file_name, 0, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME);
  242. HAL_Snprintf(pDevInfo->dev_cert_file_name, MAX_SIZE_OF_DEVICE_CERT_FILE_NAME, "%s_cert.crt",
  243. pDevInfo->device_name);
  244. if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_cert_file_name, clientCert, strlen(clientCert))) {
  245. Log_e("save %s file fail", pDevInfo->dev_cert_file_name);
  246. ret = QCLOUD_ERR_FAILURE;
  247. }
  248. HAL_Free(clientCert);
  249. } else {
  250. Log_e("Get clientCert data fail");
  251. ret = QCLOUD_ERR_FAILURE;
  252. }
  253. clientKey = _get_json_key_data(decodeBuff);
  254. if (NULL != clientKey) {
  255. memset(pDevInfo->dev_key_file_name, 0, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME);
  256. HAL_Snprintf(pDevInfo->dev_key_file_name, MAX_SIZE_OF_DEVICE_SECRET_FILE_NAME, "%s_private.key",
  257. pDevInfo->device_name);
  258. if (QCLOUD_RET_SUCCESS != _cert_file_save(pDevInfo->dev_key_file_name, clientKey, strlen(clientKey))) {
  259. Log_e("save %s file fail", pDevInfo->dev_key_file_name);
  260. ret = QCLOUD_ERR_FAILURE;
  261. }
  262. HAL_Free(clientKey);
  263. } else {
  264. Log_e("Get clientCert data fail");
  265. ret = QCLOUD_ERR_FAILURE;
  266. }
  267. #else
  268. if (ePSK_TYPE != enType) {
  269. Log_e("encryt type should be psk type");
  270. ret = QCLOUD_ERR_FAILURE;
  271. goto exit;
  272. }
  273. psk = _get_json_psk(decodeBuff);
  274. if (NULL != psk) {
  275. if (strlen(psk) > MAX_SIZE_OF_DEVICE_SECRET) {
  276. Log_e("psk exceed max len,%s", psk);
  277. strcpy(pDevInfo->device_secret, psk);
  278. } else {
  279. strncpy(pDevInfo->device_secret, psk, MAX_SIZE_OF_DEVICE_SECRET);
  280. pDevInfo->device_secret[MAX_SIZE_OF_DEVICE_SECRET] = '\0';
  281. }
  282. HAL_Free(psk);
  283. } else {
  284. Log_e("Get psk data fail");
  285. }
  286. #endif
  287. exit:
  288. if (payload) {
  289. HAL_Free(payload);
  290. }
  291. return ret;
  292. }
  293. static int _post_reg_request_by_http(unsigned char profile_idx, char *request_buf, DeviceInfo *pDevInfo)
  294. {
  295. int Ret = 0;
  296. HTTPClient http_client; /* http client */
  297. HTTPClientData http_data; /* http client data */
  298. const char *url_format = "%s://%s/register/dev";
  299. char url[REG_URL_MAX_LEN] = {0};
  300. int port;
  301. const char *ca_crt = NULL;
  302. char respbuff[DYN_RESPONSE_BUFF_LEN];
  303. /*format URL*/
  304. #ifndef AUTH_WITH_NOTLS
  305. HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "https", iot_get_dyn_reg_domain(pDevInfo->region));
  306. port = DYN_REG_SERVER_PORT_TLS;
  307. ca_crt = iot_ca_get();
  308. #else
  309. HAL_Snprintf(url, REG_URL_MAX_LEN, url_format, "http", iot_get_dyn_reg_domain(pDevInfo->region));
  310. port = DYN_REG_SERVER_PORT;
  311. #endif
  312. memset((char *)&http_client, 0, sizeof(HTTPClient));
  313. memset((char *)&http_data, 0, sizeof(HTTPClientData));
  314. http_client.header = "Accept: text/xml,application/json;*/*\r\n";
  315. http_client.profile_idx = profile_idx;
  316. http_data.post_content_type = "application/x-www-form-urlencoded";
  317. http_data.post_buf = request_buf;
  318. http_data.post_buf_len = strlen(request_buf);
  319. Ret = qcloud_http_client_common(&http_client, url, port, ca_crt, HTTP_POST, &http_data);
  320. if (QCLOUD_RET_SUCCESS != Ret) {
  321. Log_e("qcloud_http_client_common failed, Ret = %d", Ret);
  322. return Ret;
  323. }
  324. memset(respbuff, 0, DYN_RESPONSE_BUFF_LEN);
  325. http_data.response_buf_len = DYN_RESPONSE_BUFF_LEN;
  326. http_data.response_buf = respbuff;
  327. Ret = qcloud_http_recv_data(&http_client, DYN_REG_RES_HTTP_TIMEOUT_MS, &http_data);
  328. if (QCLOUD_RET_SUCCESS != Ret) {
  329. Log_e("dynamic register response fail, Ret = %d", Ret);
  330. } else {
  331. /*Parse dev info*/
  332. Ret = _parse_devinfo(http_data.response_buf, pDevInfo);
  333. if (QCLOUD_RET_SUCCESS != Ret) {
  334. Log_e("parse device info err");
  335. }
  336. }
  337. qcloud_http_client_close(&http_client);
  338. return Ret;
  339. }
  340. static int _cal_dynreg_sign(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, uint32_t timestamp)
  341. {
  342. int sign_len;
  343. size_t olen = 0;
  344. char * pSignSource = NULL;
  345. const char *sign_fmt = "deviceName=%s&nonce=%d&productId=%s&timestamp=%d";
  346. char sign[DYN_REG_SIGN_LEN] = {0};
  347. /*format sign data*/
  348. sign_len = strlen(sign_fmt) + strlen(pDevInfo->device_name) + strlen(pDevInfo->product_id) + sizeof(int) +
  349. sizeof(uint32_t) + DYN_BUFF_DATA_MORE;
  350. pSignSource = HAL_Malloc(sign_len);
  351. if (pSignSource == NULL) {
  352. Log_e("malloc sign source buff fail");
  353. return QCLOUD_ERR_FAILURE;
  354. }
  355. memset(pSignSource, 0, sign_len);
  356. HAL_Snprintf((char *)pSignSource, sign_len, sign_fmt, pDevInfo->device_name, nonce, pDevInfo->product_id,
  357. timestamp);
  358. /*cal hmac sha1*/
  359. utils_hmac_sha1(pSignSource, strlen(pSignSource), sign, pDevInfo->product_secret, strlen(pDevInfo->product_secret));
  360. /*base64 encode*/
  361. qcloud_iot_utils_base64encode((uint8_t *)signout, max_signlen, &olen, (const uint8_t *)sign, strlen(sign));
  362. HAL_Free(pSignSource);
  363. return (olen > max_signlen) ? QCLOUD_ERR_FAILURE : QCLOUD_RET_SUCCESS;
  364. }
  365. int IOT_DynReg_Device(unsigned char profile_idx, DeviceInfo *pDevInfo)
  366. {
  367. const char *para_format =
  368. "{\"deviceName\":\"%s\",\"nonce\":%d,\"productId\":"
  369. "\"%s\",\"timestamp\":%d,\"signature\":\"%s\"}";
  370. int nonce;
  371. int Ret;
  372. uint32_t timestamp;
  373. int len;
  374. char sign[DYN_REG_SIGN_LEN] = {0};
  375. char * pRequest = NULL;
  376. if (strlen(pDevInfo->product_secret) < UTILS_AES_BLOCK_LEN) {
  377. Log_e("product key inllegal");
  378. return QCLOUD_ERR_FAILURE;
  379. }
  380. srand_d(HAL_GetTimeMs());
  381. nonce = rand_d();
  382. timestamp = HAL_GetTimeMs();
  383. /*cal sign*/
  384. if (QCLOUD_RET_SUCCESS == _cal_dynreg_sign(pDevInfo, sign, DYN_REG_SIGN_LEN, nonce, timestamp)) {
  385. Log_d("sign:%s", sign);
  386. } else {
  387. Log_e("cal sign fail");
  388. return QCLOUD_ERR_FAILURE;
  389. }
  390. /*format http request*/
  391. len = strlen(para_format) + strlen(pDevInfo->product_id) + strlen(pDevInfo->device_name) + sizeof(int) +
  392. sizeof(uint32_t) + strlen(sign) + DYN_BUFF_DATA_MORE;
  393. pRequest = HAL_Malloc(len);
  394. if (!pRequest) {
  395. Log_e("malloc request memory fail");
  396. return QCLOUD_ERR_FAILURE;
  397. }
  398. memset(pRequest, 0, len);
  399. HAL_Snprintf(pRequest, len, para_format, pDevInfo->device_name, nonce, pDevInfo->product_id, timestamp, sign);
  400. Log_d("request:%s", pRequest);
  401. Log_d("resbuff len:%d", DYN_RESPONSE_BUFF_LEN);
  402. /*post request*/
  403. Ret = _post_reg_request_by_http(profile_idx, pRequest, pDevInfo);
  404. if (QCLOUD_RET_SUCCESS == Ret) {
  405. Log_d("request dev info success");
  406. } else {
  407. Log_e("request dev info fail");
  408. }
  409. HAL_Free(pRequest);
  410. return Ret;
  411. }
  412. #ifdef __cplusplus
  413. }
  414. #endif