plugin_rest_credential.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012-2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @author Martin Schanzenbach
  18. * @file credential/plugin_rest_credential.c
  19. * @brief GNUnet CREDENTIAL REST plugin
  20. *
  21. */
  22. #include "platform.h"
  23. #include "gnunet_rest_plugin.h"
  24. #include <gnunet_identity_service.h>
  25. #include <gnunet_gnsrecord_lib.h>
  26. #include <gnunet_namestore_service.h>
  27. #include <gnunet_credential_service.h>
  28. #include <gnunet_rest_lib.h>
  29. #include <gnunet_jsonapi_lib.h>
  30. #include <gnunet_jsonapi_util.h>
  31. #include <jansson.h>
  32. #define GNUNET_REST_API_NS_CREDENTIAL "/credential"
  33. #define GNUNET_REST_API_NS_CREDENTIAL_ISSUE "/credential/issue"
  34. #define GNUNET_REST_API_NS_CREDENTIAL_VERIFY "/credential/verify"
  35. #define GNUNET_REST_API_NS_CREDENTIAL_COLLECT "/credential/collect"
  36. #define GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION "expiration"
  37. #define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY "subject_key"
  38. #define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO "subject"
  39. #define GNUNET_REST_JSONAPI_CREDENTIAL "credential"
  40. #define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential"
  41. #define GNUNET_REST_JSONAPI_DELEGATIONS "delegations"
  42. #define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute"
  43. #define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential"
  44. /**
  45. * @brief struct returned by the initialization function of the plugin
  46. */
  47. struct Plugin
  48. {
  49. const struct GNUNET_CONFIGURATION_Handle *cfg;
  50. };
  51. const struct GNUNET_CONFIGURATION_Handle *cfg;
  52. struct RequestHandle
  53. {
  54. /**
  55. * Handle to Credential service.
  56. */
  57. struct GNUNET_CREDENTIAL_Handle *credential;
  58. /**
  59. * Handle to lookup request
  60. */
  61. struct GNUNET_CREDENTIAL_Request *verify_request;
  62. /**
  63. * Handle to issue request
  64. */
  65. struct GNUNET_CREDENTIAL_Request *issue_request;
  66. /**
  67. * Handle to identity
  68. */
  69. struct GNUNET_IDENTITY_Handle *identity;
  70. /**
  71. * Handle to identity operation
  72. */
  73. struct GNUNET_IDENTITY_Operation *id_op;
  74. /**
  75. * Handle to ego lookup
  76. */
  77. struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
  78. /**
  79. * Handle to rest request
  80. */
  81. struct GNUNET_REST_RequestHandle *rest_handle;
  82. /**
  83. * ID of a task associated with the resolution process.
  84. */
  85. struct GNUNET_SCHEDULER_Task *timeout_task;
  86. /**
  87. * The root of the received JSON or NULL
  88. */
  89. json_t *json_root;
  90. /**
  91. * The plugin result processor
  92. */
  93. GNUNET_REST_ResultProcessor proc;
  94. /**
  95. * The closure of the result processor
  96. */
  97. void *proc_cls;
  98. /**
  99. * The issuer attribute to verify
  100. */
  101. char *issuer_attr;
  102. /**
  103. * The subject attribute
  104. */
  105. char *subject_attr;
  106. /**
  107. * The public key of the issuer
  108. */
  109. struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
  110. /**
  111. * The public key of the subject
  112. */
  113. struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
  114. /**
  115. * HTTP response code
  116. */
  117. int response_code;
  118. /**
  119. * Timeout
  120. */
  121. struct GNUNET_TIME_Relative timeout;
  122. };
  123. /**
  124. * Cleanup lookup handle.
  125. *
  126. * @param handle Handle to clean up
  127. */
  128. static void
  129. cleanup_handle (struct RequestHandle *handle)
  130. {
  131. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  132. "Cleaning up\n");
  133. if (NULL != handle->json_root)
  134. json_decref (handle->json_root);
  135. if (NULL != handle->issuer_attr)
  136. GNUNET_free (handle->issuer_attr);
  137. if (NULL != handle->subject_attr)
  138. GNUNET_free (handle->subject_attr);
  139. if (NULL != handle->verify_request)
  140. GNUNET_CREDENTIAL_request_cancel (handle->verify_request);
  141. if (NULL != handle->credential)
  142. GNUNET_CREDENTIAL_disconnect (handle->credential);
  143. if (NULL != handle->id_op)
  144. GNUNET_IDENTITY_cancel (handle->id_op);
  145. if (NULL != handle->ego_lookup)
  146. GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
  147. if (NULL != handle->identity)
  148. GNUNET_IDENTITY_disconnect (handle->identity);
  149. if (NULL != handle->timeout_task)
  150. {
  151. GNUNET_SCHEDULER_cancel (handle->timeout_task);
  152. }
  153. GNUNET_free (handle);
  154. }
  155. static void
  156. do_error (void *cls)
  157. {
  158. struct RequestHandle *handle = cls;
  159. struct MHD_Response *resp;
  160. resp = GNUNET_REST_create_response (NULL);
  161. handle->proc (handle->proc_cls, resp, handle->response_code);
  162. cleanup_handle (handle);
  163. }
  164. /**
  165. * Attribute delegation to JSON
  166. *
  167. * @param delegation_chain_entry the DSE
  168. * @return JSON, NULL if failed
  169. */
  170. static json_t*
  171. attribute_delegation_to_json (struct
  172. GNUNET_CREDENTIAL_Delegation *
  173. delegation_chain_entry)
  174. {
  175. char *subject;
  176. char *issuer;
  177. json_t *attr_obj;
  178. issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (
  179. &delegation_chain_entry->issuer_key);
  180. if (NULL == issuer)
  181. {
  182. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  183. "Issuer in delegation malformed\n");
  184. return NULL;
  185. }
  186. subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (
  187. &delegation_chain_entry->subject_key);
  188. if (NULL == subject)
  189. {
  190. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  191. "Subject in credential malformed\n");
  192. GNUNET_free (issuer);
  193. return NULL;
  194. }
  195. attr_obj = json_object ();
  196. json_object_set_new (attr_obj, "issuer", json_string (issuer));
  197. json_object_set_new (attr_obj, "issuer_attribute",
  198. json_string (delegation_chain_entry->issuer_attribute));
  199. json_object_set_new (attr_obj, "subject", json_string (subject));
  200. if (0 < delegation_chain_entry->subject_attribute_len)
  201. {
  202. json_object_set_new (attr_obj, "subject_attribute",
  203. json_string (
  204. delegation_chain_entry->subject_attribute));
  205. }
  206. GNUNET_free (issuer);
  207. GNUNET_free (subject);
  208. return attr_obj;
  209. }
  210. /**
  211. * JSONAPI resource to Credential
  212. *
  213. * @param res the JSONAPI resource
  214. * @return the resulting credential, NULL if failed
  215. */
  216. static struct GNUNET_CREDENTIAL_Credential*
  217. json_to_credential (json_t *res)
  218. {
  219. struct GNUNET_CREDENTIAL_Credential *cred;
  220. json_t *tmp;
  221. const char *attribute;
  222. const char *signature;
  223. char *sig;
  224. tmp = json_object_get (res, "attribute");
  225. if (0 == json_is_string (tmp))
  226. {
  227. return NULL;
  228. }
  229. attribute = json_string_value (tmp);
  230. cred = GNUNET_malloc (sizeof(struct GNUNET_CREDENTIAL_Credential)
  231. + strlen (attribute));
  232. cred->issuer_attribute = attribute;
  233. cred->issuer_attribute_len = strlen (attribute);
  234. tmp = json_object_get (res, "issuer");
  235. if (0 == json_is_string (tmp))
  236. {
  237. GNUNET_free (cred);
  238. return NULL;
  239. }
  240. GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value (tmp),
  241. strlen (json_string_value (tmp)),
  242. &cred->issuer_key);
  243. tmp = json_object_get (res, "subject");
  244. if (0 == json_is_string (tmp))
  245. {
  246. GNUNET_free (cred);
  247. return NULL;
  248. }
  249. GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value (tmp),
  250. strlen (json_string_value (tmp)),
  251. &cred->subject_key);
  252. tmp = json_object_get (res, "signature");
  253. if (0 == json_is_string (tmp))
  254. {
  255. GNUNET_free (cred);
  256. return NULL;
  257. }
  258. signature = json_string_value (tmp);
  259. GNUNET_STRINGS_base64_decode (signature,
  260. strlen (signature),
  261. (char**) &sig);
  262. GNUNET_memcpy (&cred->signature,
  263. sig,
  264. sizeof(struct GNUNET_CRYPTO_EcdsaSignature));
  265. GNUNET_free (sig);
  266. tmp = json_object_get (res, "expiration");
  267. if (0 == json_is_integer (tmp))
  268. {
  269. GNUNET_free (cred);
  270. return NULL;
  271. }
  272. cred->expiration.abs_value_us = json_integer_value (tmp);
  273. return cred;
  274. }
  275. /**
  276. * Credential to JSON
  277. *
  278. * @param cred the credential
  279. * @return the resulting json, NULL if failed
  280. */
  281. static json_t*
  282. credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
  283. {
  284. char *issuer;
  285. char *subject;
  286. char *signature;
  287. char attribute[cred->issuer_attribute_len + 1];
  288. json_t *cred_obj;
  289. issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
  290. if (NULL == issuer)
  291. {
  292. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  293. "Issuer in credential malformed\n");
  294. return NULL;
  295. }
  296. subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
  297. if (NULL == subject)
  298. {
  299. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  300. "Subject in credential malformed\n");
  301. GNUNET_free (issuer);
  302. return NULL;
  303. }
  304. GNUNET_STRINGS_base64_encode ((char*) &cred->signature,
  305. sizeof(struct GNUNET_CRYPTO_EcdsaSignature),
  306. &signature);
  307. GNUNET_memcpy (attribute,
  308. cred->issuer_attribute,
  309. cred->issuer_attribute_len);
  310. attribute[cred->issuer_attribute_len] = '\0';
  311. cred_obj = json_object ();
  312. json_object_set_new (cred_obj, "issuer", json_string (issuer));
  313. json_object_set_new (cred_obj, "subject", json_string (subject));
  314. json_object_set_new (cred_obj, "attribute", json_string (attribute));
  315. json_object_set_new (cred_obj, "signature", json_string (signature));
  316. json_object_set_new (cred_obj, "expiration", json_integer (
  317. cred->expiration.abs_value_us));
  318. GNUNET_free (issuer);
  319. GNUNET_free (subject);
  320. GNUNET_free (signature);
  321. return cred_obj;
  322. }
  323. static void
  324. handle_collect_response (void *cls,
  325. unsigned int d_count,
  326. struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
  327. unsigned int c_count,
  328. struct GNUNET_CREDENTIAL_Credential *cred)
  329. {
  330. struct RequestHandle *handle = cls;
  331. struct MHD_Response *resp;
  332. struct GNUNET_JSONAPI_Document *json_document;
  333. struct GNUNET_JSONAPI_Resource *json_resource;
  334. json_t *cred_obj;
  335. json_t *cred_array;
  336. char *result;
  337. char *issuer;
  338. char *id;
  339. uint32_t i;
  340. handle->verify_request = NULL;
  341. if (NULL == cred)
  342. {
  343. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  344. "Verify failed.\n");
  345. handle->response_code = MHD_HTTP_NOT_FOUND;
  346. GNUNET_SCHEDULER_add_now (&do_error, handle);
  347. return;
  348. }
  349. issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
  350. if (NULL == issuer)
  351. {
  352. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  353. "Issuer in delegation malformed\n");
  354. return;
  355. }
  356. GNUNET_asprintf (&id,
  357. "%s.%s",
  358. issuer,
  359. handle->issuer_attr);
  360. GNUNET_free (issuer);
  361. json_document = GNUNET_JSONAPI_document_new ();
  362. json_resource = GNUNET_JSONAPI_resource_new (
  363. GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
  364. id);
  365. GNUNET_free (id);
  366. cred_array = json_array ();
  367. for (i = 0; i < c_count; i++)
  368. {
  369. cred_obj = credential_to_json (&cred[i]);
  370. json_array_append_new (cred_array, cred_obj);
  371. }
  372. GNUNET_JSONAPI_resource_add_attr (json_resource,
  373. GNUNET_REST_JSONAPI_CREDENTIAL,
  374. cred_array);
  375. GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
  376. GNUNET_JSONAPI_document_serialize (json_document, &result);
  377. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  378. "Result %s\n",
  379. result);
  380. json_decref (cred_array);
  381. GNUNET_JSONAPI_document_delete (json_document);
  382. resp = GNUNET_REST_create_response (result);
  383. GNUNET_free (result);
  384. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  385. cleanup_handle (handle);
  386. }
  387. static void
  388. subject_ego_lookup (void *cls,
  389. const struct GNUNET_IDENTITY_Ego *ego)
  390. {
  391. struct RequestHandle *handle = cls;
  392. const struct GNUNET_CRYPTO_EcdsaPrivateKey *sub_key;
  393. handle->ego_lookup = NULL;
  394. if (NULL == ego)
  395. {
  396. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  397. "Subject not found\n");
  398. GNUNET_SCHEDULER_add_now (&do_error, handle);
  399. return;
  400. }
  401. sub_key = GNUNET_IDENTITY_ego_get_private_key (ego);
  402. handle->verify_request = GNUNET_CREDENTIAL_collect (handle->credential,
  403. &handle->issuer_key,
  404. handle->issuer_attr,
  405. sub_key,
  406. &handle_collect_response,
  407. handle);
  408. }
  409. static void
  410. handle_verify_response (void *cls,
  411. unsigned int d_count,
  412. struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
  413. unsigned int c_count,
  414. struct GNUNET_CREDENTIAL_Credential *cred)
  415. {
  416. struct RequestHandle *handle = cls;
  417. struct MHD_Response *resp;
  418. struct GNUNET_JSONAPI_Document *json_document;
  419. struct GNUNET_JSONAPI_Resource *json_resource;
  420. json_t *cred_obj;
  421. json_t *attr_obj;
  422. json_t *cred_array;
  423. json_t *attr_array;
  424. char *result;
  425. char *issuer;
  426. char *id;
  427. uint32_t i;
  428. handle->verify_request = NULL;
  429. if (NULL == cred)
  430. {
  431. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  432. "Verify failed.\n");
  433. handle->response_code = MHD_HTTP_NOT_FOUND;
  434. GNUNET_SCHEDULER_add_now (&do_error, handle);
  435. return;
  436. }
  437. issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
  438. if (NULL == issuer)
  439. {
  440. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  441. "Issuer in delegation malformed\n");
  442. return;
  443. }
  444. GNUNET_asprintf (&id,
  445. "%s.%s",
  446. issuer,
  447. handle->issuer_attr);
  448. GNUNET_free (issuer);
  449. json_document = GNUNET_JSONAPI_document_new ();
  450. json_resource = GNUNET_JSONAPI_resource_new (
  451. GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
  452. id);
  453. GNUNET_free (id);
  454. attr_array = json_array ();
  455. for (i = 0; i < d_count; i++)
  456. {
  457. attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
  458. json_array_append_new (attr_array, attr_obj);
  459. }
  460. cred_array = json_array ();
  461. for (i = 0; i < c_count; i++)
  462. {
  463. cred_obj = credential_to_json (&cred[i]);
  464. json_array_append_new (cred_array, cred_obj);
  465. }
  466. GNUNET_JSONAPI_resource_add_attr (json_resource,
  467. GNUNET_REST_JSONAPI_CREDENTIAL,
  468. cred_array);
  469. GNUNET_JSONAPI_resource_add_attr (json_resource,
  470. GNUNET_REST_JSONAPI_DELEGATIONS,
  471. attr_array);
  472. GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
  473. GNUNET_JSONAPI_document_serialize (json_document, &result);
  474. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  475. "Result %s\n",
  476. result);
  477. json_decref (attr_array);
  478. json_decref (cred_array);
  479. GNUNET_JSONAPI_document_delete (json_document);
  480. resp = GNUNET_REST_create_response (result);
  481. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  482. GNUNET_free (result);
  483. cleanup_handle (handle);
  484. }
  485. static void
  486. collect_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
  487. const char*url,
  488. void *cls)
  489. {
  490. struct RequestHandle *handle = cls;
  491. struct GNUNET_HashCode key;
  492. char *tmp;
  493. char *entity_attr;
  494. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  495. "Connecting...\n");
  496. handle->credential = GNUNET_CREDENTIAL_connect (cfg);
  497. handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
  498. &do_error, handle);
  499. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  500. "Connected\n");
  501. if (NULL == handle->credential)
  502. {
  503. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  504. "Connecting to CREDENTIAL failed\n");
  505. GNUNET_SCHEDULER_add_now (&do_error, handle);
  506. return;
  507. }
  508. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
  509. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
  510. &key);
  511. if (GNUNET_NO ==
  512. GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
  513. &key))
  514. {
  515. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  516. "Missing issuer attribute\n");
  517. GNUNET_SCHEDULER_add_now (&do_error, handle);
  518. return;
  519. }
  520. tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
  521. &key);
  522. entity_attr = GNUNET_strdup (tmp);
  523. tmp = strtok (entity_attr, ".");
  524. if (NULL == tmp)
  525. {
  526. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  527. "Malformed issuer or attribute\n");
  528. GNUNET_free (entity_attr);
  529. GNUNET_SCHEDULER_add_now (&do_error, handle);
  530. return;
  531. }
  532. if (GNUNET_OK !=
  533. GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
  534. strlen (tmp),
  535. &handle->issuer_key))
  536. {
  537. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  538. "Malformed issuer key\n");
  539. GNUNET_free (entity_attr);
  540. GNUNET_SCHEDULER_add_now (&do_error, handle);
  541. return;
  542. }
  543. tmp = strtok (NULL, "."); // Issuer attribute
  544. if (NULL == tmp)
  545. {
  546. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  547. "Malformed attribute\n");
  548. GNUNET_free (entity_attr);
  549. GNUNET_SCHEDULER_add_now (&do_error, handle);
  550. return;
  551. }
  552. handle->issuer_attr = GNUNET_strdup (tmp);
  553. GNUNET_free (entity_attr);
  554. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO,
  555. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO),
  556. &key);
  557. if (GNUNET_NO ==
  558. GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
  559. &key))
  560. {
  561. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  562. "Missing subject\n");
  563. GNUNET_SCHEDULER_add_now (&do_error, handle);
  564. return;
  565. }
  566. tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
  567. &key);
  568. if (NULL == tmp)
  569. {
  570. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  571. "Malformed subject\n");
  572. GNUNET_SCHEDULER_add_now (&do_error, handle);
  573. return;
  574. }
  575. handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
  576. tmp,
  577. &subject_ego_lookup,
  578. handle);
  579. }
  580. static void
  581. verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
  582. const char*url,
  583. void *cls)
  584. {
  585. struct RequestHandle *handle = cls;
  586. struct GNUNET_HashCode key;
  587. struct GNUNET_JSONAPI_Document *json_obj;
  588. struct GNUNET_JSONAPI_Resource *res;
  589. struct GNUNET_CREDENTIAL_Credential *cred;
  590. char *tmp;
  591. char *entity_attr;
  592. int i;
  593. uint32_t credential_count;
  594. uint32_t resource_count;
  595. json_t *cred_json;
  596. json_t *data_js;
  597. json_error_t err;
  598. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  599. "Connecting...\n");
  600. handle->credential = GNUNET_CREDENTIAL_connect (cfg);
  601. handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
  602. &do_error, handle);
  603. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  604. "Connected\n");
  605. if (NULL == handle->credential)
  606. {
  607. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  608. "Connecting to CREDENTIAL failed\n");
  609. GNUNET_SCHEDULER_add_now (&do_error, handle);
  610. return;
  611. }
  612. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
  613. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
  614. &key);
  615. if (GNUNET_NO ==
  616. GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
  617. &key))
  618. {
  619. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  620. "Missing issuer attribute\n");
  621. GNUNET_SCHEDULER_add_now (&do_error, handle);
  622. return;
  623. }
  624. tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
  625. &key);
  626. entity_attr = GNUNET_strdup (tmp);
  627. tmp = strtok (entity_attr, ".");
  628. if (NULL == tmp)
  629. {
  630. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  631. "Malformed issuer or attribute\n");
  632. GNUNET_free (entity_attr);
  633. GNUNET_SCHEDULER_add_now (&do_error, handle);
  634. return;
  635. }
  636. if (GNUNET_OK !=
  637. GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
  638. strlen (tmp),
  639. &handle->issuer_key))
  640. {
  641. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  642. "Malformed issuer key\n");
  643. GNUNET_free (entity_attr);
  644. GNUNET_SCHEDULER_add_now (&do_error, handle);
  645. return;
  646. }
  647. tmp = strtok (NULL, "."); // Issuer attribute
  648. if (NULL == tmp)
  649. {
  650. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  651. "Malformed attribute\n");
  652. GNUNET_free (entity_attr);
  653. GNUNET_SCHEDULER_add_now (&do_error, handle);
  654. return;
  655. }
  656. handle->issuer_attr = GNUNET_strdup (tmp);
  657. GNUNET_free (entity_attr);
  658. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
  659. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
  660. &key);
  661. if (GNUNET_NO ==
  662. GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
  663. &key))
  664. {
  665. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  666. "Missing subject key\n");
  667. GNUNET_SCHEDULER_add_now (&do_error, handle);
  668. return;
  669. }
  670. tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
  671. &key);
  672. if (NULL == tmp)
  673. {
  674. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  675. "Malformed subject\n");
  676. GNUNET_SCHEDULER_add_now (&do_error, handle);
  677. return;
  678. }
  679. if (GNUNET_OK !=
  680. GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
  681. strlen (tmp),
  682. &handle->subject_key))
  683. {
  684. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  685. "Malformed subject key\n");
  686. GNUNET_SCHEDULER_add_now (&do_error, handle);
  687. return;
  688. }
  689. if (0 >= handle->rest_handle->data_size)
  690. {
  691. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  692. "Missing credentials\n");
  693. GNUNET_SCHEDULER_add_now (&do_error, handle);
  694. return;
  695. }
  696. struct GNUNET_JSON_Specification docspec[] = {
  697. GNUNET_JSON_spec_jsonapi_document (&json_obj),
  698. GNUNET_JSON_spec_end ()
  699. };
  700. char term_data[handle->rest_handle->data_size + 1];
  701. term_data[handle->rest_handle->data_size] = '\0';
  702. credential_count = 0;
  703. GNUNET_memcpy (term_data,
  704. handle->rest_handle->data,
  705. handle->rest_handle->data_size);
  706. data_js = json_loads (term_data,
  707. JSON_DECODE_ANY,
  708. &err);
  709. GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (data_js, docspec,
  710. NULL, NULL));
  711. json_decref (data_js);
  712. if (NULL == json_obj)
  713. {
  714. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  715. "Unable to parse JSONAPI Object from %s\n",
  716. term_data);
  717. GNUNET_SCHEDULER_add_now (&do_error, handle);
  718. return;
  719. }
  720. resource_count = GNUNET_JSONAPI_document_resource_count (json_obj);
  721. GNUNET_assert (1 == resource_count);
  722. res = (GNUNET_JSONAPI_document_get_resource (json_obj, 0));
  723. if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (res,
  724. GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO))
  725. {
  726. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  727. "Resource not a credential!\n");
  728. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  729. "Unable to parse JSONAPI Object from %s\n",
  730. term_data);
  731. GNUNET_JSONAPI_document_delete (json_obj);
  732. GNUNET_SCHEDULER_add_now (&do_error, handle);
  733. return;
  734. }
  735. cred_json = GNUNET_JSONAPI_resource_read_attr (res,
  736. GNUNET_REST_JSONAPI_CREDENTIAL);
  737. GNUNET_assert (json_is_array (cred_json));
  738. credential_count = json_array_size (cred_json);
  739. struct GNUNET_CREDENTIAL_Credential credentials[credential_count];
  740. for (i = 0; i < credential_count; i++)
  741. {
  742. cred = json_to_credential (json_array_get (cred_json, i));
  743. if (NULL == cred)
  744. {
  745. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  746. "Unable to parse credential!\n");
  747. continue;
  748. }
  749. GNUNET_memcpy (&credentials[i],
  750. cred,
  751. sizeof(struct GNUNET_CREDENTIAL_Credential));
  752. credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
  753. GNUNET_free (cred);
  754. }
  755. GNUNET_JSONAPI_document_delete (json_obj);
  756. handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
  757. &handle->issuer_key,
  758. handle->issuer_attr,
  759. &handle->subject_key,
  760. credential_count,
  761. credentials,
  762. &handle_verify_response,
  763. handle);
  764. for (i = 0; i < credential_count; i++)
  765. GNUNET_free ((char*) credentials[i].issuer_attribute);
  766. }
  767. void
  768. send_cred_response (struct RequestHandle *handle,
  769. struct GNUNET_CREDENTIAL_Credential *cred)
  770. {
  771. struct MHD_Response *resp;
  772. struct GNUNET_JSONAPI_Document *json_document;
  773. struct GNUNET_JSONAPI_Resource *json_resource;
  774. json_t *cred_obj;
  775. char *result;
  776. char *issuer;
  777. char *subject;
  778. char *signature;
  779. char *id;
  780. GNUNET_assert (NULL != cred);
  781. issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
  782. if (NULL == issuer)
  783. {
  784. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  785. "Subject malformed\n");
  786. GNUNET_free (issuer);
  787. return;
  788. }
  789. GNUNET_asprintf (&id,
  790. "%s.%s",
  791. issuer,
  792. (char*) &cred[1]);
  793. subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
  794. if (NULL == subject)
  795. {
  796. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  797. "Subject malformed\n");
  798. GNUNET_free (id);
  799. GNUNET_free (issuer);
  800. return;
  801. }
  802. GNUNET_STRINGS_base64_encode ((char*) &cred->signature,
  803. sizeof(struct GNUNET_CRYPTO_EcdsaSignature),
  804. &signature);
  805. json_document = GNUNET_JSONAPI_document_new ();
  806. json_resource = GNUNET_JSONAPI_resource_new (
  807. GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
  808. id);
  809. GNUNET_free (id);
  810. cred_obj = json_object ();
  811. json_object_set_new (cred_obj, "issuer", json_string (issuer));
  812. json_object_set_new (cred_obj, "subject", json_string (subject));
  813. json_object_set_new (cred_obj, "expiration", json_integer (
  814. cred->expiration.abs_value_us));
  815. json_object_set_new (cred_obj, "signature", json_string (signature));
  816. GNUNET_JSONAPI_resource_add_attr (json_resource,
  817. GNUNET_REST_JSONAPI_CREDENTIAL,
  818. cred_obj);
  819. GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
  820. GNUNET_JSONAPI_document_serialize (json_document, &result);
  821. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  822. "Result %s\n",
  823. result);
  824. json_decref (cred_obj);
  825. GNUNET_JSONAPI_document_delete (json_document);
  826. resp = GNUNET_REST_create_response (result);
  827. handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
  828. GNUNET_free (result);
  829. GNUNET_free (signature);
  830. GNUNET_free (issuer);
  831. GNUNET_free (subject);
  832. cleanup_handle (handle);
  833. }
  834. void
  835. get_cred_issuer_cb (void *cls,
  836. struct GNUNET_IDENTITY_Ego *ego,
  837. void **ctx,
  838. const char *name)
  839. {
  840. struct RequestHandle *handle = cls;
  841. struct GNUNET_TIME_Absolute etime_abs;
  842. struct GNUNET_TIME_Relative etime_rel;
  843. const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key;
  844. struct GNUNET_HashCode key;
  845. struct GNUNET_CREDENTIAL_Credential *cred;
  846. char*expiration_str;
  847. char*tmp;
  848. handle->id_op = NULL;
  849. if (NULL == name)
  850. {
  851. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  852. "Issuer not configured!\n");
  853. GNUNET_SCHEDULER_add_now (&do_error, handle);
  854. return;
  855. }
  856. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  857. "Connecting to credential service...\n");
  858. handle->credential = GNUNET_CREDENTIAL_connect (cfg);
  859. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  860. "Connected\n");
  861. if (NULL == handle->credential)
  862. {
  863. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  864. "Connecting to CREDENTIAL failed\n");
  865. GNUNET_SCHEDULER_add_now (&do_error, handle);
  866. return;
  867. }
  868. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION,
  869. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION),
  870. &key);
  871. if (GNUNET_NO ==
  872. GNUNET_CONTAINER_multihashmap_contains (
  873. handle->rest_handle->url_param_map,
  874. &key))
  875. {
  876. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  877. "Missing expiration\n");
  878. GNUNET_SCHEDULER_add_now (&do_error, handle);
  879. return;
  880. }
  881. expiration_str = GNUNET_CONTAINER_multihashmap_get (
  882. handle->rest_handle->url_param_map,
  883. &key);
  884. if (NULL == expiration_str)
  885. {
  886. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  887. "Expiration malformed\n");
  888. GNUNET_SCHEDULER_add_now (&do_error, handle);
  889. return;
  890. }
  891. if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str,
  892. &etime_rel))
  893. {
  894. etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
  895. }
  896. else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str,
  897. &etime_abs))
  898. {
  899. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  900. "Malformed expiration: %s\n", expiration_str);
  901. GNUNET_SCHEDULER_add_now (&do_error, handle);
  902. return;
  903. }
  904. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
  905. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
  906. &key);
  907. if (GNUNET_NO ==
  908. GNUNET_CONTAINER_multihashmap_contains (
  909. handle->rest_handle->url_param_map,
  910. &key))
  911. {
  912. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  913. "Missing issuer attribute\n");
  914. GNUNET_SCHEDULER_add_now (&do_error, handle);
  915. return;
  916. }
  917. handle->issuer_attr = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get
  918. (handle->rest_handle->url_param_map,
  919. &key));
  920. GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
  921. strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
  922. &key);
  923. if (GNUNET_NO ==
  924. GNUNET_CONTAINER_multihashmap_contains (
  925. handle->rest_handle->url_param_map,
  926. &key))
  927. {
  928. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  929. "Missing subject\n");
  930. GNUNET_SCHEDULER_add_now (&do_error, handle);
  931. return;
  932. }
  933. tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
  934. &key);
  935. if (NULL == tmp)
  936. {
  937. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  938. "Malformed subject\n");
  939. GNUNET_SCHEDULER_add_now (&do_error, handle);
  940. return;
  941. }
  942. if (GNUNET_OK !=
  943. GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
  944. strlen (tmp),
  945. &handle->subject_key))
  946. {
  947. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  948. "Malformed subject key\n");
  949. GNUNET_SCHEDULER_add_now (&do_error, handle);
  950. return;
  951. }
  952. issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego);
  953. cred = GNUNET_CREDENTIAL_credential_issue (issuer_key,
  954. &handle->subject_key,
  955. handle->issuer_attr,
  956. &etime_abs);
  957. if (NULL == cred)
  958. {
  959. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  960. "Failed to create credential\n");
  961. GNUNET_SCHEDULER_add_now (&do_error, handle);
  962. return;
  963. }
  964. send_cred_response (handle, cred);
  965. }
  966. static void
  967. issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
  968. const char*url,
  969. void *cls)
  970. {
  971. struct RequestHandle *handle = cls;
  972. handle->identity = GNUNET_IDENTITY_connect (cfg,
  973. NULL,
  974. NULL);
  975. handle->id_op = GNUNET_IDENTITY_get (handle->identity,
  976. "credential-issuer",
  977. &get_cred_issuer_cb,
  978. handle);
  979. handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
  980. &do_error,
  981. handle);
  982. }
  983. static void
  984. options_cont (struct GNUNET_REST_RequestHandle *con_handle,
  985. const char*url,
  986. void *cls)
  987. {
  988. struct MHD_Response *resp;
  989. struct RequestHandle *handle = cls;
  990. // For GNS, independent of path return all options
  991. resp = GNUNET_REST_create_response (NULL);
  992. MHD_add_response_header (resp,
  993. "Access-Control-Allow-Methods",
  994. MHD_HTTP_METHOD_GET);
  995. handle->proc (handle->proc_cls,
  996. resp,
  997. MHD_HTTP_OK);
  998. cleanup_handle (handle);
  999. }
  1000. static void
  1001. rest_credential_process_request (struct
  1002. GNUNET_REST_RequestHandle *conndata_handle,
  1003. GNUNET_REST_ResultProcessor proc,
  1004. void *proc_cls)
  1005. {
  1006. struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
  1007. struct GNUNET_REST_RequestHandlerError err;
  1008. handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
  1009. handle->proc_cls = proc_cls;
  1010. handle->proc = proc;
  1011. handle->rest_handle = conndata_handle;
  1012. static const struct GNUNET_REST_RequestHandler handlers[] = {
  1013. { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CREDENTIAL_VERIFY,
  1014. &verify_cred_cont },
  1015. { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_COLLECT,
  1016. &collect_cred_cont },
  1017. { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE,
  1018. &issue_cred_cont },
  1019. { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont },
  1020. GNUNET_REST_HANDLER_END
  1021. };
  1022. if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
  1023. handlers,
  1024. &err,
  1025. handle))
  1026. {
  1027. handle->response_code = err.error_code;
  1028. GNUNET_SCHEDULER_add_now (&do_error, handle);
  1029. }
  1030. }
  1031. /**
  1032. * Entry point for the plugin.
  1033. *
  1034. * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
  1035. * @return NULL on error, otherwise the plugin context
  1036. */
  1037. void *
  1038. libgnunet_plugin_rest_credential_init (void *cls)
  1039. {
  1040. static struct Plugin plugin;
  1041. cfg = cls;
  1042. struct GNUNET_REST_Plugin *api;
  1043. if (NULL != plugin.cfg)
  1044. return NULL; /* can only initialize once! */
  1045. memset (&plugin, 0, sizeof(struct Plugin));
  1046. plugin.cfg = cfg;
  1047. api = GNUNET_new (struct GNUNET_REST_Plugin);
  1048. api->cls = &plugin;
  1049. api->name = GNUNET_REST_API_NS_CREDENTIAL;
  1050. api->process_request = &rest_credential_process_request;
  1051. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  1052. _ ("GNS REST API initialized\n"));
  1053. return api;
  1054. }
  1055. /**
  1056. * Exit point from the plugin.
  1057. *
  1058. * @param cls the plugin context (as returned by "init")
  1059. * @return always NULL
  1060. */
  1061. void *
  1062. libgnunet_plugin_rest_credential_done (void *cls)
  1063. {
  1064. struct GNUNET_REST_Plugin *api = cls;
  1065. struct Plugin *plugin = api->cls;
  1066. plugin->cfg = NULL;
  1067. GNUNET_free (api);
  1068. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  1069. "GNS REST plugin is finished\n");
  1070. return NULL;
  1071. }
  1072. /* end of plugin_rest_gns.c */