aclk_otp.c 28 KB

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