aclk_otp.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "aclk_otp.h"
  3. #include "aclk_util.h"
  4. #include "aclk.h"
  5. #include "daemon/common.h"
  6. #include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
  7. struct dictionary_singleton {
  8. char *key;
  9. char *result;
  10. };
  11. static int json_extract_singleton(JSON_ENTRY *e)
  12. {
  13. struct dictionary_singleton *data = e->callback_data;
  14. switch (e->type) {
  15. case JSON_OBJECT:
  16. case JSON_ARRAY:
  17. break;
  18. case JSON_STRING:
  19. if (!strcmp(e->name, data->key)) {
  20. data->result = strdupz(e->data.string);
  21. break;
  22. }
  23. break;
  24. case JSON_NUMBER:
  25. case JSON_BOOLEAN:
  26. case JSON_NULL:
  27. break;
  28. }
  29. return 0;
  30. }
  31. // Base-64 decoder.
  32. // Note: This is non-validating, invalid input will be decoded without an error.
  33. // Challenges are packed into json strings so we don't skip newlines.
  34. // Size errors (i.e. invalid input size or insufficient output space) are caught.
  35. static size_t base64_decode(unsigned char *input, size_t input_size, unsigned char *output, size_t output_size)
  36. {
  37. static char lookup[256];
  38. static int first_time=1;
  39. if (first_time)
  40. {
  41. first_time = 0;
  42. for(int i=0; i<256; i++)
  43. lookup[i] = -1;
  44. for(int i='A'; i<='Z'; i++)
  45. lookup[i] = i-'A';
  46. for(int i='a'; i<='z'; i++)
  47. lookup[i] = i-'a' + 26;
  48. for(int i='0'; i<='9'; i++)
  49. lookup[i] = i-'0' + 52;
  50. lookup['+'] = 62;
  51. lookup['/'] = 63;
  52. }
  53. if ((input_size & 3) != 0)
  54. {
  55. error("Can't decode base-64 input length %zu", input_size);
  56. return 0;
  57. }
  58. size_t unpadded_size = (input_size/4) * 3;
  59. if ( unpadded_size > output_size )
  60. {
  61. error("Output buffer size %zu is too small to decode %zu into", output_size, input_size);
  62. return 0;
  63. }
  64. // Don't check padding within full quantums
  65. for (size_t i = 0 ; i < input_size-4 ; i+=4 )
  66. {
  67. uint32_t value = (lookup[input[0]] << 18) + (lookup[input[1]] << 12) + (lookup[input[2]] << 6) + lookup[input[3]];
  68. output[0] = value >> 16;
  69. output[1] = value >> 8;
  70. output[2] = value;
  71. //error("Decoded %c %c %c %c -> %02x %02x %02x", input[0], input[1], input[2], input[3], output[0], output[1], output[2]);
  72. output += 3;
  73. input += 4;
  74. }
  75. // Handle padding only in last quantum
  76. if (input[2] == '=') {
  77. uint32_t value = (lookup[input[0]] << 6) + lookup[input[1]];
  78. output[0] = value >> 4;
  79. //error("Decoded %c %c %c %c -> %02x", input[0], input[1], input[2], input[3], output[0]);
  80. return unpadded_size-2;
  81. }
  82. else if (input[3] == '=') {
  83. uint32_t value = (lookup[input[0]] << 12) + (lookup[input[1]] << 6) + lookup[input[2]];
  84. output[0] = value >> 10;
  85. output[1] = value >> 2;
  86. //error("Decoded %c %c %c %c -> %02x %02x", input[0], input[1], input[2], input[3], output[0], output[1]);
  87. return unpadded_size-1;
  88. }
  89. else
  90. {
  91. uint32_t value = (input[0] << 18) + (input[1] << 12) + (input[2]<<6) + input[3];
  92. output[0] = value >> 16;
  93. output[1] = value >> 8;
  94. output[2] = value;
  95. //error("Decoded %c %c %c %c -> %02x %02x %02x", input[0], input[1], input[2], input[3], output[0], output[1], output[2]);
  96. return unpadded_size;
  97. }
  98. }
  99. static size_t base64_encode(unsigned char *input, size_t input_size, char *output, size_t output_size)
  100. {
  101. uint32_t value;
  102. static char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  103. "abcdefghijklmnopqrstuvwxyz"
  104. "0123456789+/";
  105. if ((input_size/3+1)*4 >= output_size)
  106. {
  107. error("Output buffer for encoding size=%zu is not large enough for %zu-bytes input", output_size, input_size);
  108. return 0;
  109. }
  110. size_t count = 0;
  111. while (input_size>3)
  112. {
  113. value = ((input[0] << 16) + (input[1] << 8) + input[2]) & 0xffffff;
  114. output[0] = lookup[value >> 18];
  115. output[1] = lookup[(value >> 12) & 0x3f];
  116. output[2] = lookup[(value >> 6) & 0x3f];
  117. output[3] = lookup[value & 0x3f];
  118. //error("Base-64 encode (%04x) -> %c %c %c %c\n", value, output[0], output[1], output[2], output[3]);
  119. output += 4;
  120. input += 3;
  121. input_size -= 3;
  122. count += 4;
  123. }
  124. switch (input_size)
  125. {
  126. case 2:
  127. value = (input[0] << 10) + (input[1] << 2);
  128. output[0] = lookup[(value >> 12) & 0x3f];
  129. output[1] = lookup[(value >> 6) & 0x3f];
  130. output[2] = lookup[value & 0x3f];
  131. output[3] = '=';
  132. //error("Base-64 encode (%06x) -> %c %c %c %c\n", (value>>2)&0xffff, output[0], output[1], output[2], output[3]);
  133. count += 4;
  134. break;
  135. case 1:
  136. value = input[0] << 4;
  137. output[0] = lookup[(value >> 6) & 0x3f];
  138. output[1] = lookup[value & 0x3f];
  139. output[2] = '=';
  140. output[3] = '=';
  141. //error("Base-64 encode (%06x) -> %c %c %c %c\n", value, output[0], output[1], output[2], output[3]);
  142. count += 4;
  143. break;
  144. case 0:
  145. break;
  146. }
  147. return count;
  148. }
  149. static int private_decrypt(RSA *p_key, unsigned char * enc_data, int data_len, unsigned char *decrypted)
  150. {
  151. int result = RSA_private_decrypt( data_len, enc_data, decrypted, p_key, RSA_PKCS1_OAEP_PADDING);
  152. if (result == -1) {
  153. char err[512];
  154. ERR_error_string_n(ERR_get_error(), err, sizeof(err));
  155. error("Decryption of the challenge failed: %s", err);
  156. }
  157. return result;
  158. }
  159. static int aclk_https_request(https_req_t *request, https_req_response_t *response) {
  160. int rc;
  161. // wrapper for ACLK only which loads ACLK specific proxy settings
  162. // then only calls https_request
  163. struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .type = MQTT_WSS_DIRECT };
  164. aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
  165. if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) {
  166. request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well
  167. request->proxy_port = proxy_conf.port;
  168. }
  169. rc = https_request(request, response);
  170. freez((char*)proxy_conf.host);
  171. return rc;
  172. }
  173. struct auth_data {
  174. char *client_id;
  175. char *username;
  176. char *passwd;
  177. };
  178. #define PARSE_ENV_JSON_CHK_TYPE(it, type, name) \
  179. if (json_object_get_type(json_object_iter_peek_value(it)) != type) { \
  180. error("value of key \"%s\" should be %s", name, #type); \
  181. goto exit; \
  182. }
  183. #define JSON_KEY_CLIENTID "clientID"
  184. #define JSON_KEY_USER "username"
  185. #define JSON_KEY_PASS "password"
  186. #define JSON_KEY_TOPICS "topics"
  187. static int parse_passwd_response(const char *json_str, struct auth_data *auth) {
  188. int rc = 1;
  189. json_object *json;
  190. struct json_object_iterator it;
  191. struct json_object_iterator itEnd;
  192. json = json_tokener_parse(json_str);
  193. if (!json) {
  194. error("JSON-C failed to parse the payload of http response of /env endpoint");
  195. return 1;
  196. }
  197. it = json_object_iter_begin(json);
  198. itEnd = json_object_iter_end(json);
  199. while (!json_object_iter_equal(&it, &itEnd)) {
  200. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_CLIENTID)) {
  201. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_CLIENTID)
  202. auth->client_id = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  203. json_object_iter_next(&it);
  204. continue;
  205. }
  206. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_USER)) {
  207. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_USER)
  208. auth->username = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  209. json_object_iter_next(&it);
  210. continue;
  211. }
  212. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_PASS)) {
  213. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_PASS)
  214. auth->passwd = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  215. json_object_iter_next(&it);
  216. continue;
  217. }
  218. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_TOPICS)) {
  219. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_array, JSON_KEY_TOPICS)
  220. if (aclk_generate_topic_cache(json_object_iter_peek_value(&it))) {
  221. error("Failed to generate topic cache!");
  222. goto exit;
  223. }
  224. json_object_iter_next(&it);
  225. continue;
  226. }
  227. error("Unknown key \"%s\" in passwd response payload. Ignoring", json_object_iter_peek_name(&it));
  228. json_object_iter_next(&it);
  229. }
  230. if (!auth->client_id) {
  231. error(JSON_KEY_CLIENTID " is compulsory key in /password response");
  232. goto exit;
  233. }
  234. if (!auth->passwd) {
  235. error(JSON_KEY_PASS " is compulsory in /password response");
  236. goto exit;
  237. }
  238. if (!auth->username) {
  239. error(JSON_KEY_USER " is compulsory in /password response");
  240. goto exit;
  241. }
  242. rc = 0;
  243. exit:
  244. json_object_put(json);
  245. return rc;
  246. }
  247. #define JSON_KEY_ERTRY "errorNonRetryable"
  248. #define JSON_KEY_EDELAY "errorRetryDelaySeconds"
  249. #define JSON_KEY_EEC "errorCode"
  250. #define JSON_KEY_EMSGKEY "errorMsgKey"
  251. #define JSON_KEY_EMSG "errorMessage"
  252. #if JSON_C_MINOR_VERSION >= 13
  253. static const char *get_json_str_by_path(json_object *json, const char *path) {
  254. json_object *ptr;
  255. if (json_pointer_get(json, path, &ptr)) {
  256. error("Missing compulsory key \"%s\" in error response", path);
  257. return NULL;
  258. }
  259. if (json_object_get_type(ptr) != json_type_string) {
  260. error("Value of Key \"%s\" in error response should be string", path);
  261. return NULL;
  262. }
  263. return json_object_get_string(ptr);
  264. }
  265. static int aclk_parse_otp_error(const char *json_str) {
  266. int rc = 1;
  267. json_object *json, *ptr;
  268. const char *ec;
  269. const char *ek;
  270. const char *emsg;
  271. int block_retry = -1, backoff = -1;
  272. json = json_tokener_parse(json_str);
  273. if (!json) {
  274. error("JSON-C failed to parse the payload of http response of /env endpoint");
  275. return 1;
  276. }
  277. if ((ec = get_json_str_by_path(json, "/" JSON_KEY_EEC)) == NULL)
  278. goto exit;
  279. if ((ek = get_json_str_by_path(json, "/" JSON_KEY_EMSGKEY)) == NULL)
  280. goto exit;
  281. if ((emsg = get_json_str_by_path(json, "/" JSON_KEY_EMSG)) == NULL)
  282. goto exit;
  283. // optional field
  284. if (!json_pointer_get(json, "/" JSON_KEY_ERTRY, &ptr)) {
  285. if (json_object_get_type(ptr) != json_type_boolean) {
  286. error("Error response Key " "/" JSON_KEY_ERTRY " should be of boolean type");
  287. goto exit;
  288. }
  289. block_retry = json_object_get_boolean(ptr);
  290. }
  291. // optional field
  292. if (!json_pointer_get(json, "/" JSON_KEY_EDELAY, &ptr)) {
  293. if (json_object_get_type(ptr) != json_type_int) {
  294. error("Error response Key " "/" JSON_KEY_EDELAY " should be of integer type");
  295. goto exit;
  296. }
  297. backoff = json_object_get_int(ptr);
  298. }
  299. if (block_retry > 0)
  300. aclk_disable_runtime = 1;
  301. if (backoff > 0)
  302. aclk_block_until = now_monotonic_sec() + backoff;
  303. error("Cloud returned EC=\"%s\", Msg-Key:\"%s\", Msg:\"%s\", BlockRetry:%s, Backoff:%ds (-1 unset by cloud)", ec, ek, emsg, block_retry > 0 ? "true" : "false", backoff);
  304. rc = 0;
  305. exit:
  306. json_object_put(json);
  307. return rc;
  308. }
  309. #else
  310. static int aclk_parse_otp_error(const char *json_str) {
  311. int rc = 1;
  312. int block_retry = -1, backoff = -1;
  313. const char *ec = NULL;
  314. const char *ek = NULL;
  315. const char *emsg = NULL;
  316. json_object *json;
  317. struct json_object_iterator it;
  318. struct json_object_iterator itEnd;
  319. json = json_tokener_parse(json_str);
  320. if (!json) {
  321. error("JSON-C failed to parse the payload of http response of /env endpoint");
  322. return 1;
  323. }
  324. it = json_object_iter_begin(json);
  325. itEnd = json_object_iter_end(json);
  326. while (!json_object_iter_equal(&it, &itEnd)) {
  327. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_EMSG)) {
  328. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_EMSG)
  329. emsg = json_object_get_string(json_object_iter_peek_value(&it));
  330. json_object_iter_next(&it);
  331. continue;
  332. }
  333. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_EMSGKEY)) {
  334. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_EMSGKEY)
  335. ek = json_object_get_string(json_object_iter_peek_value(&it));
  336. json_object_iter_next(&it);
  337. continue;
  338. }
  339. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_EEC)) {
  340. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_EEC)
  341. ec = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  342. json_object_iter_next(&it);
  343. continue;
  344. }
  345. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_EDELAY)) {
  346. if (json_object_get_type(json_object_iter_peek_value(&it)) != json_type_int) {
  347. error("value of key " JSON_KEY_EDELAY " should be integer");
  348. goto exit;
  349. }
  350. backoff = json_object_get_int(json_object_iter_peek_value(&it));
  351. json_object_iter_next(&it);
  352. continue;
  353. }
  354. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_ERTRY)) {
  355. if (json_object_get_type(json_object_iter_peek_value(&it)) != json_type_boolean) {
  356. error("value of key " JSON_KEY_ERTRY " should be integer");
  357. goto exit;
  358. }
  359. block_retry = json_object_get_boolean(json_object_iter_peek_value(&it));
  360. json_object_iter_next(&it);
  361. continue;
  362. }
  363. error("Unknown key \"%s\" in error response payload. Ignoring", json_object_iter_peek_name(&it));
  364. json_object_iter_next(&it);
  365. }
  366. if (block_retry > 0)
  367. aclk_disable_runtime = 1;
  368. if (backoff > 0)
  369. aclk_block_until = now_monotonic_sec() + backoff;
  370. error("Cloud returned EC=\"%s\", Msg-Key:\"%s\", Msg:\"%s\", BlockRetry:%s, Backoff:%ds (-1 unset by cloud)", ec, ek, emsg, block_retry > 0 ? "true" : "false", backoff);
  371. rc = 0;
  372. exit:
  373. json_object_put(json);
  374. return rc;
  375. }
  376. #endif
  377. #define OTP_URL_PREFIX "/api/v1/auth/node/"
  378. int aclk_get_mqtt_otp(RSA *p_key, char **mqtt_id, char **mqtt_usr, char **mqtt_pass, url_t *target) {
  379. // TODO this fnc will be rewritten and simplified in following PRs
  380. // still carries lot of baggage from ACLK Legacy
  381. int rc = 1;
  382. BUFFER *url = buffer_create(strlen(OTP_URL_PREFIX) + UUID_STR_LEN + 20);
  383. https_req_t req = HTTPS_REQ_T_INITIALIZER;
  384. https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
  385. char *agent_id = is_agent_claimed();
  386. if (agent_id == NULL)
  387. {
  388. error("Agent was not claimed - cannot perform challenge/response");
  389. goto cleanup;
  390. }
  391. // GET Challenge
  392. req.host = target->host;
  393. req.port = target->port;
  394. buffer_sprintf(url, "%s/node/%s/challenge", target->path, agent_id);
  395. req.url = url->buffer;
  396. if (aclk_https_request(&req, &resp)) {
  397. error ("ACLK_OTP Challenge failed");
  398. goto cleanup;
  399. }
  400. if (resp.http_code != 200) {
  401. error ("ACLK_OTP Challenge HTTP code not 200 OK (got %d)", resp.http_code);
  402. if (resp.payload_size)
  403. aclk_parse_otp_error(resp.payload);
  404. goto cleanup_resp;
  405. }
  406. info ("ACLK_OTP Got Challenge from Cloud");
  407. struct dictionary_singleton challenge = { .key = "challenge", .result = NULL };
  408. if (json_parse(resp.payload, &challenge, json_extract_singleton) != JSON_OK)
  409. {
  410. freez(challenge.result);
  411. error("Could not parse the the challenge");
  412. goto cleanup_resp;
  413. }
  414. if (challenge.result == NULL) {
  415. error("Could not retrieve challenge JSON key from challenge response");
  416. goto cleanup_resp;
  417. }
  418. // Decrypt the Challenge and Calculate Response
  419. size_t challenge_len = strlen(challenge.result);
  420. unsigned char decoded[512];
  421. size_t decoded_len = base64_decode((unsigned char*)challenge.result, challenge_len, decoded, sizeof(decoded));
  422. freez(challenge.result);
  423. unsigned char plaintext[4096]={};
  424. int decrypted_length = private_decrypt(p_key, decoded, decoded_len, plaintext);
  425. char encoded[512];
  426. size_t encoded_len = base64_encode(plaintext, decrypted_length, encoded, sizeof(encoded));
  427. encoded[encoded_len] = 0;
  428. debug(D_ACLK, "Encoded len=%zu Decryption len=%d: '%s'", encoded_len, decrypted_length, encoded);
  429. char response_json[4096]={};
  430. sprintf(response_json, "{\"response\":\"%s\"}", encoded);
  431. debug(D_ACLK, "Password phase: %s",response_json);
  432. https_req_response_free(&resp);
  433. https_req_response_init(&resp);
  434. // POST password
  435. req.request_type = HTTP_REQ_POST;
  436. buffer_flush(url);
  437. buffer_sprintf(url, "%s/node/%s/password", target->path, agent_id);
  438. req.url = url->buffer;
  439. req.payload = response_json;
  440. req.payload_size = strlen(response_json);
  441. if (aclk_https_request(&req, &resp)) {
  442. error ("ACLK_OTP Password error trying to post result to password");
  443. goto cleanup;
  444. }
  445. if (resp.http_code != 201) {
  446. error ("ACLK_OTP Password HTTP code not 201 Created (got %d)", resp.http_code);
  447. if (resp.payload_size)
  448. aclk_parse_otp_error(resp.payload);
  449. goto cleanup_resp;
  450. }
  451. info ("ACLK_OTP Got Password from Cloud");
  452. struct auth_data data = { .client_id = NULL, .passwd = NULL, .username = NULL };
  453. if (parse_passwd_response(resp.payload, &data)){
  454. error("Error parsing response of password endpoint");
  455. goto cleanup_resp;
  456. }
  457. *mqtt_pass = data.passwd;
  458. *mqtt_usr = data.username;
  459. *mqtt_id = data.client_id;
  460. rc = 0;
  461. cleanup_resp:
  462. https_req_response_free(&resp);
  463. cleanup:
  464. freez(agent_id);
  465. buffer_free(url);
  466. return rc;
  467. }
  468. #define JSON_KEY_ENC "encoding"
  469. #define JSON_KEY_AUTH_ENDPOINT "authEndpoint"
  470. #define JSON_KEY_TRP "transports"
  471. #define JSON_KEY_TRP_TYPE "type"
  472. #define JSON_KEY_TRP_ENDPOINT "endpoint"
  473. #define JSON_KEY_BACKOFF "backoff"
  474. #define JSON_KEY_BACKOFF_BASE "base"
  475. #define JSON_KEY_BACKOFF_MAX "maxSeconds"
  476. #define JSON_KEY_BACKOFF_MIN "minSeconds"
  477. #define JSON_KEY_CAPS "capabilities"
  478. static int parse_json_env_transport(json_object *json, aclk_transport_desc_t *trp) {
  479. struct json_object_iterator it;
  480. struct json_object_iterator itEnd;
  481. it = json_object_iter_begin(json);
  482. itEnd = json_object_iter_end(json);
  483. while (!json_object_iter_equal(&it, &itEnd)) {
  484. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_TRP_TYPE)) {
  485. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_TRP_TYPE)
  486. if (trp->type != ACLK_TRP_UNKNOWN) {
  487. error(JSON_KEY_TRP_TYPE " set already");
  488. goto exit;
  489. }
  490. trp->type = aclk_transport_type_t_from_str(json_object_get_string(json_object_iter_peek_value(&it)));
  491. if (trp->type == ACLK_TRP_UNKNOWN) {
  492. error(JSON_KEY_TRP_TYPE " unknown type \"%s\"", json_object_get_string(json_object_iter_peek_value(&it)));
  493. goto exit;
  494. }
  495. json_object_iter_next(&it);
  496. continue;
  497. }
  498. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_TRP_ENDPOINT)) {
  499. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_TRP_ENDPOINT)
  500. if (trp->endpoint) {
  501. error(JSON_KEY_TRP_ENDPOINT " set already");
  502. goto exit;
  503. }
  504. trp->endpoint = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  505. json_object_iter_next(&it);
  506. continue;
  507. }
  508. error ("unknown JSON key in dictionary (\"%s\")", json_object_iter_peek_name(&it));
  509. json_object_iter_next(&it);
  510. }
  511. if (!trp->endpoint) {
  512. error (JSON_KEY_TRP_ENDPOINT " is missing from JSON dictionary");
  513. goto exit;
  514. }
  515. if (trp->type == ACLK_TRP_UNKNOWN) {
  516. error ("transport type not set");
  517. goto exit;
  518. }
  519. return 0;
  520. exit:
  521. aclk_transport_desc_t_destroy(trp);
  522. return 1;
  523. }
  524. static int parse_json_env_transports(json_object *json_array, aclk_env_t *env) {
  525. aclk_transport_desc_t *trp;
  526. json_object *obj;
  527. if (env->transports) {
  528. error("transports have been set already");
  529. return 1;
  530. }
  531. env->transport_count = json_object_array_length(json_array);
  532. env->transports = callocz(env->transport_count , sizeof(aclk_transport_desc_t *));
  533. for (size_t i = 0; i < env->transport_count; i++) {
  534. trp = callocz(1, sizeof(aclk_transport_desc_t));
  535. obj = json_object_array_get_idx(json_array, i);
  536. if (parse_json_env_transport(obj, trp)) {
  537. error("error parsing transport idx %d", (int)i);
  538. freez(trp);
  539. return 1;
  540. }
  541. env->transports[i] = trp;
  542. }
  543. return 0;
  544. }
  545. #define MATCHED_CORRECT 1
  546. #define MATCHED_ERROR -1
  547. #define NOT_MATCHED 0
  548. static int parse_json_backoff_int(struct json_object_iterator *it, int *out, const char* name, int min, int max) {
  549. if (!strcmp(json_object_iter_peek_name(it), name)) {
  550. if (json_object_get_type(json_object_iter_peek_value(it)) != json_type_int) {
  551. error("Could not parse \"%s\". Not an integer as expected.", name);
  552. return MATCHED_ERROR;
  553. }
  554. *out = json_object_get_int(json_object_iter_peek_value(it));
  555. if (*out < min || *out > max) {
  556. error("Value of \"%s\"=%d out of range (%d-%d).", name, *out, min, max);
  557. return MATCHED_ERROR;
  558. }
  559. return MATCHED_CORRECT;
  560. }
  561. return NOT_MATCHED;
  562. }
  563. static int parse_json_backoff(json_object *json, aclk_backoff_t *backoff) {
  564. struct json_object_iterator it;
  565. struct json_object_iterator itEnd;
  566. int ret;
  567. it = json_object_iter_begin(json);
  568. itEnd = json_object_iter_end(json);
  569. while (!json_object_iter_equal(&it, &itEnd)) {
  570. if ( (ret = parse_json_backoff_int(&it, &backoff->base, JSON_KEY_BACKOFF_BASE, 1, 10)) ) {
  571. if (ret == MATCHED_ERROR) {
  572. return 1;
  573. }
  574. json_object_iter_next(&it);
  575. continue;
  576. }
  577. if ( (ret = parse_json_backoff_int(&it, &backoff->max_s, JSON_KEY_BACKOFF_MAX, 500, INT_MAX)) ) {
  578. if (ret == MATCHED_ERROR) {
  579. return 1;
  580. }
  581. json_object_iter_next(&it);
  582. continue;
  583. }
  584. if ( (ret = parse_json_backoff_int(&it, &backoff->min_s, JSON_KEY_BACKOFF_MIN, 0, INT_MAX)) ) {
  585. if (ret == MATCHED_ERROR) {
  586. return 1;
  587. }
  588. json_object_iter_next(&it);
  589. continue;
  590. }
  591. error ("unknown JSON key in dictionary (\"%s\")", json_object_iter_peek_name(&it));
  592. json_object_iter_next(&it);
  593. }
  594. return 0;
  595. }
  596. static int parse_json_env_caps(json_object *json, aclk_env_t *env) {
  597. json_object *obj;
  598. const char *str;
  599. if (env->capabilities) {
  600. error("transports have been set already");
  601. return 1;
  602. }
  603. env->capability_count = json_object_array_length(json);
  604. // empty capabilities list is allowed
  605. if (!env->capability_count)
  606. return 0;
  607. env->capabilities = callocz(env->capability_count , sizeof(char *));
  608. for (size_t i = 0; i < env->capability_count; i++) {
  609. obj = json_object_array_get_idx(json, i);
  610. if (json_object_get_type(obj) != json_type_string) {
  611. error("Capability at index %d not a string!", (int)i);
  612. return 1;
  613. }
  614. str = json_object_get_string(obj);
  615. if (!str) {
  616. error("Error parsing capabilities");
  617. return 1;
  618. }
  619. env->capabilities[i] = strdupz(str);
  620. }
  621. return 0;
  622. }
  623. static int parse_json_env(const char *json_str, aclk_env_t *env) {
  624. json_object *json;
  625. struct json_object_iterator it;
  626. struct json_object_iterator itEnd;
  627. json = json_tokener_parse(json_str);
  628. if (!json) {
  629. error("JSON-C failed to parse the payload of http response of /env endpoint");
  630. return 1;
  631. }
  632. it = json_object_iter_begin(json);
  633. itEnd = json_object_iter_end(json);
  634. while (!json_object_iter_equal(&it, &itEnd)) {
  635. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_AUTH_ENDPOINT)) {
  636. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_AUTH_ENDPOINT)
  637. if (env->auth_endpoint) {
  638. error("authEndpoint set already");
  639. goto exit;
  640. }
  641. env->auth_endpoint = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
  642. json_object_iter_next(&it);
  643. continue;
  644. }
  645. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_ENC)) {
  646. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_ENC)
  647. if (env->encoding != ACLK_ENC_UNKNOWN) {
  648. error(JSON_KEY_ENC " set already");
  649. goto exit;
  650. }
  651. env->encoding = aclk_encoding_type_t_from_str(json_object_get_string(json_object_iter_peek_value(&it)));
  652. json_object_iter_next(&it);
  653. continue;
  654. }
  655. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_TRP)) {
  656. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_array, JSON_KEY_TRP)
  657. json_object *now = json_object_iter_peek_value(&it);
  658. parse_json_env_transports(now, env);
  659. json_object_iter_next(&it);
  660. continue;
  661. }
  662. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_BACKOFF)) {
  663. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_object, JSON_KEY_BACKOFF)
  664. if (parse_json_backoff(json_object_iter_peek_value(&it), &env->backoff)) {
  665. env->backoff.base = 0;
  666. error("Error parsing Backoff parameters in env");
  667. goto exit;
  668. }
  669. json_object_iter_next(&it);
  670. continue;
  671. }
  672. if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_CAPS)) {
  673. PARSE_ENV_JSON_CHK_TYPE(&it, json_type_array, JSON_KEY_CAPS)
  674. if (parse_json_env_caps(json_object_iter_peek_value(&it), env)) {
  675. error("Error parsing capabilities list");
  676. goto exit;
  677. }
  678. json_object_iter_next(&it);
  679. continue;
  680. }
  681. error ("unknown JSON key in dictionary (\"%s\")", json_object_iter_peek_name(&it));
  682. json_object_iter_next(&it);
  683. }
  684. // Check all compulsory keys have been set
  685. if (env->transport_count < 1) {
  686. error("env has to return at least one transport");
  687. goto exit;
  688. }
  689. if (!env->auth_endpoint) {
  690. error(JSON_KEY_AUTH_ENDPOINT " is compulsory");
  691. goto exit;
  692. }
  693. if (env->encoding == ACLK_ENC_UNKNOWN) {
  694. error(JSON_KEY_ENC " is compulsory");
  695. goto exit;
  696. }
  697. if (!env->backoff.base) {
  698. error(JSON_KEY_BACKOFF " is compulsory");
  699. goto exit;
  700. }
  701. json_object_put(json);
  702. return 0;
  703. exit:
  704. aclk_env_t_destroy(env);
  705. json_object_put(json);
  706. return 1;
  707. }
  708. int aclk_get_env(aclk_env_t *env, const char* aclk_hostname, int aclk_port) {
  709. BUFFER *buf = buffer_create(1024);
  710. https_req_t req = HTTPS_REQ_T_INITIALIZER;
  711. https_req_response_t resp = HTTPS_REQ_RESPONSE_T_INITIALIZER;
  712. req.request_type = HTTP_REQ_GET;
  713. char *agent_id = is_agent_claimed();
  714. if (agent_id == NULL)
  715. {
  716. error("Agent was not claimed - cannot perform challenge/response");
  717. buffer_free(buf);
  718. return 1;
  719. }
  720. #ifdef ENABLE_NEW_CLOUD_PROTOCOL
  721. buffer_sprintf(buf, "/api/v1/env?v=%s&cap=json,proto&claim_id=%s", &(VERSION[1]) /* skip 'v' at beginning */, agent_id);
  722. #else
  723. buffer_sprintf(buf, "/api/v1/env?v=%s&cap=json&claim_id=%s", &(VERSION[1]) /* skip 'v' at beginning */, agent_id);
  724. #endif
  725. freez(agent_id);
  726. req.host = (char*)aclk_hostname;
  727. req.port = aclk_port;
  728. req.url = buf->buffer;
  729. if (aclk_https_request(&req, &resp)) {
  730. error("Error trying to contact env endpoint");
  731. https_req_response_free(&resp);
  732. buffer_free(buf);
  733. return 1;
  734. }
  735. if (resp.http_code != 200) {
  736. error("The HTTP code not 200 OK (Got %d)", resp.http_code);
  737. https_req_response_free(&resp);
  738. buffer_free(buf);
  739. return 1;
  740. }
  741. if (!resp.payload || !resp.payload_size) {
  742. error("Unexpected empty payload as response to /env call");
  743. https_req_response_free(&resp);
  744. buffer_free(buf);
  745. return 1;
  746. }
  747. if (parse_json_env(resp.payload, env)) {
  748. error ("error parsing /env message");
  749. https_req_response_free(&resp);
  750. buffer_free(buf);
  751. return 1;
  752. }
  753. info("Getting Cloud /env successful");
  754. https_req_response_free(&resp);
  755. buffer_free(buf);
  756. return 0;
  757. }