gnunet-credential.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012-2013 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. * @file gnunet-credential.c
  18. * @brief command line tool to access command line Credential service
  19. * @author Martin Schanzenbach
  20. */
  21. #include "platform.h"
  22. #include <gnunet_util_lib.h>
  23. #include <gnunet_credential_service.h>
  24. #include <gnunet_gnsrecord_lib.h>
  25. #include "credential_misc.h"
  26. #include "credential_serialization.h"
  27. /**
  28. * Configuration we are using.
  29. */
  30. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  31. /**
  32. * EgoLookup
  33. */
  34. static struct GNUNET_IDENTITY_EgoLookup *el;
  35. /**
  36. * Handle to Credential service.
  37. */
  38. static struct GNUNET_CREDENTIAL_Handle *credential;
  39. /**
  40. * Desired timeout for the lookup (default is no timeout).
  41. */
  42. static struct GNUNET_TIME_Relative timeout;
  43. /**
  44. * Handle to verify request
  45. */
  46. static struct GNUNET_CREDENTIAL_Request *verify_request;
  47. /**
  48. * Handle to collect request
  49. */
  50. static struct GNUNET_CREDENTIAL_Request *collect_request;
  51. /**
  52. * Task scheduled to handle timeout.
  53. */
  54. static struct GNUNET_SCHEDULER_Task *tt;
  55. /**
  56. * Subject pubkey string
  57. */
  58. static char *subject_key;
  59. /**
  60. * Subject credential string
  61. */
  62. static char *subject_credential;
  63. /**
  64. * Credential TTL
  65. */
  66. static char *expiration;
  67. /**
  68. * Subject key
  69. */
  70. struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
  71. /**
  72. * Issuer key
  73. */
  74. struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
  75. /**
  76. * Issuer pubkey string
  77. */
  78. static char *issuer_key;
  79. /**
  80. * ego
  81. */
  82. static char *ego_name;
  83. /**
  84. * Issuer attribute
  85. */
  86. static char *issuer_attr;
  87. /**
  88. * Verify mode
  89. */
  90. static int verify;
  91. /**
  92. * Issue mode
  93. */
  94. static int create_cred;
  95. /**
  96. * Collect mode
  97. */
  98. static int collect;
  99. /**
  100. * Task run on shutdown. Cleans up everything.
  101. *
  102. * @param cls unused
  103. */
  104. static void
  105. do_shutdown (void *cls)
  106. {
  107. if (NULL != verify_request)
  108. {
  109. GNUNET_CREDENTIAL_request_cancel (verify_request);
  110. verify_request = NULL;
  111. }
  112. if (NULL != credential)
  113. {
  114. GNUNET_CREDENTIAL_disconnect (credential);
  115. credential = NULL;
  116. }
  117. if (NULL != tt)
  118. {
  119. GNUNET_SCHEDULER_cancel (tt);
  120. tt = NULL;
  121. }
  122. }
  123. /**
  124. * Task run on timeout. Triggers shutdown.
  125. *
  126. * @param cls unused
  127. */
  128. static void
  129. do_timeout (void *cls)
  130. {
  131. tt = NULL;
  132. GNUNET_SCHEDULER_shutdown ();
  133. }
  134. static void
  135. handle_collect_result (void *cls,
  136. unsigned int d_count,
  137. struct GNUNET_CREDENTIAL_Delegation *dc,
  138. unsigned int c_count,
  139. struct GNUNET_CREDENTIAL_Credential *cred)
  140. {
  141. int i;
  142. char* line;
  143. verify_request = NULL;
  144. if (NULL != cred)
  145. {
  146. for (i=0;i<c_count;i++)
  147. {
  148. line = GNUNET_CREDENTIAL_credential_to_string (&cred[i]);
  149. printf ("%s\n",
  150. line);
  151. GNUNET_free (line);
  152. }
  153. }
  154. GNUNET_SCHEDULER_shutdown ();
  155. }
  156. static void
  157. handle_verify_result (void *cls,
  158. unsigned int d_count,
  159. struct GNUNET_CREDENTIAL_Delegation *dc,
  160. unsigned int c_count,
  161. struct GNUNET_CREDENTIAL_Credential *cred)
  162. {
  163. int i;
  164. char* iss_key;
  165. char* sub_key;
  166. verify_request = NULL;
  167. if (NULL == cred)
  168. printf ("Failed.\n");
  169. else
  170. {
  171. printf("Delegation Chain:\n");
  172. for (i=0;i<d_count;i++)
  173. {
  174. iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key);
  175. sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key);
  176. if (0 != dc[i].subject_attribute_len)
  177. {
  178. printf ("(%d) %s.%s <- %s.%s\n", i,
  179. iss_key, dc[i].issuer_attribute,
  180. sub_key, dc[i].subject_attribute);
  181. } else {
  182. printf ("(%d) %s.%s <- %s\n", i,
  183. iss_key, dc[i].issuer_attribute,
  184. sub_key);
  185. }
  186. GNUNET_free (iss_key);
  187. GNUNET_free (sub_key);
  188. }
  189. printf("\nCredentials:\n");
  190. for (i=0;i<c_count;i++)
  191. {
  192. iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key);
  193. sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key);
  194. printf ("%s.%s <- %s\n",
  195. iss_key, cred[i].issuer_attribute,
  196. sub_key);
  197. GNUNET_free (iss_key);
  198. GNUNET_free (sub_key);
  199. }
  200. printf ("Successful.\n");
  201. }
  202. GNUNET_SCHEDULER_shutdown ();
  203. }
  204. /**
  205. * Callback invoked from identity service with ego information.
  206. * An @a ego of NULL means the ego was not found.
  207. *
  208. * @param cls closure with the configuration
  209. * @param ego an ego known to identity service, or NULL
  210. */
  211. static void
  212. identity_cb (void *cls,
  213. const struct GNUNET_IDENTITY_Ego *ego)
  214. {
  215. const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
  216. struct GNUNET_CREDENTIAL_Credential *crd;
  217. struct GNUNET_TIME_Absolute etime_abs;
  218. struct GNUNET_TIME_Relative etime_rel;
  219. char *res;
  220. el = NULL;
  221. if (NULL == ego)
  222. {
  223. if (NULL != ego_name)
  224. {
  225. fprintf (stderr,
  226. _("Ego `%s' not known to identity service\n"),
  227. ego_name);
  228. }
  229. GNUNET_SCHEDULER_shutdown ();
  230. return;
  231. }
  232. if (GNUNET_YES == collect)
  233. {
  234. if (GNUNET_OK !=
  235. GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
  236. strlen (issuer_key),
  237. &issuer_pkey))
  238. {
  239. fprintf (stderr,
  240. _("Issuer public key `%s' is not well-formed\n"),
  241. issuer_key);
  242. GNUNET_SCHEDULER_shutdown ();
  243. }
  244. privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
  245. collect_request = GNUNET_CREDENTIAL_collect(credential,
  246. &issuer_pkey,
  247. issuer_attr, //TODO argument
  248. privkey,
  249. &handle_collect_result,
  250. NULL);
  251. return;
  252. }
  253. //Else issue
  254. if (NULL == expiration)
  255. {
  256. fprintf (stderr,
  257. "Please specify a TTL\n");
  258. GNUNET_SCHEDULER_shutdown ();
  259. return;
  260. } else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration,
  261. &etime_rel))
  262. {
  263. etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
  264. } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration,
  265. &etime_abs))
  266. {
  267. fprintf (stderr,
  268. "%s is not a valid ttl!\n",
  269. expiration);
  270. GNUNET_SCHEDULER_shutdown ();
  271. return;
  272. }
  273. privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
  274. GNUNET_free_non_null (ego_name);
  275. ego_name = NULL;
  276. crd = GNUNET_CREDENTIAL_credential_issue (privkey,
  277. &subject_pkey,
  278. issuer_attr,
  279. &etime_abs);
  280. res = GNUNET_CREDENTIAL_credential_to_string (crd);
  281. GNUNET_free (crd);
  282. printf ("%s\n", res);
  283. GNUNET_SCHEDULER_shutdown ();
  284. }
  285. /**
  286. * Main function that will be run.
  287. *
  288. * @param cls closure
  289. * @param args remaining command-line arguments
  290. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  291. * @param c configuration
  292. */
  293. static void
  294. run (void *cls,
  295. char *const *args,
  296. const char *cfgfile,
  297. const struct GNUNET_CONFIGURATION_Handle *c)
  298. {
  299. cfg = c;
  300. tt = GNUNET_SCHEDULER_add_delayed (timeout,
  301. &do_timeout, NULL);
  302. GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
  303. if (GNUNET_YES == collect) {
  304. if (NULL == issuer_key)
  305. {
  306. fprintf (stderr,
  307. _("Issuer public key not well-formed\n"));
  308. GNUNET_SCHEDULER_shutdown ();
  309. return;
  310. }
  311. credential = GNUNET_CREDENTIAL_connect (cfg);
  312. if (NULL == credential)
  313. {
  314. fprintf (stderr,
  315. _("Failed to connect to CREDENTIAL\n"));
  316. GNUNET_SCHEDULER_shutdown ();
  317. return;
  318. }
  319. if (NULL == issuer_attr)
  320. {
  321. fprintf (stderr,
  322. _("You must provide issuer the attribute\n"));
  323. GNUNET_SCHEDULER_shutdown ();
  324. return;
  325. }
  326. if (NULL == ego_name)
  327. {
  328. fprintf (stderr,
  329. _("ego required\n"));
  330. GNUNET_SCHEDULER_shutdown ();
  331. return;
  332. }
  333. el = GNUNET_IDENTITY_ego_lookup (cfg,
  334. ego_name,
  335. &identity_cb,
  336. (void *) cfg);
  337. return;
  338. }
  339. if (NULL == subject_key)
  340. {
  341. fprintf (stderr,
  342. _("Subject public key needed\n"));
  343. GNUNET_SCHEDULER_shutdown ();
  344. return;
  345. }
  346. if (GNUNET_OK !=
  347. GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
  348. strlen (subject_key),
  349. &subject_pkey))
  350. {
  351. fprintf (stderr,
  352. _("Subject public key `%s' is not well-formed\n"),
  353. subject_key);
  354. GNUNET_SCHEDULER_shutdown ();
  355. return;
  356. }
  357. if (GNUNET_YES == verify) {
  358. if (NULL == issuer_key)
  359. {
  360. fprintf (stderr,
  361. _("Issuer public key not well-formed\n"));
  362. GNUNET_SCHEDULER_shutdown ();
  363. return;
  364. }
  365. if (GNUNET_OK !=
  366. GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
  367. strlen (issuer_key),
  368. &issuer_pkey))
  369. {
  370. fprintf (stderr,
  371. _("Issuer public key `%s' is not well-formed\n"),
  372. issuer_key);
  373. GNUNET_SCHEDULER_shutdown ();
  374. return;
  375. }
  376. credential = GNUNET_CREDENTIAL_connect (cfg);
  377. if (NULL == credential)
  378. {
  379. fprintf (stderr,
  380. _("Failed to connect to CREDENTIAL\n"));
  381. GNUNET_SCHEDULER_shutdown ();
  382. return;
  383. }
  384. if (NULL == issuer_attr || NULL == subject_credential)
  385. {
  386. fprintf (stderr,
  387. _("You must provide issuer and subject attributes\n"));
  388. GNUNET_SCHEDULER_shutdown ();
  389. return;
  390. }
  391. //Subject credentials are comma separated
  392. char *tmp = GNUNET_strdup (subject_credential);
  393. char *tok = strtok (tmp, ",");
  394. if (NULL == tok)
  395. {
  396. fprintf (stderr,
  397. "Invalid subject credentials\n");
  398. GNUNET_free (tmp);
  399. GNUNET_SCHEDULER_shutdown ();
  400. return;
  401. }
  402. int count = 1;
  403. int i;
  404. while (NULL != (tok = strtok(NULL, ",")))
  405. count++;
  406. struct GNUNET_CREDENTIAL_Credential credentials[count];
  407. struct GNUNET_CREDENTIAL_Credential *cred;
  408. GNUNET_free (tmp);
  409. tmp = GNUNET_strdup (subject_credential);
  410. tok = strtok (tmp, ",");
  411. for (i=0;i<count;i++)
  412. {
  413. cred = GNUNET_CREDENTIAL_credential_from_string (tok);
  414. GNUNET_memcpy (&credentials[i],
  415. cred,
  416. sizeof (struct GNUNET_CREDENTIAL_Credential));
  417. credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
  418. tok = strtok(NULL, ",");
  419. GNUNET_free (cred);
  420. }
  421. verify_request = GNUNET_CREDENTIAL_verify(credential,
  422. &issuer_pkey,
  423. issuer_attr, //TODO argument
  424. &subject_pkey,
  425. count,
  426. credentials,
  427. &handle_verify_result,
  428. NULL);
  429. for (i=0;i<count;i++)
  430. {
  431. GNUNET_free ((char*)credentials[i].issuer_attribute);
  432. }
  433. GNUNET_free (tmp);
  434. } else if (GNUNET_YES == create_cred) {
  435. if (NULL == ego_name)
  436. {
  437. fprintf (stderr,
  438. _("Issuer ego required\n"));
  439. GNUNET_SCHEDULER_shutdown ();
  440. return;
  441. }
  442. el = GNUNET_IDENTITY_ego_lookup (cfg,
  443. ego_name,
  444. &identity_cb,
  445. (void *) cfg);
  446. return;
  447. } else {
  448. fprintf (stderr,
  449. _("Please specify name to lookup, subject key and issuer key!\n"));
  450. GNUNET_SCHEDULER_shutdown ();
  451. }
  452. return;
  453. }
  454. /**
  455. * The main function for gnunet-gns.
  456. *
  457. * @param argc number of arguments from the command line
  458. * @param argv command line arguments
  459. * @return 0 ok, 1 on error
  460. */
  461. int
  462. main (int argc, char *const *argv)
  463. {
  464. struct GNUNET_GETOPT_CommandLineOption options[] = {
  465. GNUNET_GETOPT_option_flag ('I',
  466. "issue",
  467. gettext_noop ("create credential"),
  468. &create_cred),
  469. GNUNET_GETOPT_option_flag ('V',
  470. "verify",
  471. gettext_noop ("verify credential against attribute"),
  472. &verify),
  473. GNUNET_GETOPT_option_string ('s',
  474. "subject",
  475. "PKEY",
  476. gettext_noop ("The public key of the subject to lookup the credential for"),
  477. &subject_key),
  478. GNUNET_GETOPT_option_string ('b',
  479. "credential",
  480. "CRED",
  481. gettext_noop ("The name of the credential presented by the subject"),
  482. &subject_credential),
  483. GNUNET_GETOPT_option_string ('i',
  484. "issuer",
  485. "PKEY",
  486. gettext_noop ("The public key of the authority to verify the credential against"),
  487. &issuer_key),
  488. GNUNET_GETOPT_option_string ('e',
  489. "ego",
  490. "EGO",
  491. gettext_noop ("The ego to use"),
  492. &ego_name),
  493. GNUNET_GETOPT_option_string ('a',
  494. "attribute",
  495. "ATTR",
  496. gettext_noop ("The issuer attribute to verify against or to issue"),
  497. &issuer_attr),
  498. GNUNET_GETOPT_option_string ('T',
  499. "ttl",
  500. "EXP",
  501. gettext_noop ("The time to live for the credential"),
  502. &expiration),
  503. GNUNET_GETOPT_option_flag ('g',
  504. "collect",
  505. gettext_noop ("collect credentials"),
  506. &collect),
  507. GNUNET_GETOPT_OPTION_END
  508. };
  509. int ret;
  510. timeout = GNUNET_TIME_UNIT_FOREVER_REL;
  511. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  512. return 2;
  513. GNUNET_log_setup ("gnunet-credential", "WARNING", NULL);
  514. ret =
  515. (GNUNET_OK ==
  516. GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
  517. _("GNUnet credential resolver tool"),
  518. options,
  519. &run, NULL)) ? 0 : 1;
  520. GNUNET_free ((void*) argv);
  521. return ret;
  522. }
  523. /* end of gnunet-credential.c */