endif
if HAVE_REST
- EXP_DIR += identity-token
+ EXP_DIR += identity-provider
endif
if BUILD_PULSE_HELPERS
--- /dev/null
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+ plugindir = $(libdir)/gnunet
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+pkgcfg_DATA = \
+ identity-token.conf
+
+plugin_LTLIBRARIES = \
+ libgnunet_plugin_rest_identity_token.la
+lib_LTLIBRARIES = \
+ libgnunetidentityprovider.la
+
+bin_PROGRAMS = \
+ gnunet-identity-token
+
+libexec_PROGRAMS = \
+ gnunet-service-identity-token
+
+gnunet_service_identity_token_SOURCES = \
+ gnunet-service-identity-token.c
+gnunet_service_identity_token_LDADD = \
+ libgnunetidentityprovider.la \
+ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/namestore/libgnunetnamestore.la \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(GN_LIBINTL) \
+ -ljansson
+
+libgnunetidentityprovider_la_SOURCES = \
+ identity-token.c
+libgnunetidentityprovider_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+ $(LTLIBINTL) -ljansson
+
+libgnunet_plugin_rest_identity_token_la_SOURCES = \
+ plugin_rest_identity_token.c
+libgnunet_plugin_rest_identity_token_la_LIBADD = \
+ $(top_builddir)/src/identity/libgnunetidentity.la \
+ $(top_builddir)/src/rest/libgnunetrest.la \
+ $(top_builddir)/src/namestore/libgnunetnamestore.la \
+ $(top_builddir)/src/gns/libgnunetgns.la \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+ $(LTLIBINTL) -ljansson -lmicrohttpd
+libgnunet_plugin_rest_identity_token_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+
+gnunet_identity_token_SOURCES = \
+ gnunet-identity-token.c
+gnunet_identity_token_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ -ljansson -lmicrohttpd \
+ $(GN_LIBINTL)
+
+
--- /dev/null
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include <jansson.h>
+#include "gnunet_signatures.h"
+
+/**
+ * The token
+ */
+static char* token;
+
+/**
+ * Weather to print the token
+ */
+static int print_token;
+
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ char* payload;
+ char* header;
+ //Get token parts
+ char* header_b64 = strtok (token, ".");
+ char* payload_b64 = strtok(NULL, ".");
+ char* signature_b32 = strtok(NULL, ".");
+ const char* keystring;
+ char* data;
+ json_t *payload_json;
+ json_t *keystring_json;
+ json_error_t error;
+ struct GNUNET_CRYPTO_EcdsaPublicKey key;
+ struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
+ struct GNUNET_CRYPTO_EcdsaSignature sig;
+ //Decode payload
+ GNUNET_STRINGS_base64_decode (payload_b64,
+ strlen (payload_b64),
+ &payload);
+ //Decode header
+ GNUNET_STRINGS_base64_decode (header_b64,
+ strlen (header_b64),
+ &header);
+ if (NULL == token)
+ return;
+
+
+ GNUNET_asprintf(&data,
+ "%s,%s",
+ header_b64,
+ payload_b64);
+ char *val = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
+ purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose*)val;
+ purpose->size = htonl(sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
+ purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
+ memcpy (&purpose[1], data, strlen(data));
+
+
+ payload_json = json_loads (payload, 0, &error);
+ if ((NULL == payload_json) || !json_is_object (payload_json))
+ {
+ return;
+ }
+ keystring_json = json_object_get (payload_json, "iss");
+ if (!json_is_string (keystring_json))
+ {
+ return;
+ }
+ keystring = json_string_value (keystring_json);
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (keystring,
+ strlen (keystring),
+ &key))
+ {
+ return;
+ }
+ GNUNET_STRINGS_string_to_data (signature_b32,
+ strlen (signature_b32),
+ &sig,
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+
+ if (print_token) {
+ printf ("Token:\nHeader:\t\t%s\nPayload:\t%s\nSignature:\t%s\n", header, payload, keystring);
+ }
+
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN,
+ purpose,
+ &sig,
+ &key))
+ {
+ printf("Signature not OK!\n");
+ return;
+ }
+ printf("Signature OK!\n");
+ return;
+}
+int
+main(int argc, char *const argv[])
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'t', "token", NULL,
+ gettext_noop ("GNUid token"), 1,
+ &GNUNET_GETOPT_set_string, &token},
+ {'p', "print", NULL,
+ gettext_noop ("Print token contents"), 0,
+ &GNUNET_GETOPT_set_one, &print_token},
+
+ GNUNET_GETOPT_OPTION_END
+ };
+ return GNUNET_PROGRAM_run (argc, argv, "ct",
+ "ct", options,
+ &run, NULL);
+}
+
+
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+/**
+ * @author Martin Schanzenbach
+ * @file src/rest/gnunet-service-identity-token.c
+ * @brief Identity Token Service
+ *
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_namestore_service.h"
+#include <jansson.h>
+#include "gnunet_signatures.h"
+#include "gnunet_identity_provider_lib.h"
+
+/**
+ * First pass state
+ */
+#define STATE_INIT 0
+
+/**
+ * Normal operation state
+ */
+#define STATE_POST_INIT 1
+
+/**
+ * Minimum interval between updates
+ */
+#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
+
+/**
+ * Service state (to detect initial update pass)
+ */
+static int state;
+
+/**
+ * Head of ego entry DLL
+ */
+static struct EgoEntry *ego_head;
+
+/**
+ * Tail of ego entry DLL
+ */
+static struct EgoEntry *ego_tail;
+
+/**
+ * Identity handle
+ */
+static struct GNUNET_IDENTITY_Handle *identity_handle;
+
+/**
+ * Namestore handle
+ */
+static struct GNUNET_NAMESTORE_Handle *ns_handle;
+
+/**
+ * Namestore qe
+ */
+static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
+
+/**
+ * Namestore iterator
+ */
+static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
+
+/**
+ * Timeout task
+ */
+static struct GNUNET_SCHEDULER_Task * timeout_task;
+
+
+/**
+ * Update task
+ */
+static struct GNUNET_SCHEDULER_Task * update_task;
+
+/**
+ * Timeout for next update pass
+ */
+static struct GNUNET_TIME_Relative min_rel_exp;
+
+
+/**
+ * Currently processed token
+ */
+static struct GNUNET_IDENTITY_PROVIDER_Token *token;
+
+/**
+ * Label for currently processed token
+ */
+static char* label;
+
+/**
+ * Scopes for processed token
+ */
+static char* scopes;
+
+/**
+ * Expiration for processed token
+ */
+static uint64_t rd_exp;
+
+/**
+ * ECDHE Privkey for processed token metadata
+ */
+static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
+
+/**
+ * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
+ *
+ */
+struct EgoEntry
+{
+ /**
+ * DLL
+ */
+ struct EgoEntry *next;
+
+ /**
+ * DLL
+ */
+ struct EgoEntry *prev;
+
+ /**
+ * Ego handle
+ */
+ struct GNUNET_IDENTITY_Ego *ego;
+
+ /**
+ * Attribute map. Contains the attributes as json_t
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *attr_map;
+
+ /**
+ * Attributes are old and should be updated if GNUNET_YES
+ */
+ int attributes_dirty;
+};
+
+/**
+ * Our configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * Continuation for token store call
+ *
+ * @param cls NULL
+ * @param success error code
+ * @param emsg error message
+ */
+static void
+store_token_cont (void *cls,
+ int32_t success,
+ const char *emsg)
+{
+ ns_qe = NULL;
+ if (GNUNET_SYSERR == success)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to update token: %s\n",
+ emsg);
+ return;
+ }
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+}
+
+
+/**
+ * This function updates the old token with new attributes,
+ * removes deleted attributes and expiration times.
+ *
+ * @param cls the ego entry
+ * @param tc task context
+ */
+static void
+handle_token_update (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ char *token_metadata;
+ char *write_ptr;
+ char *enc_token_str;
+ const char *key;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+ struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
+ struct EgoEntry *ego_entry = cls;
+ struct GNUNET_GNSRECORD_Data token_record[2];
+ struct GNUNET_HashCode key_hash;
+ struct GNUNET_TIME_Relative token_rel_exp;
+ struct GNUNET_TIME_Relative token_ttl;
+ struct GNUNET_TIME_Absolute token_exp;
+ struct GNUNET_TIME_Absolute token_nbf;
+ struct GNUNET_TIME_Absolute new_exp;
+ struct GNUNET_TIME_Absolute new_iat;
+ struct GNUNET_TIME_Absolute new_nbf;
+ struct GNUNET_IDENTITY_PROVIDER_Token *new_token;
+ json_t *payload_json;
+ json_t *value;
+ json_t *cur_value;
+ json_t *token_nbf_json;
+ json_t *token_exp_json;
+ size_t token_metadata_len;
+
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
+ GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
+ &pub_key);
+
+ //Note: We need the token expiration time here. Not the record expiration
+ //time.
+ //There are two types of tokens: Token that expire on GNS level with
+ //an absolute expiration time. Those are basically tokens that will
+ //be automatically revoked on (record)expiration.
+ //Tokens stored with relative expiration times will expire on the token level (token expiration)
+ //but this service will reissue new tokens that can be retrieved from GNS
+ //automatically.
+
+ payload_json = token->payload;
+
+ token_exp_json = json_object_get (payload_json, "exp");
+ token_nbf_json = json_object_get (payload_json, "nbf");
+ token_exp.abs_value_us = json_integer_value(token_exp_json);
+ token_nbf.abs_value_us = json_integer_value(token_nbf_json);
+ token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
+
+ token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
+ if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
+ {
+ //This token is not yet expired! Save and skip
+ if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
+ {
+ min_rel_exp = token_ttl;
+ }
+ json_decref (payload_json);
+ GNUNET_free (token);
+ token = NULL;
+ GNUNET_free (label);
+ label = NULL;
+ GNUNET_free (scopes);
+ scopes = NULL;
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Token is expired. Create a new one\n");
+ new_token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
+ &token->aud_key);
+ new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
+ new_nbf = GNUNET_TIME_absolute_get ();
+ new_iat = new_nbf;
+
+ json_object_foreach(payload_json, key, value) {
+ if (0 == strcmp (key, "exp"))
+ {
+ GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_exp.abs_value_us));
+ }
+ else if (0 == strcmp (key, "nbf"))
+ {
+ GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_nbf.abs_value_us));
+ }
+ else if (0 == strcmp (key, "iat"))
+ {
+ GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_iat.abs_value_us));
+ }
+ else if ((0 == strcmp (key, "iss"))
+ || (0 == strcmp (key, "aud")))
+ {
+ //Omit
+ }
+ else if ((0 == strcmp (key, "sub"))
+ || (0 == strcmp (key, "rnl")))
+ {
+ GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, value);
+ }
+ else {
+ GNUNET_CRYPTO_hash (key,
+ strlen (key),
+ &key_hash);
+ //Check if attr still exists. omit of not
+ if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
+ &key_hash))
+ {
+ cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
+ &key_hash);
+ GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, cur_value);
+ }
+ }
+ }
+
+ // reassemble and set
+ GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (new_token,
+ priv_key,
+ &new_ecdhe_privkey,
+ &enc_token_str));
+
+ json_decref (payload_json);
+
+ token_record[0].data = enc_token_str;
+ token_record[0].data_size = strlen (enc_token_str) + 1;
+ token_record[0].expiration_time = rd_exp; //Old expiration time
+ token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
+ token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
+
+ //Meta
+ token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
+ + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
+ + strlen (scopes) + 1; //With 0-Terminator
+ token_metadata = GNUNET_malloc (token_metadata_len);
+ write_ptr = token_metadata;
+ memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
+ memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
+
+ token_record[1].data = token_metadata;
+ token_record[1].data_size = token_metadata_len;
+ token_record[1].expiration_time = rd_exp;
+ token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
+ token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
+
+ ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
+ priv_key,
+ label,
+ 2,
+ token_record,
+ &store_token_cont,
+ ego_entry);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
+ GNUNET_IDENTITY_PROVIDER_token_destroy (new_token);
+ GNUNET_IDENTITY_PROVIDER_token_destroy (token);
+ GNUNET_free (new_ecdhe_privkey);
+ GNUNET_free (enc_token_str);
+ token = NULL;
+ GNUNET_free (label);
+ label = NULL;
+ GNUNET_free (scopes);
+ scopes = NULL;
+}
+
+static void
+update_identities(void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ *
+ * Cleanup attr_map
+ *
+ * @param cls NULL
+ * @param key the key
+ * @param value the json_t attribute value
+ * @return GNUNET_YES
+ */
+static int
+clear_ego_attrs (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ json_t *attr_value = value;
+
+ json_decref (attr_value);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ *
+ * Update all ID_TOKEN records for an identity and store them
+ *
+ * @param cls the identity entry
+ * @param zone the identity
+ * @param lbl the name of the record
+ * @param rd_count number of records
+ * @param rd record data
+ *
+ */
+static void
+token_collect (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *lbl,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct EgoEntry *ego_entry = cls;
+ const struct GNUNET_GNSRECORD_Data *token_record;
+ const struct GNUNET_GNSRECORD_Data *token_metadata_record;
+ struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
+
+ if (NULL == lbl)
+ {
+ //Done
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ ">>> Updating Ego finished\n");
+ //Clear attribute map for ego
+ GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
+ &clear_ego_attrs,
+ ego_entry);
+ GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
+ GNUNET_SCHEDULER_add_now (&update_identities, ego_entry->next);
+ return;
+ }
+
+ //There should be only a single record for a token under a label
+ if (2 != rd_count)
+ {
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+ return;
+ }
+
+ if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
+ {
+ token_metadata_record = &rd[0];
+ token_record = &rd[1];
+ } else {
+ token_record = &rd[0];
+ token_metadata_record = &rd[1];
+ }
+ GNUNET_assert (token_metadata_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA);
+ GNUNET_assert (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN);
+
+ //Get metadata and decrypt token
+ ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
+ aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
+ scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+
+ GNUNET_IDENTITY_PROVIDER_token_parse2 (token_record->data,
+ &ecdhe_privkey,
+ aud_key,
+ &token);
+
+ //token = GNUNET_GNSRECORD_value_to_string (rd->record_type,
+ // rd->data,
+ // rd->data_size);
+ label = GNUNET_strdup (lbl);
+ rd_exp = token_record->expiration_time;
+
+ GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
+}
+
+
+/**
+ *
+ * Collect all ID_ATTR records for an identity and store them
+ *
+ * @param cls the identity entry
+ * @param zone the identity
+ * @param lbl the name of the record
+ * @param rd_count number of records
+ * @param rd record data
+ *
+ */
+static void
+attribute_collect (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *lbl,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct EgoEntry *ego_entry = cls;
+ json_t *attr_value;
+ struct GNUNET_HashCode key;
+ char* attr;
+ int i;
+
+ if (NULL == lbl)
+ {
+ //Done
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ ">>> Updating Attributes finished\n");
+ ego_entry->attributes_dirty = GNUNET_NO;
+ GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
+ return;
+ }
+
+ if (0 == rd_count)
+ {
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+ return;
+ }
+ GNUNET_CRYPTO_hash (lbl,
+ strlen (lbl),
+ &key);
+ if (1 == rd_count)
+ {
+ if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
+ {
+ attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
+ rd->data,
+ rd->data_size);
+ attr_value = json_string (attr);
+ GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
+ &key,
+ attr_value,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ GNUNET_free (attr);
+ }
+
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+ return;
+ }
+
+ attr_value = json_array();
+ for (i = 0; i < rd_count; i++)
+ {
+ if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
+ {
+ attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+ rd[i].data,
+ rd[i].data_size);
+ json_array_append_new (attr_value, json_string (attr));
+ GNUNET_free (attr);
+ }
+
+ }
+ GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
+ &key,
+ attr_value,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ GNUNET_NAMESTORE_zone_iterator_next (ns_it);
+ return;
+}
+
+/**
+ *
+ * Update identity information for ego. If attribute map is
+ * dirty, first update the attributes.
+ *
+ * @param cls the ego to update
+ * param tc task context
+ *
+ */
+static void
+update_identities(void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct EgoEntry *next_ego = cls;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ if (NULL == next_ego)
+ {
+ if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
+ min_rel_exp = MIN_WAIT_TIME;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ ">>> Finished. Rescheduling in %d\n",
+ min_rel_exp.rel_value_us);
+ ns_it = NULL;
+ //finished -> TODO reschedule
+ update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
+ &update_identities,
+ ego_head);
+ min_rel_exp.rel_value_us = 0;
+ return;
+ }
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
+ if (GNUNET_YES == next_ego->attributes_dirty)
+ {
+ //Starting over. We must update the Attributes for they might have changed.
+ ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
+ priv_key,
+ &attribute_collect,
+ next_ego);
+
+ }
+ else
+ {
+ //Ego will be dirty next time
+ next_ego->attributes_dirty = GNUNET_YES;
+ ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
+ priv_key,
+ &token_collect,
+ next_ego);
+ }
+}
+
+
+
+/**
+ * Function called initially to start update task
+ */
+static void
+init_cont ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
+ //Initially iterate all itenties and refresh all tokens
+ update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
+}
+
+/**
+ * Initial ego collection function.
+ *
+ * @param cls NULL
+ * @param ego ego
+ * @param ctx context
+ * @param identifier ego name
+ */
+static void
+list_ego (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *identifier)
+{
+ struct EgoEntry *new_entry;
+ if ((NULL == ego) && (STATE_INIT == state))
+ {
+ state = STATE_POST_INIT;
+ init_cont ();
+ return;
+ }
+ if (STATE_INIT == state) {
+ new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
+ new_entry->ego = ego;
+ new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
+ GNUNET_NO);
+ new_entry->attributes_dirty = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
+ }
+}
+
+/**
+ * Cleanup task
+ */
+static void
+cleanup()
+{
+ struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_tmp;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up\n");
+ if (NULL != timeout_task)
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ if (NULL != update_task)
+ GNUNET_SCHEDULER_cancel (update_task);
+ if (NULL != identity_handle)
+ GNUNET_IDENTITY_disconnect (identity_handle);
+ if (NULL != ns_it)
+ GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
+ if (NULL != ns_qe)
+ GNUNET_NAMESTORE_cancel (ns_qe);
+ if (NULL != ns_handle)
+ GNUNET_NAMESTORE_disconnect (ns_handle);
+ if (NULL != token)
+ GNUNET_free (token);
+ if (NULL != label)
+ GNUNET_free (label);
+
+ for (ego_entry = ego_head;
+ NULL != ego_entry;)
+ {
+ ego_tmp = ego_entry;
+ if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
+ &clear_ego_attrs,
+ ego_tmp);
+
+ }
+ GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
+ ego_entry = ego_entry->next;
+ GNUNET_free (ego_tmp);
+ }
+}
+
+/**
+ * Shutdown task
+ *
+ * @param cls NULL
+ * @param tc task context
+ */
+static void
+do_shutdown (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Shutting down...\n");
+ cleanup();
+}
+
+/**
+ * Main function that will be run
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ cfg = c;
+
+
+ //Connect to identity and namestore services
+ ns_handle = GNUNET_NAMESTORE_connect (cfg);
+ if (NULL == ns_handle)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
+ }
+
+ identity_handle = GNUNET_IDENTITY_connect (cfg,
+ &list_ego,
+ NULL);
+
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+}
+
+
+/**
+ *
+ * The main function for gnunet-service-identity-token
+ *
+ * @param argc number of arguments from the cli
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ *
+ */
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+ GNUNET_log_setup ("gnunet-service-identity-token", "WARNING", NULL);
+ ret =
+ (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-service-identity-token",
+ _("GNUnet identity token service"),
+ options,
+ &run, NULL)) ? 0: 1;
+ GNUNET_free_non_null ((char *) argv);
+ return ret;
+}
+
+/* end of gnunet-rest-server.c */
--- /dev/null
+/*
+ This file is part of GNUnet
+ Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file identity-token/identity-token.c
+ * @brief helper library to manage identity tokens
+ * @author Martin Schanzenbach
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_identity_provider_lib.h"
+#include <jansson.h>
+
+
+/**
+ * Crypto helper functions
+ */
+
+static int
+create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
+ struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
+ struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
+{
+ struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
+
+ GNUNET_CRYPTO_hash_to_enc (new_key_hash,
+ &new_key_hash_str);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
+ static const char ctx_key[] = "gnuid-aes-ctx-key";
+ GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
+ new_key_hash, sizeof (struct GNUNET_HashCode),
+ ctx_key, strlen (ctx_key),
+ NULL, 0);
+ static const char ctx_iv[] = "gnuid-aes-ctx-iv";
+ GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
+ new_key_hash, sizeof (struct GNUNET_HashCode),
+ ctx_iv, strlen (ctx_iv),
+ NULL, 0);
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Decrypts metainfo part from a token code
+ */
+static int
+decrypt_str_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key,
+ const char *cyphertext,
+ size_t cyphertext_len,
+ char **result_str)
+{
+ struct GNUNET_HashCode new_key_hash;
+ struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
+
+ char *str_buf = GNUNET_malloc (cyphertext_len);
+ size_t str_size;
+
+ //Calculate symmetric key from ecdh parameters
+ GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_ecdh (priv_key,
+ ecdh_key,
+ &new_key_hash));
+
+ create_sym_key_from_ecdh (&new_key_hash,
+ &enc_key,
+ &enc_iv);
+
+ str_size = GNUNET_CRYPTO_symmetric_decrypt (cyphertext,
+ cyphertext_len,
+ &enc_key,
+ &enc_iv,
+ str_buf);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Decrypted bytes: %d Expected bytes: %d\n", str_size, cyphertext_len);
+ if (-1 == str_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH invalid\n");
+ GNUNET_free (str_buf);
+ return GNUNET_SYSERR;
+ }
+ *result_str = GNUNET_malloc (str_size+1);
+ memcpy (*result_str, str_buf, str_size);
+ (*result_str)[str_size] = '\0';
+ GNUNET_free (str_buf);
+ return GNUNET_OK;
+
+}
+
+/**
+ * Decrypt string using pubkey and ECDHE
+*/
+static int
+decrypt_str_ecdhe2 (const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_privkey,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
+ const char *ciphertext,
+ size_t ciphertext_len,
+ char **plaintext)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_HashCode new_key_hash;
+
+ //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
+ *plaintext = GNUNET_malloc (ciphertext_len);
+
+ // Derived key K = H(eB)
+ GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (ecdh_privkey,
+ aud_key,
+ &new_key_hash));
+ create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
+ GNUNET_CRYPTO_symmetric_decrypt (ciphertext,
+ ciphertext_len,
+ &skey, &iv,
+ *plaintext);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Encrypt string using pubkey and ECDHE
+ * Returns ECDHE pubkey to be used for decryption
+ */
+static int
+encrypt_str_ecdhe (const char *plaintext,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
+ char **cyphertext,
+ struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
+ struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pubkey)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey skey;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_HashCode new_key_hash;
+ ssize_t enc_size;
+
+ // ECDH keypair E = eG
+ *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
+ GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
+ ecdh_pubkey);
+
+ //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
+ *cyphertext = GNUNET_malloc (strlen (plaintext));
+
+ // Derived key K = H(eB)
+ GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
+ pub_key,
+ &new_key_hash));
+ create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypting string %s\n (len=%d)",
+ plaintext,
+ strlen (plaintext));
+ enc_size = GNUNET_CRYPTO_symmetric_encrypt (plaintext, strlen (plaintext),
+ &skey, &iv,
+ *cyphertext);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypted (len=%d)", enc_size);
+ return GNUNET_OK;
+}
+
+
+
+
+/**
+ * Identity Token API
+ */
+
+
+/**
+ * Create an Identity Token
+ *
+ * @param type the JSON API resource type
+ * @param id the JSON API resource id
+ * @return a new JSON API resource or NULL on error.
+ */
+struct GNUNET_IDENTITY_PROVIDER_Token*
+GNUNET_IDENTITY_PROVIDER_token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey* iss,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey* aud)
+{
+ struct GNUNET_IDENTITY_PROVIDER_Token *token;
+ char* audience;
+ char* issuer;
+
+ issuer = GNUNET_STRINGS_data_to_string_alloc (iss,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ audience = GNUNET_STRINGS_data_to_string_alloc (aud,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+
+
+
+ token = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
+
+ token->header = json_object();
+ token->payload = json_object();
+
+ json_object_set_new (token->header, "alg", json_string ("ED512"));
+ json_object_set_new (token->header, "typ", json_string ("JWT"));
+
+ json_object_set_new (token->payload, "iss", json_string (issuer));
+ json_object_set_new (token->payload, "aud", json_string (audience));
+
+ token->aud_key = *aud;
+ GNUNET_free (issuer);
+ GNUNET_free (audience);
+ return token;
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_token_destroy (struct GNUNET_IDENTITY_PROVIDER_Token *token)
+{
+ json_decref (token->header);
+ json_decref (token->payload);
+ GNUNET_free (token);
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_token_add_attr (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const char* key,
+ const char* value)
+{
+ GNUNET_assert (NULL != token);
+ GNUNET_assert (NULL != token->payload);
+
+ json_object_set_new (token->payload, key, json_string (value));
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_token_add_json (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const char* key,
+ json_t* value)
+{
+ GNUNET_assert (NULL != token);
+ GNUNET_assert (NULL != token->payload);
+
+ json_object_set_new (token->payload, key, value);
+}
+
+
+int
+GNUNET_IDENTITY_PROVIDER_token_parse2 (const char* raw_data,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
+ struct GNUNET_IDENTITY_PROVIDER_Token **result)
+{
+ char *enc_token_str;
+ char *tmp_buf;
+ char *token_str;
+ char *enc_token;
+ char *header;
+ char *header_base64;
+ char *payload;
+ char *payload_base64;
+ size_t enc_token_len;
+ json_error_t err_json;
+
+ GNUNET_asprintf (&tmp_buf, "%s", raw_data);
+ strtok (tmp_buf, ",");
+ enc_token_str = strtok (NULL, ",");
+
+ enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
+ strlen (enc_token_str),
+ &enc_token);
+ if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key,
+ aud_key,
+ enc_token,
+ enc_token_len,
+ &token_str))
+ {
+ GNUNET_free (tmp_buf);
+ GNUNET_free (enc_token);
+ return GNUNET_SYSERR;
+ }
+
+ header_base64 = strtok (token_str, ".");
+ payload_base64 = strtok (NULL, ".");
+
+ GNUNET_STRINGS_base64_decode (header_base64,
+ strlen (header_base64),
+ &header);
+ GNUNET_STRINGS_base64_decode (payload_base64,
+ strlen (payload_base64),
+ &payload);
+ //TODO signature
+
+
+ *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
+ (*result)->aud_key = *aud_key;
+ (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
+ (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
+ GNUNET_free (enc_token);
+ GNUNET_free (token_str);
+ GNUNET_free (tmp_buf);
+ GNUNET_free (payload);
+ GNUNET_free (header);
+ return GNUNET_OK;
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_token_parse (const char* raw_data,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_IDENTITY_PROVIDER_Token **result)
+{
+ char *ecdh_pubkey_str;
+ char *enc_token_str;
+ char *tmp_buf;
+ char *token_str;
+ char *enc_token;
+ char *header;
+ char *header_base64;
+ char *payload;
+ char *payload_base64;
+ size_t enc_token_len;
+ json_error_t err_json;
+ struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
+
+ GNUNET_asprintf (&tmp_buf, "%s", raw_data);
+ ecdh_pubkey_str = strtok (tmp_buf, ",");
+ enc_token_str = strtok (NULL, ",");
+
+ GNUNET_STRINGS_string_to_data (ecdh_pubkey_str,
+ strlen (ecdh_pubkey_str),
+ &ecdh_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+ enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
+ strlen (enc_token_str),
+ &enc_token);
+ if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
+ &ecdh_pubkey,
+ enc_token,
+ enc_token_len,
+ &token_str))
+ {
+ GNUNET_free (tmp_buf);
+ GNUNET_free (enc_token);
+ return GNUNET_SYSERR;
+ }
+
+ header_base64 = strtok (token_str, ".");
+ payload_base64 = strtok (NULL, ".");
+
+ GNUNET_STRINGS_base64_decode (header_base64,
+ strlen (header_base64),
+ &header);
+ GNUNET_STRINGS_base64_decode (payload_base64,
+ strlen (payload_base64),
+ &payload);
+ //TODO signature and aud key
+
+
+ *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
+ (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
+ (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
+ GNUNET_free (enc_token);
+ GNUNET_free (token_str);
+ GNUNET_free (tmp_buf);
+ GNUNET_free (payload);
+ GNUNET_free (header);
+ return GNUNET_OK;
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ char **result)
+{
+ char *payload_str;
+ char *header_str;
+ char *payload_base64;
+ char *header_base64;
+ char *padding;
+ char *signature_target;
+ char *signature_str;
+ struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
+ header_str = json_dumps (token->header, JSON_COMPACT);
+ GNUNET_STRINGS_base64_encode (header_str,
+ strlen (header_str),
+ &header_base64);
+ //Remove GNUNET padding of base64
+ padding = strtok(header_base64, "=");
+ while (NULL != padding)
+ padding = strtok(NULL, "=");
+
+ payload_str = json_dumps (token->payload, JSON_COMPACT);
+ GNUNET_STRINGS_base64_encode (payload_str,
+ strlen (payload_str),
+ &payload_base64);
+
+ //Remove GNUNET padding of base64
+ padding = strtok(payload_base64, "=");
+ while (NULL != padding)
+ padding = strtok(NULL, "=");
+
+ GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64);
+ purpose =
+ GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ strlen (signature_target));
+ purpose->size =
+ htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
+ purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
+ memcpy (&purpose[1], signature_target, strlen (signature_target));
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
+ purpose,
+ (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature))
+ {
+ GNUNET_free (signature_target);
+ GNUNET_free (payload_str);
+ GNUNET_free (header_str);
+ GNUNET_free (payload_base64);
+ GNUNET_free (header_base64);
+ GNUNET_free (purpose);
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_STRINGS_base64_encode ((const char*)&token->signature,
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
+ &signature_str);
+ GNUNET_asprintf (result, "%s.%s.%s",
+ header_base64, payload_base64, signature_str);
+ GNUNET_free (signature_target);
+ GNUNET_free (payload_str);
+ GNUNET_free (header_str);
+ GNUNET_free (signature_str);
+ GNUNET_free (payload_base64);
+ GNUNET_free (header_base64);
+ GNUNET_free (purpose);
+ return GNUNET_OK;
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_token_serialize (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
+ char **result)
+{
+ char *token_str;
+ char *enc_token;
+ char *dh_key_str;
+ char *enc_token_base64;
+ struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
+
+ GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (token,
+ priv_key,
+ &token_str));
+
+ GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str,
+ &token->aud_key,
+ &enc_token,
+ ecdh_privkey,
+ &ecdh_pubkey));
+ GNUNET_STRINGS_base64_encode (enc_token,
+ strlen (token_str),
+ &enc_token_base64);
+ dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+ GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64);
+ GNUNET_free (dh_key_str);
+ GNUNET_free (enc_token_base64);
+ GNUNET_free (enc_token);
+ GNUNET_free (token_str);
+ return GNUNET_OK;
+}
+
+struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload*
+GNUNET_IDENTITY_PROVIDER_ticket_payload_create (const char* nonce,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
+ const char* lbl_str)
+{
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload;
+
+ payload = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload));
+ GNUNET_asprintf (&payload->nonce, nonce, strlen (nonce));
+ payload->identity_key = *identity_pkey;
+ GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str));
+ return payload;
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload)
+{
+ GNUNET_free (payload->nonce);
+ GNUNET_free (payload->label);
+ GNUNET_free (payload);
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *payload,
+ char **result)
+{
+ char* identity_key_str;
+
+ identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+
+ GNUNET_asprintf (result,
+ "{\"nonce\": \"%u\",\"identity\": \"%s\",\"label\": \"%s\"}",
+ payload->nonce, identity_key_str, payload->label);
+ GNUNET_free (identity_key_str);
+
+}
+
+
+/**
+ * Create the token code
+ * The metadata is encrypted with a share ECDH derived secret using B (aud_key)
+ * and e (ecdh_privkey)
+ * The ticket also contains E (ecdh_pubkey) and a signature over the
+ * metadata and E
+ */
+struct GNUNET_IDENTITY_PROVIDER_TokenTicket*
+GNUNET_IDENTITY_PROVIDER_ticket_create (const char* nonce_str,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
+ const char* lbl_str,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key)
+{
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *code_payload;
+
+ ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
+ code_payload = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
+ identity_pkey,
+ lbl_str);
+ ticket->aud_key = *aud_key;
+ ticket->payload = code_payload;
+
+
+ return ticket;
+}
+
+void
+GNUNET_IDENTITY_PROVIDER_ticket_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket)
+{
+ GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (ticket->payload);
+ GNUNET_free (ticket);
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_ticket_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ char **result)
+{
+ char *code_payload_str;
+ char *enc_ticket_payload;
+ char *ticket_payload_str;
+ char *ticket_sig_str;
+ char *ticket_str;
+ char *dh_key_str;
+ char *write_ptr;
+ struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
+
+ struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
+
+ GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (ticket->payload,
+ &code_payload_str);
+
+ GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str,
+ &ticket->aud_key,
+ &enc_ticket_payload,
+ &ecdhe_privkey,
+ &ticket->ecdh_pubkey));
+
+ GNUNET_free (ecdhe_privkey);
+
+ purpose =
+ GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
+ strlen (code_payload_str)); // E_K (code_str)
+ purpose->size =
+ htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ strlen (code_payload_str));
+ purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
+ write_ptr = (char*) &purpose[1];
+ memcpy (write_ptr,
+ &ticket->ecdh_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
+ memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
+ GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
+ purpose,
+ &ticket->signature));
+ GNUNET_STRINGS_base64_encode (enc_ticket_payload,
+ strlen (code_payload_str),
+ &ticket_payload_str);
+ ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature,
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+
+ dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s to encrypt\n", dh_key_str);
+ GNUNET_asprintf (&ticket_str, "{\"meta\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}",
+ ticket_payload_str, dh_key_str, ticket_sig_str);
+ GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result);
+ GNUNET_free (dh_key_str);
+ GNUNET_free (purpose);
+ GNUNET_free (ticket_str);
+ GNUNET_free (ticket_sig_str);
+ GNUNET_free (code_payload_str);
+ GNUNET_free (enc_ticket_payload);
+ GNUNET_free (ticket_payload_str);
+ return GNUNET_OK;
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_ticket_payload_parse(const char *raw_data,
+ ssize_t data_len,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey,
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload **result)
+{
+ const char* label_str;
+ const char* nonce_str;
+ const char* identity_key_str;
+
+ json_t *root;
+ json_t *label_json;
+ json_t *identity_json;
+ json_t *nonce_json;
+ json_error_t err_json;
+ char* meta_str;
+ struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey;
+
+ if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
+ ecdhe_pkey,
+ raw_data,
+ data_len,
+ &meta_str))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata decryption failed\n");
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata: %s\n", meta_str);
+ root = json_loads (meta_str, JSON_DECODE_ANY, &err_json);
+ if (!root)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error parsing metadata: %s\n", err_json.text);
+ GNUNET_free (meta_str);
+ return GNUNET_SYSERR;
+ }
+
+ identity_json = json_object_get (root, "identity");
+ if (!json_is_string (identity_json))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error parsing metadata: %s\n", err_json.text);
+ json_decref (root);
+ GNUNET_free (meta_str);
+ return GNUNET_SYSERR;
+ }
+ identity_key_str = json_string_value (identity_json);
+ GNUNET_STRINGS_string_to_data (identity_key_str,
+ strlen (identity_key_str),
+ &id_pkey,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+
+
+ label_json = json_object_get (root, "label");
+ if (!json_is_string (label_json))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error parsing metadata: %s\n", err_json.text);
+ json_decref (root);
+ GNUNET_free (meta_str);
+ return GNUNET_SYSERR;
+ }
+
+ label_str = json_string_value (label_json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found label: %s\n", label_str);
+
+ nonce_json = json_object_get (root, "nonce");
+ if (!json_is_string (label_json))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error parsing metadata: %s\n", err_json.text);
+ json_decref (root);
+ GNUNET_free (meta_str);
+ return GNUNET_SYSERR;
+ }
+
+ nonce_str = json_string_value (nonce_json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found nonce: %s\n", nonce_str);
+
+ *result = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
+ (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey,
+ label_str);
+ GNUNET_free (meta_str);
+ json_decref (root);
+ return GNUNET_OK;
+
+}
+
+int
+GNUNET_IDENTITY_PROVIDER_ticket_parse (const char *raw_data,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicket **result)
+{
+ const char* enc_meta_str;
+ const char* ecdh_enc_str;
+ const char* signature_enc_str;
+
+ json_t *root;
+ json_t *signature_json;
+ json_t *ecdh_json;
+ json_t *enc_meta_json;
+ json_error_t err_json;
+ char* enc_meta;
+ char* ticket_decoded;
+ char* write_ptr;
+ size_t enc_meta_len;
+ struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *ticket_payload;
+
+ ticket_decoded = NULL;
+ GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Token Code: %s\n", ticket_decoded);
+ root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json);
+ if (!root)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "%s\n", err_json.text);
+ return GNUNET_SYSERR;
+ }
+
+ signature_json = json_object_get (root, "signature");
+ ecdh_json = json_object_get (root, "ecdh");
+ enc_meta_json = json_object_get (root, "meta");
+
+ signature_enc_str = json_string_value (signature_json);
+ ecdh_enc_str = json_string_value (ecdh_json);
+ enc_meta_str = json_string_value (enc_meta_json);
+
+ ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
+
+ if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str,
+ strlen (ecdh_enc_str),
+ &ticket->ecdh_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in metadata\n", ecdh_enc_str);
+ json_decref (root);
+ GNUNET_free (ticket);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s for metadata decryption\n", ecdh_enc_str);
+ if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str,
+ strlen (signature_enc_str),
+ &ticket->signature,
+ sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
+ {
+ json_decref (root);
+ GNUNET_free (ticket_decoded);
+ GNUNET_free (ticket);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in metadata\n");
+ return GNUNET_SYSERR;
+ }
+
+ enc_meta_len = GNUNET_STRINGS_base64_decode (enc_meta_str,
+ strlen (enc_meta_str),
+ &enc_meta);
+
+
+ GNUNET_IDENTITY_PROVIDER_ticket_payload_parse (enc_meta,
+ enc_meta_len,
+ priv_key,
+ (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey,
+ &ticket_payload);
+
+ ticket->payload = ticket_payload;
+ //TODO: check signature here
+ purpose =
+ GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
+ enc_meta_len); // E_K (code_str)
+ purpose->size =
+ htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
+ enc_meta_len);
+ purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
+ write_ptr = (char*) &purpose[1];
+ memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
+ memcpy (write_ptr, enc_meta, enc_meta_len);
+
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET,
+ purpose,
+ &ticket->signature,
+ &ticket_payload->identity_key))
+ {
+ GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
+ GNUNET_free (ticket_decoded);
+ json_decref (root);
+ GNUNET_free (purpose);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Error verifying signature for token code\n");
+ return GNUNET_SYSERR;
+ }
+ *result = ticket;
+ GNUNET_free (purpose);
+
+ GNUNET_free (enc_meta);
+ GNUNET_free (ticket_decoded);
+ json_decref (root);
+ return GNUNET_OK;
+
+}
+
+
+
+/* end of identity-token.c */
--- /dev/null
+[identity-token]
+BINARY=gnunet-service-identity-token
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+/**
+ * @author Martin Schanzenbach
+ * @file identity/plugin_rest_identity.c
+ * @brief GNUnet Namestore REST plugin
+ *
+ */
+
+#include "platform.h"
+#include "gnunet_rest_plugin.h"
+#include "gnunet_identity_service.h"
+#include "gnunet_gns_service.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_namestore_service.h"
+#include "gnunet_rest_lib.h"
+#include "microhttpd.h"
+#include <jansson.h>
+#include "gnunet_signatures.h"
+#include "gnunet_identity_provider_lib.h"
+
+/**
+ * REST root namespace
+ */
+#define GNUNET_REST_API_NS_IDENTITY_TOKEN "/gnuid"
+
+/**
+ * Issue namespace
+ */
+#define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/gnuid/issue"
+
+/**
+ * Check namespace
+ */
+#define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/gnuid/check"
+
+/**
+ * Token namespace
+ */
+#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/gnuid/token"
+
+/**
+ * Authorize namespace
+ */
+#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_AUTHORIZE "/gnuid/authorize"
+
+#define GNUNET_REST_JSONAPI_IDENTITY_token_ticket "code"
+
+#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE_CODE "authorization_code"
+
+#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE "grant_type"
+
+#define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
+
+/**
+ * State while collecting all egos
+ */
+#define ID_REST_STATE_INIT 0
+
+/**
+ * Done collecting egos
+ */
+#define ID_REST_STATE_POST_INIT 1
+
+/**
+ * Resource type
+ */
+#define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
+
+/**
+ * URL parameter to create a GNUid token for a specific audience
+ */
+#define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
+
+/**
+ * URL parameter to create a GNUid token for a specific issuer (EGO)
+ */
+#define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
+
+/**
+ * Attributes passed to issue request
+ */
+#define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
+
+/**
+ * Token expiration string
+ */
+#define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
+
+/**
+ * Renew token w/ relative expirations
+ */
+#define GNUNET_IDENTITY_TOKEN_RENEW_TOKEN "renew_token"
+
+/**
+ * Error messages
+ */
+#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
+#define GNUNET_REST_ERROR_NO_DATA "No data"
+
+/**
+ * GNUid token lifetime
+ */
+#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
+
+/**
+ * The configuration handle
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * HTTP methods allows for this plugin
+ */
+static char* allow_methods;
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct Plugin
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+};
+
+/**
+ * The ego list
+ */
+struct EgoEntry
+{
+ /**
+ * DLL
+ */
+ struct EgoEntry *next;
+
+ /**
+ * DLL
+ */
+ struct EgoEntry *prev;
+
+ /**
+ * Ego Identifier
+ */
+ char *identifier;
+
+ /**
+ * Public key string
+ */
+ char *keystring;
+
+ /**
+ * The Ego
+ */
+ struct GNUNET_IDENTITY_Ego *ego;
+};
+
+
+struct RequestHandle
+{
+ /**
+ * Ego list
+ */
+ struct EgoEntry *ego_head;
+
+ /**
+ * Ego list
+ */
+ struct EgoEntry *ego_tail;
+
+ /**
+ * Selected ego
+ */
+ struct EgoEntry *ego_entry;
+
+ /**
+ * Ptr to current ego private key
+ */
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+
+ /**
+ * Handle to the rest connection
+ */
+ struct RestConnectionDataHandle *conndata_handle;
+
+ /**
+ * The processing state
+ */
+ int state;
+
+ /**
+ * Handle to Identity service.
+ */
+ struct GNUNET_IDENTITY_Handle *identity_handle;
+
+ /**
+ * IDENTITY Operation
+ */
+ struct GNUNET_IDENTITY_Operation *op;
+
+ /**
+ * Handle to NS service
+ */
+ struct GNUNET_NAMESTORE_Handle *ns_handle;
+
+ /**
+ * Handle to GNS service
+ */
+ struct GNUNET_GNS_Handle *gns_handle;
+
+ /**
+ * NS iterator
+ */
+ struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
+
+ /**
+ * NS Handle
+ */
+ struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
+
+ /**
+ * Desired timeout for the lookup (default is no timeout).
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * ID of a task associated with the resolution process.
+ */
+ struct GNUNET_SCHEDULER_Task * timeout_task;
+
+ /**
+ * GNS lookup
+ */
+ struct GNUNET_GNS_LookupRequest *lookup_request;
+
+ /**
+ * The plugin result processor
+ */
+ GNUNET_REST_ResultProcessor proc;
+
+ /**
+ * The closure of the result processor
+ */
+ void *proc_cls;
+
+ /**
+ * The name to look up
+ */
+ char *name;
+
+ /**
+ * The url
+ */
+ char *url;
+
+ /**
+ * The data from the REST request
+ */
+ const char* data;
+
+ /**
+ * the length of the REST data
+ */
+ size_t data_size;
+
+ /**
+ * HTTP method
+ */
+ const char* method;
+
+ /**
+ * Error response message
+ */
+ char *emsg;
+
+ /**
+ * Identity Token
+ */
+ struct GNUNET_IDENTITY_PROVIDER_Token *token;
+
+ /**
+ * Identity Token Code
+ */
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicket *token_ticket;
+
+ /**
+ * Response object
+ */
+ struct JsonApiObject *resp_object;
+
+ /**
+ * ID Attribute list given
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *attr_map;
+
+
+};
+
+
+/**
+ * Cleanup lookup handle
+ * @param handle Handle to clean up
+ */
+static void
+cleanup_handle (struct RequestHandle *handle)
+{
+ struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_tmp;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up\n");
+ if (NULL != handle->resp_object)
+ GNUNET_REST_jsonapi_object_delete (handle->resp_object);
+ if (NULL != handle->name)
+ GNUNET_free (handle->name);
+ if (NULL != handle->timeout_task)
+ GNUNET_SCHEDULER_cancel (handle->timeout_task);
+ if (NULL != handle->identity_handle)
+ GNUNET_IDENTITY_disconnect (handle->identity_handle);
+ if (NULL != handle->gns_handle)
+ GNUNET_GNS_disconnect (handle->gns_handle);
+ if (NULL != handle->ns_it)
+ GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
+ if (NULL != handle->ns_qe)
+ GNUNET_NAMESTORE_cancel (handle->ns_qe);
+ if (NULL != handle->ns_handle)
+ GNUNET_NAMESTORE_disconnect (handle->ns_handle);
+ if (NULL != handle->attr_map)
+ GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
+ if (NULL != handle->token)
+ GNUNET_IDENTITY_PROVIDER_token_destroy (handle->token);
+ if (NULL != handle->token_ticket)
+ GNUNET_IDENTITY_PROVIDER_ticket_destroy (handle->token_ticket);
+ if (NULL != handle->url)
+ GNUNET_free (handle->url);
+ if (NULL != handle->emsg)
+ GNUNET_free (handle->emsg);
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;)
+ {
+ ego_tmp = ego_entry;
+ ego_entry = ego_entry->next;
+ GNUNET_free (ego_tmp->identifier);
+ GNUNET_free (ego_tmp->keystring);
+ GNUNET_free (ego_tmp);
+ }
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Task run on shutdown. Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_error (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+ char *json_error;
+
+ GNUNET_asprintf (&json_error,
+ "{Error while processing request: %s}",
+ handle->emsg);
+
+ resp = GNUNET_REST_create_json_response (json_error);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+ cleanup_handle (handle);
+ GNUNET_free (json_error);
+}
+
+/**
+ * Task run on shutdown. Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_cleanup_handle_delayed (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RequestHandle *handle = cls;
+ cleanup_handle(handle);
+}
+
+void
+store_token_cont (void *cls,
+ int32_t success,
+ const char *emsg)
+{
+ char *result_str;
+ struct MHD_Response *resp;
+ struct RequestHandle *handle = cls;
+
+ handle->ns_qe = NULL;
+ if (GNUNET_SYSERR == success)
+ {
+ handle->emsg = GNUNET_strdup (emsg);
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+ resp = GNUNET_REST_create_json_response (result_str);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_free (result_str);
+ GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
+}
+
+
+
+
+
+
+
+
+
+/**
+ * Build a GNUid token for identity
+ * @param handle the handle
+ * @param ego_entry the ego to build the token for
+ * @param name name of the ego
+ * @param token_aud token audience
+ * @param token the resulting gnuid token
+ * @return identifier string of token (label)
+ */
+static void
+sign_and_return_token (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+ struct GNUNET_CRYPTO_EcdsaPublicKey aud_pkey;
+ struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
+ struct JsonApiResource *json_resource;
+ struct RequestHandle *handle = cls;
+ struct GNUNET_GNSRECORD_Data token_record[2];
+ struct GNUNET_HashCode key;
+ struct GNUNET_TIME_Relative etime_rel;
+ json_t *token_str;
+ json_t *name_str;
+ json_t *token_ticket_json;
+ char *lbl_str;
+ char *exp_str;
+ char *token_ticket_str;
+ char *audience;
+ char *nonce_str;
+ char *enc_token_str;
+ char *token_metadata;
+ char *scopes;
+ char* write_ptr;
+ uint64_t time;
+ uint64_t exp_time;
+ uint64_t rnd_key;
+ size_t token_metadata_len;
+
+ //Remote nonce
+ nonce_str = NULL;
+ GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
+ strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
+ &key);
+ if ( GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
+ //Token audience
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
+ &key);
+ audience = NULL;
+ if ( GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ handle->emsg = GNUNET_strdup ("Audience missing!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience to issue token for: %s\n", audience);
+
+ //Audience pubkey (B = bG)
+ if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (audience,
+ strlen (audience),
+ &aud_pkey))
+ {
+ handle->emsg = GNUNET_strdup ("Client PKEY invalid!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+
+ rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
+ GNUNET_STRINGS_base64_encode ((char*)&rnd_key, sizeof (uint64_t), &lbl_str);
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
+ GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
+ &pub_key);
+
+ handle->token_ticket = GNUNET_IDENTITY_PROVIDER_ticket_create (nonce_str,
+ &pub_key,
+ lbl_str,
+ &aud_pkey);
+
+ if (GNUNET_OK != GNUNET_IDENTITY_PROVIDER_ticket_serialize (handle->token_ticket,
+ priv_key,
+ &token_ticket_str))
+ {
+ handle->emsg = GNUNET_strdup ("Unable to create ref token!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
+ strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
+ &key);
+ //Get expiration for token from URL parameter
+ exp_str = NULL;
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key))
+ {
+ exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ }
+ if (NULL == exp_str) {
+ handle->emsg = GNUNET_strdup ("No expiration given!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_fancy_time_to_relative (exp_str,
+ &etime_rel))
+ {
+ handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ time = GNUNET_TIME_absolute_get().abs_value_us;
+ exp_time = time + etime_rel.rel_value_us;
+
+ //json_object_set_new (handle->payload, "lbl", json_string (lbl_str));
+ GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "sub", handle->ego_entry->identifier);
+ GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "nbf", json_integer (time));
+ GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "iat", json_integer (time));
+ GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "exp", json_integer (exp_time));
+ GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "nonce", nonce_str);
+
+
+ handle->resp_object = GNUNET_REST_jsonapi_object_new ();
+
+ json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
+ lbl_str);
+ name_str = json_string (handle->ego_entry->identifier);
+ GNUNET_REST_jsonapi_resource_add_attr (json_resource,
+ GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
+ name_str);
+ json_decref (name_str);
+ token_str = json_string (enc_token_str);
+ GNUNET_REST_jsonapi_resource_add_attr (json_resource,
+ GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
+ token_str);
+ token_ticket_json = json_string (token_ticket_str);
+ GNUNET_REST_jsonapi_resource_add_attr (json_resource,
+ GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
+ token_ticket_json);
+ GNUNET_free (token_ticket_str);
+ json_decref (token_ticket_json);
+ GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
+ //Token in a serialized encrypted format
+ GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (handle->token,
+ priv_key,
+ &ecdhe_privkey,
+ &enc_token_str));
+
+ //Token record E,E_K (Token)
+ token_record[0].data = enc_token_str;
+ token_record[0].data_size = strlen (enc_token_str) + 1;
+ token_record[0].expiration_time = exp_time;
+ token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
+ token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
+
+
+ //Meta info
+ GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
+ strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
+ &key);
+
+ scopes = NULL;
+ if ( GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ handle->emsg = GNUNET_strdup ("Scopes missing!\n");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+
+ token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
+ + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
+ + strlen (scopes) + 1; //With 0-Terminator
+ token_metadata = GNUNET_malloc (token_metadata_len);
+ write_ptr = token_metadata;
+ memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
+ memcpy (write_ptr, &aud_pkey, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
+
+ GNUNET_free (ecdhe_privkey);
+
+ token_record[1].data = token_metadata;
+ token_record[1].data_size = token_metadata_len;
+ token_record[1].expiration_time = exp_time;
+ token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
+ token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
+
+ //Persist token
+ handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
+ priv_key,
+ lbl_str,
+ 2,
+ token_record,
+ &store_token_cont,
+ handle);
+ GNUNET_free (lbl_str);
+ GNUNET_free (enc_token_str);
+ json_decref (token_str);
+}
+
+
+
+
+
+static void
+attr_collect (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ int i;
+ char* data;
+ json_t *attr_arr;
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode key;
+
+ if (NULL == label)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
+ handle->ns_it = NULL;
+ GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
+ return;
+ }
+
+ GNUNET_CRYPTO_hash (label,
+ strlen (label),
+ &key);
+
+ if (0 == rd_count ||
+ ( (NULL != handle->attr_map) &&
+ (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
+ &key))
+ )
+ )
+ {
+ GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
+
+ if (1 == rd_count)
+ {
+ if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
+ {
+ data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
+ rd->data,
+ rd->data_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
+ GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, label, data);
+ GNUNET_free (data);
+ }
+ GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
+ return;
+ }
+
+ i = 0;
+ attr_arr = json_array();
+ for (; i < rd_count; i++)
+ {
+ if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
+ {
+ data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+ rd[i].data,
+ rd[i].data_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
+ json_array_append_new (attr_arr, json_string (data));
+ GNUNET_free (data);
+ }
+ }
+
+ if (0 < json_array_size (attr_arr))
+ {
+ GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, label, attr_arr);
+ }
+ json_decref (attr_arr);
+ GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
+}
+
+
+/**
+ * Create a response with requested ego(s)
+ *
+ * @param con the Rest handle
+ * @param url the requested url
+ * @param cls the request handle
+ */
+static void
+issue_token_cont (struct RestConnectionDataHandle *con,
+ const char *url,
+ void *cls)
+{
+ const char *egoname;
+ char *ego_val;
+ char *audience;
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct GNUNET_HashCode key;
+ struct MHD_Response *resp;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+ struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
+
+ if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
+ GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
+ resp = GNUNET_REST_create_json_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+ cleanup_handle (handle);
+ return;
+ }
+
+ egoname = NULL;
+ ego_entry = NULL;
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
+ &key);
+ if ( GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ if (NULL == ego_val)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
+ if (NULL != ego_val)
+ {
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;
+ ego_entry = ego_entry->next)
+ {
+ if (0 != strcmp (ego_val, ego_entry->identifier))
+ continue;
+ egoname = ego_entry->identifier;
+ break;
+ }
+ if (NULL == egoname || NULL == ego_entry)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
+ resp = GNUNET_REST_create_json_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+ cleanup_handle (handle);
+ return;
+ }
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
+ &key);
+
+ //Token audience
+ audience = NULL;
+ if ( GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
+ resp = GNUNET_REST_create_json_response (NULL);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+ cleanup_handle (handle);
+ return;
+ }
+ audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
+
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
+ GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
+ &pub_key);
+ GNUNET_STRINGS_string_to_data (audience,
+ strlen (audience),
+ &aud_key,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ handle->token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
+ aud_key);
+ GNUNET_free (aud_key);
+
+
+ //Get identity attributes
+ handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
+ handle->ego_entry = ego_entry;
+ handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
+ priv_key,
+ &attr_collect,
+ handle);
+}
+
+
+/**
+ * Build a GNUid token for identity
+ * @param handle the handle
+ * @param ego_entry the ego to build the token for
+ * @param name name of the ego
+ * @param token_aud token audience
+ * @param token the resulting gnuid token
+ * @return identifier string of token (label)
+ */
+static void
+return_token_list (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ char* result_str;
+ struct RequestHandle *handle = cls;
+ struct MHD_Response *resp;
+
+ GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
+ resp = GNUNET_REST_create_json_response (result_str);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ GNUNET_free (result_str);
+ cleanup_handle (handle);
+}
+
+/**
+ * Collect all tokens for ego
+ */
+static void
+token_collect (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ int i;
+ char* data;
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_tmp;
+ struct JsonApiResource *json_resource;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ json_t *issuer;
+ json_t *token;
+
+ if (NULL == label)
+ {
+ ego_tmp = handle->ego_head;
+ GNUNET_CONTAINER_DLL_remove (handle->ego_head,
+ handle->ego_tail,
+ ego_tmp);
+ GNUNET_free (ego_tmp->identifier);
+ GNUNET_free (ego_tmp->keystring);
+ GNUNET_free (ego_tmp);
+
+ if (NULL == handle->ego_head)
+ {
+ //Done
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
+ handle->ns_it = NULL;
+ GNUNET_SCHEDULER_add_now (&return_token_list, handle);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+ handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
+ priv_key,
+ &token_collect,
+ handle);
+ return;
+ }
+
+ for (i = 0; i < rd_count; i++)
+ {
+ if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
+ {
+ data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
+ rd[i].data,
+ rd[i].data_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
+ json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
+ label);
+ issuer = json_string (handle->ego_head->identifier);
+ GNUNET_REST_jsonapi_resource_add_attr (json_resource,
+ GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
+ issuer);
+ json_decref (issuer);
+ token = json_string (data);
+ GNUNET_REST_jsonapi_resource_add_attr (json_resource,
+ GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
+ token);
+ json_decref (token);
+
+ GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
+ GNUNET_free (data);
+ }
+ }
+
+ GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
+}
+
+
+
+/**
+ * Respond to OPTIONS request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+list_token_cont (struct RestConnectionDataHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ char* ego_val;
+ struct GNUNET_HashCode key;
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct EgoEntry *ego_tmp;
+
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
+ &key);
+
+ if ( GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ //Remove non-matching egos
+ for (ego_entry = handle->ego_head;
+ NULL != ego_entry;)
+ {
+ ego_tmp = ego_entry;
+ ego_entry = ego_entry->next;
+ if (0 != strcmp (ego_val, ego_tmp->identifier))
+ {
+ GNUNET_CONTAINER_DLL_remove (handle->ego_head,
+ handle->ego_tail,
+ ego_tmp);
+ GNUNET_free (ego_tmp->identifier);
+ GNUNET_free (ego_tmp->keystring);
+ GNUNET_free (ego_tmp);
+ }
+ }
+ }
+ handle->resp_object = GNUNET_REST_jsonapi_object_new ();
+ if (NULL == handle->ego_head)
+ {
+ //Done
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
+ GNUNET_SCHEDULER_add_now (&return_token_list, handle);
+ return;
+ }
+ priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
+ handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
+ handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
+ priv_key,
+ &token_collect,
+ handle);
+
+}
+
+
+
+
+static void
+process_lookup_result (void *cls, uint32_t rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
+{
+ struct RequestHandle *handle = cls;
+ json_t *root;
+ struct MHD_Response *resp;
+ char *result;
+ char* token_str;
+ char* record_str;
+
+ handle->lookup_request = NULL;
+ if (2 != rd_count)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Number of tokens %d != 2.",
+ rd_count);
+ handle->emsg = GNUNET_strdup ("Number of tokens != 2.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ root = json_object();
+ record_str =
+ GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
+ rd->data,
+ rd->data_size);
+
+ //Decrypt and parse
+ GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_parse (record_str,
+ handle->priv_key,
+ &handle->token));
+
+ //Readable
+ GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (handle->token,
+ handle->priv_key,
+ &token_str));
+
+ json_object_set_new (root, "access_token", json_string (token_str));
+ json_object_set_new (root, "token_type", json_string ("gnuid"));
+ GNUNET_free (token_str);
+ GNUNET_free (record_str);
+
+ result = json_dumps (root, JSON_INDENT(1));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", result);
+ resp = GNUNET_REST_create_json_response (result);
+ GNUNET_free (result);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ cleanup_handle (handle);
+ json_decref (root);
+}
+
+
+static void
+exchange_token_ticket_cb (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *name)
+{
+ struct RequestHandle *handle = cls;
+ struct GNUNET_HashCode key;
+ char* code;
+ char* lookup_query;
+
+ handle->op = NULL;
+
+ if (NULL == ego)
+ {
+ handle->emsg = GNUNET_strdup ("No GNS identity found.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_token_ticket),
+ &key);
+
+ if ( GNUNET_NO ==
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ handle->emsg = GNUNET_strdup ("No code given.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ code = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+
+ handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
+
+ if (GNUNET_SYSERR == GNUNET_IDENTITY_PROVIDER_ticket_parse (code,
+ handle->priv_key,
+ &handle->token_ticket))
+ {
+ handle->emsg = GNUNET_strdup ("Error extracting values from token code.");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
+ handle->token_ticket->payload->label);
+ handle->gns_handle = GNUNET_GNS_connect (cfg);
+ GNUNET_asprintf (&lookup_query, "%s.gnu", handle->token_ticket->payload->label);
+ handle->lookup_request = GNUNET_GNS_lookup (handle->gns_handle,
+ lookup_query,
+ &handle->token_ticket->payload->identity_key,
+ GNUNET_GNSRECORD_TYPE_ID_TOKEN,
+ GNUNET_GNS_LO_LOCAL_MASTER,
+ NULL,
+ &process_lookup_result,
+ handle);
+ GNUNET_free (lookup_query);
+}
+
+/**
+ * Respond to OAuth2 /token request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ struct RequestHandle *handle = cls;
+ char* grant_type;
+ struct GNUNET_HashCode key;
+
+ GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE,
+ strlen (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE),
+ &key);
+
+ if ( GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key) )
+ {
+ grant_type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ }
+
+ if (0 == strcmp ("authorization_code", grant_type)) {
+ //Get token from GNS
+ handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
+ "gns-master",
+ &exchange_token_ticket_cb,
+ handle);
+ }
+
+ //TODO fail here
+}
+
+/**
+ * Respond to OPTIONS request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+options_cont (struct RestConnectionDataHandle *con_handle,
+ const char* url,
+ void *cls)
+{
+ struct MHD_Response *resp;
+ struct RequestHandle *handle = cls;
+
+ //For now, independent of path return all options
+ resp = GNUNET_REST_create_json_response (NULL);
+ MHD_add_response_header (resp,
+ "Access-Control-Allow-Methods",
+ allow_methods);
+ handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+ cleanup_handle (handle);
+ return;
+}
+
+/**
+ * Handle rest request
+ *
+ * @param handle the request handle
+ */
+static void
+init_cont (struct RequestHandle *handle)
+{
+ static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
+ {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
+ //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
+ {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN, &list_token_cont},
+ {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_TOKEN, &options_cont},
+ {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
+ GNUNET_REST_HANDLER_END
+ };
+
+ if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
+ {
+ handle->emsg = GNUNET_strdup ("Request unsupported");
+ GNUNET_SCHEDULER_add_now (&do_error, handle);
+ }
+}
+
+/**
+ * If listing is enabled, prints information about the egos.
+ *
+ * This function is initially called for all egos and then again
+ * whenever a ego's identifier changes or if it is deleted. At the
+ * end of the initial pass over all egos, the function is once called
+ * with 'NULL' for 'ego'. That does NOT mean that the callback won't
+ * be invoked in the future or that there was an error.
+ *
+ * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
+ * this function is only called ONCE, and 'NULL' being passed in
+ * 'ego' does indicate an error (i.e. name is taken or no default
+ * value is known). If 'ego' is non-NULL and if '*ctx'
+ * is set in those callbacks, the value WILL be passed to a subsequent
+ * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
+ * that one was not NULL).
+ *
+ * When an identity is renamed, this function is called with the
+ * (known) ego but the NEW identifier.
+ *
+ * When an identity is deleted, this function is called with the
+ * (known) ego and "NULL" for the 'identifier'. In this case,
+ * the 'ego' is henceforth invalid (and the 'ctx' should also be
+ * cleaned up).
+ *
+ * @param cls closure
+ * @param ego ego handle
+ * @param ctx context for application to store data for this ego
+ * (during the lifetime of this process, initially NULL)
+ * @param identifier identifier assigned by the user for this ego,
+ * NULL if the user just deleted the ego and it
+ * must thus no longer be used
+ */
+static void
+list_ego (void *cls,
+ struct GNUNET_IDENTITY_Ego *ego,
+ void **ctx,
+ const char *identifier)
+{
+ struct RequestHandle *handle = cls;
+ struct EgoEntry *ego_entry;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+
+ if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
+ {
+ handle->state = ID_REST_STATE_POST_INIT;
+ init_cont (handle);
+ return;
+ }
+ if (ID_REST_STATE_INIT == handle->state) {
+ ego_entry = GNUNET_new (struct EgoEntry);
+ GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
+ ego_entry->keystring =
+ GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+ ego_entry->ego = ego;
+ GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
+ GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
+ }
+
+}
+
+/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+static void
+rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
+ GNUNET_REST_ResultProcessor proc,
+ void *proc_cls)
+{
+ struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+ struct GNUNET_HashCode key;
+ char* attr_list;
+ char* attr_list_tmp;
+ char* attr;
+
+ GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
+ strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
+ &key);
+
+ handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+ handle->proc_cls = proc_cls;
+ handle->proc = proc;
+ handle->state = ID_REST_STATE_INIT;
+ handle->conndata_handle = conndata_handle;
+ handle->data = conndata_handle->data;
+ handle->data_size = conndata_handle->data_size;
+ handle->method = conndata_handle->method;
+ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+ &key))
+ {
+ handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
+ GNUNET_NO);
+ attr_list = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+ &key);
+ if (NULL != attr_list)
+ {
+ attr_list_tmp = GNUNET_strdup (attr_list);
+ attr = strtok(attr_list_tmp, ",");
+ for (; NULL != attr; attr = strtok (NULL, ","))
+ {
+ GNUNET_CRYPTO_hash (attr,
+ strlen (attr),
+ &key);
+ GNUNET_CONTAINER_multihashmap_put (handle->attr_map,
+ &key,
+ attr,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+ }
+ GNUNET_free (attr_list_tmp);
+ }
+ }
+
+
+ GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
+ if (handle->url[strlen (handle->url)-1] == '/')
+ handle->url[strlen (handle->url)-1] = '\0';
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Connecting...\n");
+ handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
+ &list_ego,
+ handle);
+ handle->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (handle->timeout,
+ &do_error,
+ handle);
+
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Connected\n");
+}
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls Config info
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_rest_identity_token_init (void *cls)
+{
+ static struct Plugin plugin;
+ struct GNUNET_REST_Plugin *api;
+
+ cfg = cls;
+ if (NULL != plugin.cfg)
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof (struct Plugin));
+ plugin.cfg = cfg;
+ api = GNUNET_new (struct GNUNET_REST_Plugin);
+ api->cls = &plugin;
+ api->name = GNUNET_REST_API_NS_IDENTITY_TOKEN;
+ api->process_request = &rest_identity_process_request;
+ GNUNET_asprintf (&allow_methods,
+ "%s, %s, %s, %s, %s",
+ MHD_HTTP_METHOD_GET,
+ MHD_HTTP_METHOD_POST,
+ MHD_HTTP_METHOD_PUT,
+ MHD_HTTP_METHOD_DELETE,
+ MHD_HTTP_METHOD_OPTIONS);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Identity Token REST API initialized\n"));
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_rest_identity_token_done (void *cls)
+{
+ struct GNUNET_REST_Plugin *api = cls;
+ struct Plugin *plugin = api->cls;
+
+ plugin->cfg = NULL;
+ GNUNET_free_non_null (allow_methods);
+ GNUNET_free (api);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Identity Token REST plugin is finished\n");
+ return NULL;
+}
+
+/* end of plugin_rest_gns.c */
+++ /dev/null
-# This Makefile.am is in the public domain
-AM_CPPFLAGS = -I$(top_srcdir)/src/include
-
- plugindir = $(libdir)/gnunet
-
-if MINGW
- WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
-endif
-
-if USE_COVERAGE
- AM_CFLAGS = --coverage -O0
- XLIB = -lgcov
-endif
-
-pkgcfgdir= $(pkgdatadir)/config.d/
-
-libexecdir= $(pkglibdir)/libexec/
-
-pkgcfg_DATA = \
- identity-token.conf
-
-plugin_LTLIBRARIES = \
- libgnunet_plugin_rest_identity_token.la
-lib_LTLIBRARIES = \
- libgnunetidentityprovider.la
-
-bin_PROGRAMS = \
- gnunet-identity-token
-
-libexec_PROGRAMS = \
- gnunet-service-identity-token
-
-gnunet_service_identity_token_SOURCES = \
- gnunet-service-identity-token.c
-gnunet_service_identity_token_LDADD = \
- libgnunetidentityprovider.la \
- $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/namestore/libgnunetnamestore.la \
- $(top_builddir)/src/identity/libgnunetidentity.la \
- $(GN_LIBINTL) \
- -ljansson
-
-libgnunetidentityprovider_la_SOURCES = \
- identity-token.c
-libgnunetidentityprovider_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
- $(LTLIBINTL) -ljansson
-
-libgnunet_plugin_rest_identity_token_la_SOURCES = \
- plugin_rest_identity_token.c
-libgnunet_plugin_rest_identity_token_la_LIBADD = \
- $(top_builddir)/src/identity/libgnunetidentity.la \
- $(top_builddir)/src/rest/libgnunetrest.la \
- $(top_builddir)/src/namestore/libgnunetnamestore.la \
- $(top_builddir)/src/gns/libgnunetgns.la \
- $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
- $(LTLIBINTL) -ljansson -lmicrohttpd
-libgnunet_plugin_rest_identity_token_la_LDFLAGS = \
- $(GN_PLUGIN_LDFLAGS)
-
-
-gnunet_identity_token_SOURCES = \
- gnunet-identity-token.c
-gnunet_identity_token_LDADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- -ljansson -lmicrohttpd \
- $(GN_LIBINTL)
-
-
+++ /dev/null
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include <jansson.h>
-#include "gnunet_signatures.h"
-
-/**
- * The token
- */
-static char* token;
-
-/**
- * Weather to print the token
- */
-static int print_token;
-
-static void
-run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
-{
- char* payload;
- char* header;
- //Get token parts
- char* header_b64 = strtok (token, ".");
- char* payload_b64 = strtok(NULL, ".");
- char* signature_b32 = strtok(NULL, ".");
- const char* keystring;
- char* data;
- json_t *payload_json;
- json_t *keystring_json;
- json_error_t error;
- struct GNUNET_CRYPTO_EcdsaPublicKey key;
- struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
- struct GNUNET_CRYPTO_EcdsaSignature sig;
- //Decode payload
- GNUNET_STRINGS_base64_decode (payload_b64,
- strlen (payload_b64),
- &payload);
- //Decode header
- GNUNET_STRINGS_base64_decode (header_b64,
- strlen (header_b64),
- &header);
- if (NULL == token)
- return;
-
-
- GNUNET_asprintf(&data,
- "%s,%s",
- header_b64,
- payload_b64);
- char *val = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
- purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose*)val;
- purpose->size = htonl(sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data));
- purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
- memcpy (&purpose[1], data, strlen(data));
-
-
- payload_json = json_loads (payload, 0, &error);
- if ((NULL == payload_json) || !json_is_object (payload_json))
- {
- return;
- }
- keystring_json = json_object_get (payload_json, "iss");
- if (!json_is_string (keystring_json))
- {
- return;
- }
- keystring = json_string_value (keystring_json);
- if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (keystring,
- strlen (keystring),
- &key))
- {
- return;
- }
- GNUNET_STRINGS_string_to_data (signature_b32,
- strlen (signature_b32),
- &sig,
- sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
-
- if (print_token) {
- printf ("Token:\nHeader:\t\t%s\nPayload:\t%s\nSignature:\t%s\n", header, payload, keystring);
- }
-
- if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN,
- purpose,
- &sig,
- &key))
- {
- printf("Signature not OK!\n");
- return;
- }
- printf("Signature OK!\n");
- return;
-}
-int
-main(int argc, char *const argv[])
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- {'t', "token", NULL,
- gettext_noop ("GNUid token"), 1,
- &GNUNET_GETOPT_set_string, &token},
- {'p', "print", NULL,
- gettext_noop ("Print token contents"), 0,
- &GNUNET_GETOPT_set_one, &print_token},
-
- GNUNET_GETOPT_OPTION_END
- };
- return GNUNET_PROGRAM_run (argc, argv, "ct",
- "ct", options,
- &run, NULL);
-}
-
-
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
- */
-/**
- * @author Martin Schanzenbach
- * @file src/rest/gnunet-service-identity-token.c
- * @brief Identity Token Service
- *
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_identity_service.h"
-#include "gnunet_gnsrecord_lib.h"
-#include "gnunet_namestore_service.h"
-#include <jansson.h>
-#include "gnunet_signatures.h"
-#include "gnunet_identity_provider_lib.h"
-
-/**
- * First pass state
- */
-#define STATE_INIT 0
-
-/**
- * Normal operation state
- */
-#define STATE_POST_INIT 1
-
-/**
- * Minimum interval between updates
- */
-#define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
-
-/**
- * Service state (to detect initial update pass)
- */
-static int state;
-
-/**
- * Head of ego entry DLL
- */
-static struct EgoEntry *ego_head;
-
-/**
- * Tail of ego entry DLL
- */
-static struct EgoEntry *ego_tail;
-
-/**
- * Identity handle
- */
-static struct GNUNET_IDENTITY_Handle *identity_handle;
-
-/**
- * Namestore handle
- */
-static struct GNUNET_NAMESTORE_Handle *ns_handle;
-
-/**
- * Namestore qe
- */
-static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
-
-/**
- * Namestore iterator
- */
-static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
-
-/**
- * Timeout task
- */
-static struct GNUNET_SCHEDULER_Task * timeout_task;
-
-
-/**
- * Update task
- */
-static struct GNUNET_SCHEDULER_Task * update_task;
-
-/**
- * Timeout for next update pass
- */
-static struct GNUNET_TIME_Relative min_rel_exp;
-
-
-/**
- * Currently processed token
- */
-static struct GNUNET_IDENTITY_PROVIDER_Token *token;
-
-/**
- * Label for currently processed token
- */
-static char* label;
-
-/**
- * Scopes for processed token
- */
-static char* scopes;
-
-/**
- * Expiration for processed token
- */
-static uint64_t rd_exp;
-
-/**
- * ECDHE Privkey for processed token metadata
- */
-static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
-
-/**
- * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
- *
- */
-struct EgoEntry
-{
- /**
- * DLL
- */
- struct EgoEntry *next;
-
- /**
- * DLL
- */
- struct EgoEntry *prev;
-
- /**
- * Ego handle
- */
- struct GNUNET_IDENTITY_Ego *ego;
-
- /**
- * Attribute map. Contains the attributes as json_t
- */
- struct GNUNET_CONTAINER_MultiHashMap *attr_map;
-
- /**
- * Attributes are old and should be updated if GNUNET_YES
- */
- int attributes_dirty;
-};
-
-/**
- * Our configuration.
- */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Continuation for token store call
- *
- * @param cls NULL
- * @param success error code
- * @param emsg error message
- */
-static void
-store_token_cont (void *cls,
- int32_t success,
- const char *emsg)
-{
- ns_qe = NULL;
- if (GNUNET_SYSERR == success)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to update token: %s\n",
- emsg);
- return;
- }
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
-}
-
-
-/**
- * This function updates the old token with new attributes,
- * removes deleted attributes and expiration times.
- *
- * @param cls the ego entry
- * @param tc task context
- */
-static void
-handle_token_update (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- char *token_metadata;
- char *write_ptr;
- char *enc_token_str;
- const char *key;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
- struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
- struct EgoEntry *ego_entry = cls;
- struct GNUNET_GNSRECORD_Data token_record[2];
- struct GNUNET_HashCode key_hash;
- struct GNUNET_TIME_Relative token_rel_exp;
- struct GNUNET_TIME_Relative token_ttl;
- struct GNUNET_TIME_Absolute token_exp;
- struct GNUNET_TIME_Absolute token_nbf;
- struct GNUNET_TIME_Absolute new_exp;
- struct GNUNET_TIME_Absolute new_iat;
- struct GNUNET_TIME_Absolute new_nbf;
- struct GNUNET_IDENTITY_PROVIDER_Token *new_token;
- json_t *payload_json;
- json_t *value;
- json_t *cur_value;
- json_t *token_nbf_json;
- json_t *token_exp_json;
- size_t token_metadata_len;
-
- priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
- GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
- &pub_key);
-
- //Note: We need the token expiration time here. Not the record expiration
- //time.
- //There are two types of tokens: Token that expire on GNS level with
- //an absolute expiration time. Those are basically tokens that will
- //be automatically revoked on (record)expiration.
- //Tokens stored with relative expiration times will expire on the token level (token expiration)
- //but this service will reissue new tokens that can be retrieved from GNS
- //automatically.
-
- payload_json = token->payload;
-
- token_exp_json = json_object_get (payload_json, "exp");
- token_nbf_json = json_object_get (payload_json, "nbf");
- token_exp.abs_value_us = json_integer_value(token_exp_json);
- token_nbf.abs_value_us = json_integer_value(token_nbf_json);
- token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
-
- token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
- if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
- {
- //This token is not yet expired! Save and skip
- if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
- {
- min_rel_exp = token_ttl;
- }
- json_decref (payload_json);
- GNUNET_free (token);
- token = NULL;
- GNUNET_free (label);
- label = NULL;
- GNUNET_free (scopes);
- scopes = NULL;
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Token is expired. Create a new one\n");
- new_token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
- &token->aud_key);
- new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
- new_nbf = GNUNET_TIME_absolute_get ();
- new_iat = new_nbf;
-
- json_object_foreach(payload_json, key, value) {
- if (0 == strcmp (key, "exp"))
- {
- GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_exp.abs_value_us));
- }
- else if (0 == strcmp (key, "nbf"))
- {
- GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_nbf.abs_value_us));
- }
- else if (0 == strcmp (key, "iat"))
- {
- GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, json_integer (new_iat.abs_value_us));
- }
- else if ((0 == strcmp (key, "iss"))
- || (0 == strcmp (key, "aud")))
- {
- //Omit
- }
- else if ((0 == strcmp (key, "sub"))
- || (0 == strcmp (key, "rnl")))
- {
- GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, value);
- }
- else {
- GNUNET_CRYPTO_hash (key,
- strlen (key),
- &key_hash);
- //Check if attr still exists. omit of not
- if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
- &key_hash))
- {
- cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
- &key_hash);
- GNUNET_IDENTITY_PROVIDER_token_add_json (new_token, key, cur_value);
- }
- }
- }
-
- // reassemble and set
- GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (new_token,
- priv_key,
- &new_ecdhe_privkey,
- &enc_token_str));
-
- json_decref (payload_json);
-
- token_record[0].data = enc_token_str;
- token_record[0].data_size = strlen (enc_token_str) + 1;
- token_record[0].expiration_time = rd_exp; //Old expiration time
- token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
- token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
-
- //Meta
- token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
- + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
- + strlen (scopes) + 1; //With 0-Terminator
- token_metadata = GNUNET_malloc (token_metadata_len);
- write_ptr = token_metadata;
- memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
- memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
- memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
-
- token_record[1].data = token_metadata;
- token_record[1].data_size = token_metadata_len;
- token_record[1].expiration_time = rd_exp;
- token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
- token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
-
- ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
- priv_key,
- label,
- 2,
- token_record,
- &store_token_cont,
- ego_entry);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
- GNUNET_IDENTITY_PROVIDER_token_destroy (new_token);
- GNUNET_IDENTITY_PROVIDER_token_destroy (token);
- GNUNET_free (new_ecdhe_privkey);
- GNUNET_free (enc_token_str);
- token = NULL;
- GNUNET_free (label);
- label = NULL;
- GNUNET_free (scopes);
- scopes = NULL;
-}
-
-static void
-update_identities(void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
-
-/**
- *
- * Cleanup attr_map
- *
- * @param cls NULL
- * @param key the key
- * @param value the json_t attribute value
- * @return GNUNET_YES
- */
-static int
-clear_ego_attrs (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
-{
- json_t *attr_value = value;
-
- json_decref (attr_value);
-
- return GNUNET_YES;
-}
-
-
-/**
- *
- * Update all ID_TOKEN records for an identity and store them
- *
- * @param cls the identity entry
- * @param zone the identity
- * @param lbl the name of the record
- * @param rd_count number of records
- * @param rd record data
- *
- */
-static void
-token_collect (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *lbl,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct EgoEntry *ego_entry = cls;
- const struct GNUNET_GNSRECORD_Data *token_record;
- const struct GNUNET_GNSRECORD_Data *token_metadata_record;
- struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
-
- if (NULL == lbl)
- {
- //Done
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- ">>> Updating Ego finished\n");
- //Clear attribute map for ego
- GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
- &clear_ego_attrs,
- ego_entry);
- GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
- GNUNET_SCHEDULER_add_now (&update_identities, ego_entry->next);
- return;
- }
-
- //There should be only a single record for a token under a label
- if (2 != rd_count)
- {
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
- return;
- }
-
- if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
- {
- token_metadata_record = &rd[0];
- token_record = &rd[1];
- } else {
- token_record = &rd[0];
- token_metadata_record = &rd[1];
- }
- GNUNET_assert (token_metadata_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA);
- GNUNET_assert (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN);
-
- //Get metadata and decrypt token
- ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
- aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
- scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
- GNUNET_IDENTITY_PROVIDER_token_parse2 (token_record->data,
- &ecdhe_privkey,
- aud_key,
- &token);
-
- //token = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- // rd->data,
- // rd->data_size);
- label = GNUNET_strdup (lbl);
- rd_exp = token_record->expiration_time;
-
- GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
-}
-
-
-/**
- *
- * Collect all ID_ATTR records for an identity and store them
- *
- * @param cls the identity entry
- * @param zone the identity
- * @param lbl the name of the record
- * @param rd_count number of records
- * @param rd record data
- *
- */
-static void
-attribute_collect (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *lbl,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct EgoEntry *ego_entry = cls;
- json_t *attr_value;
- struct GNUNET_HashCode key;
- char* attr;
- int i;
-
- if (NULL == lbl)
- {
- //Done
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- ">>> Updating Attributes finished\n");
- ego_entry->attributes_dirty = GNUNET_NO;
- GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
- return;
- }
-
- if (0 == rd_count)
- {
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
- return;
- }
- GNUNET_CRYPTO_hash (lbl,
- strlen (lbl),
- &key);
- if (1 == rd_count)
- {
- if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
- {
- attr = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- rd->data,
- rd->data_size);
- attr_value = json_string (attr);
- GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
- &key,
- attr_value,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- GNUNET_free (attr);
- }
-
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
- return;
- }
-
- attr_value = json_array();
- for (i = 0; i < rd_count; i++)
- {
- if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
- {
- attr = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
- rd[i].data,
- rd[i].data_size);
- json_array_append_new (attr_value, json_string (attr));
- GNUNET_free (attr);
- }
-
- }
- GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
- &key,
- attr_value,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
- GNUNET_NAMESTORE_zone_iterator_next (ns_it);
- return;
-}
-
-/**
- *
- * Update identity information for ego. If attribute map is
- * dirty, first update the attributes.
- *
- * @param cls the ego to update
- * param tc task context
- *
- */
-static void
-update_identities(void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct EgoEntry *next_ego = cls;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- if (NULL == next_ego)
- {
- if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
- min_rel_exp = MIN_WAIT_TIME;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- ">>> Finished. Rescheduling in %d\n",
- min_rel_exp.rel_value_us);
- ns_it = NULL;
- //finished -> TODO reschedule
- update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
- &update_identities,
- ego_head);
- min_rel_exp.rel_value_us = 0;
- return;
- }
- priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
- if (GNUNET_YES == next_ego->attributes_dirty)
- {
- //Starting over. We must update the Attributes for they might have changed.
- ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
- priv_key,
- &attribute_collect,
- next_ego);
-
- }
- else
- {
- //Ego will be dirty next time
- next_ego->attributes_dirty = GNUNET_YES;
- ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
- priv_key,
- &token_collect,
- next_ego);
- }
-}
-
-
-
-/**
- * Function called initially to start update task
- */
-static void
-init_cont ()
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
- //Initially iterate all itenties and refresh all tokens
- update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
-}
-
-/**
- * Initial ego collection function.
- *
- * @param cls NULL
- * @param ego ego
- * @param ctx context
- * @param identifier ego name
- */
-static void
-list_ego (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *identifier)
-{
- struct EgoEntry *new_entry;
- if ((NULL == ego) && (STATE_INIT == state))
- {
- state = STATE_POST_INIT;
- init_cont ();
- return;
- }
- if (STATE_INIT == state) {
- new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
- new_entry->ego = ego;
- new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
- GNUNET_NO);
- new_entry->attributes_dirty = GNUNET_YES;
- GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
- }
-}
-
-/**
- * Cleanup task
- */
-static void
-cleanup()
-{
- struct EgoEntry *ego_entry;
- struct EgoEntry *ego_tmp;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Cleaning up\n");
- if (NULL != timeout_task)
- GNUNET_SCHEDULER_cancel (timeout_task);
- if (NULL != update_task)
- GNUNET_SCHEDULER_cancel (update_task);
- if (NULL != identity_handle)
- GNUNET_IDENTITY_disconnect (identity_handle);
- if (NULL != ns_it)
- GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
- if (NULL != ns_qe)
- GNUNET_NAMESTORE_cancel (ns_qe);
- if (NULL != ns_handle)
- GNUNET_NAMESTORE_disconnect (ns_handle);
- if (NULL != token)
- GNUNET_free (token);
- if (NULL != label)
- GNUNET_free (label);
-
- for (ego_entry = ego_head;
- NULL != ego_entry;)
- {
- ego_tmp = ego_entry;
- if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
- {
- GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
- &clear_ego_attrs,
- ego_tmp);
-
- }
- GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
- ego_entry = ego_entry->next;
- GNUNET_free (ego_tmp);
- }
-}
-
-/**
- * Shutdown task
- *
- * @param cls NULL
- * @param tc task context
- */
-static void
-do_shutdown (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Shutting down...\n");
- cleanup();
-}
-
-/**
- * Main function that will be run
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL)
- * @param c configuration
- */
-static void
-run (void *cls,
- char *const *args,
- const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *c)
-{
- cfg = c;
-
-
- //Connect to identity and namestore services
- ns_handle = GNUNET_NAMESTORE_connect (cfg);
- if (NULL == ns_handle)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
- }
-
- identity_handle = GNUNET_IDENTITY_connect (cfg,
- &list_ego,
- NULL);
-
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
-}
-
-
-/**
- *
- * The main function for gnunet-service-identity-token
- *
- * @param argc number of arguments from the cli
- * @param argv command line arguments
- * @return 0 ok, 1 on error
- *
- */
-int
-main (int argc, char *const *argv)
-{
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_END
- };
- int ret;
-
- if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
- return 2;
- GNUNET_log_setup ("gnunet-service-identity-token", "WARNING", NULL);
- ret =
- (GNUNET_OK ==
- GNUNET_PROGRAM_run (argc, argv, "gnunet-service-identity-token",
- _("GNUnet identity token service"),
- options,
- &run, NULL)) ? 0: 1;
- GNUNET_free_non_null ((char *) argv);
- return ret;
-}
-
-/* end of gnunet-rest-server.c */
+++ /dev/null
-/*
- This file is part of GNUnet
- Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
- */
-
-/**
- * @file identity-token/identity-token.c
- * @brief helper library to manage identity tokens
- * @author Martin Schanzenbach
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_signatures.h"
-#include "gnunet_identity_provider_lib.h"
-#include <jansson.h>
-
-
-/**
- * Crypto helper functions
- */
-
-static int
-create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
- struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
- struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
-{
- struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
-
- GNUNET_CRYPTO_hash_to_enc (new_key_hash,
- &new_key_hash_str);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
- static const char ctx_key[] = "gnuid-aes-ctx-key";
- GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
- new_key_hash, sizeof (struct GNUNET_HashCode),
- ctx_key, strlen (ctx_key),
- NULL, 0);
- static const char ctx_iv[] = "gnuid-aes-ctx-iv";
- GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
- new_key_hash, sizeof (struct GNUNET_HashCode),
- ctx_iv, strlen (ctx_iv),
- NULL, 0);
- return GNUNET_OK;
-}
-
-
-
-/**
- * Decrypts metainfo part from a token code
- */
-static int
-decrypt_str_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key,
- const char *cyphertext,
- size_t cyphertext_len,
- char **result_str)
-{
- struct GNUNET_HashCode new_key_hash;
- struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
- struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
-
- char *str_buf = GNUNET_malloc (cyphertext_len);
- size_t str_size;
-
- //Calculate symmetric key from ecdh parameters
- GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_ecdh (priv_key,
- ecdh_key,
- &new_key_hash));
-
- create_sym_key_from_ecdh (&new_key_hash,
- &enc_key,
- &enc_iv);
-
- str_size = GNUNET_CRYPTO_symmetric_decrypt (cyphertext,
- cyphertext_len,
- &enc_key,
- &enc_iv,
- str_buf);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Decrypted bytes: %d Expected bytes: %d\n", str_size, cyphertext_len);
- if (-1 == str_size)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH invalid\n");
- GNUNET_free (str_buf);
- return GNUNET_SYSERR;
- }
- *result_str = GNUNET_malloc (str_size+1);
- memcpy (*result_str, str_buf, str_size);
- (*result_str)[str_size] = '\0';
- GNUNET_free (str_buf);
- return GNUNET_OK;
-
-}
-
-/**
- * Decrypt string using pubkey and ECDHE
-*/
-static int
-decrypt_str_ecdhe2 (const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_privkey,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
- const char *ciphertext,
- size_t ciphertext_len,
- char **plaintext)
-{
- struct GNUNET_CRYPTO_SymmetricSessionKey skey;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_HashCode new_key_hash;
-
- //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
- *plaintext = GNUNET_malloc (ciphertext_len);
-
- // Derived key K = H(eB)
- GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (ecdh_privkey,
- aud_key,
- &new_key_hash));
- create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
- GNUNET_CRYPTO_symmetric_decrypt (ciphertext,
- ciphertext_len,
- &skey, &iv,
- *plaintext);
- return GNUNET_OK;
-}
-
-
-/**
- * Encrypt string using pubkey and ECDHE
- * Returns ECDHE pubkey to be used for decryption
- */
-static int
-encrypt_str_ecdhe (const char *plaintext,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key,
- char **cyphertext,
- struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
- struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pubkey)
-{
- struct GNUNET_CRYPTO_SymmetricSessionKey skey;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
- struct GNUNET_HashCode new_key_hash;
- ssize_t enc_size;
-
- // ECDH keypair E = eG
- *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
- GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
- ecdh_pubkey);
-
- //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt
- *cyphertext = GNUNET_malloc (strlen (plaintext));
-
- // Derived key K = H(eB)
- GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
- pub_key,
- &new_key_hash));
- create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypting string %s\n (len=%d)",
- plaintext,
- strlen (plaintext));
- enc_size = GNUNET_CRYPTO_symmetric_encrypt (plaintext, strlen (plaintext),
- &skey, &iv,
- *cyphertext);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encrypted (len=%d)", enc_size);
- return GNUNET_OK;
-}
-
-
-
-
-/**
- * Identity Token API
- */
-
-
-/**
- * Create an Identity Token
- *
- * @param type the JSON API resource type
- * @param id the JSON API resource id
- * @return a new JSON API resource or NULL on error.
- */
-struct GNUNET_IDENTITY_PROVIDER_Token*
-GNUNET_IDENTITY_PROVIDER_token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey* iss,
- const struct GNUNET_CRYPTO_EcdsaPublicKey* aud)
-{
- struct GNUNET_IDENTITY_PROVIDER_Token *token;
- char* audience;
- char* issuer;
-
- issuer = GNUNET_STRINGS_data_to_string_alloc (iss,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
- audience = GNUNET_STRINGS_data_to_string_alloc (aud,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
-
-
- token = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
-
- token->header = json_object();
- token->payload = json_object();
-
- json_object_set_new (token->header, "alg", json_string ("ED512"));
- json_object_set_new (token->header, "typ", json_string ("JWT"));
-
- json_object_set_new (token->payload, "iss", json_string (issuer));
- json_object_set_new (token->payload, "aud", json_string (audience));
-
- token->aud_key = *aud;
- GNUNET_free (issuer);
- GNUNET_free (audience);
- return token;
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_token_destroy (struct GNUNET_IDENTITY_PROVIDER_Token *token)
-{
- json_decref (token->header);
- json_decref (token->payload);
- GNUNET_free (token);
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_token_add_attr (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const char* key,
- const char* value)
-{
- GNUNET_assert (NULL != token);
- GNUNET_assert (NULL != token->payload);
-
- json_object_set_new (token->payload, key, json_string (value));
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_token_add_json (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const char* key,
- json_t* value)
-{
- GNUNET_assert (NULL != token);
- GNUNET_assert (NULL != token->payload);
-
- json_object_set_new (token->payload, key, value);
-}
-
-
-int
-GNUNET_IDENTITY_PROVIDER_token_parse2 (const char* raw_data,
- const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
- struct GNUNET_IDENTITY_PROVIDER_Token **result)
-{
- char *enc_token_str;
- char *tmp_buf;
- char *token_str;
- char *enc_token;
- char *header;
- char *header_base64;
- char *payload;
- char *payload_base64;
- size_t enc_token_len;
- json_error_t err_json;
-
- GNUNET_asprintf (&tmp_buf, "%s", raw_data);
- strtok (tmp_buf, ",");
- enc_token_str = strtok (NULL, ",");
-
- enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
- strlen (enc_token_str),
- &enc_token);
- if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key,
- aud_key,
- enc_token,
- enc_token_len,
- &token_str))
- {
- GNUNET_free (tmp_buf);
- GNUNET_free (enc_token);
- return GNUNET_SYSERR;
- }
-
- header_base64 = strtok (token_str, ".");
- payload_base64 = strtok (NULL, ".");
-
- GNUNET_STRINGS_base64_decode (header_base64,
- strlen (header_base64),
- &header);
- GNUNET_STRINGS_base64_decode (payload_base64,
- strlen (payload_base64),
- &payload);
- //TODO signature
-
-
- *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
- (*result)->aud_key = *aud_key;
- (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
- (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
- GNUNET_free (enc_token);
- GNUNET_free (token_str);
- GNUNET_free (tmp_buf);
- GNUNET_free (payload);
- GNUNET_free (header);
- return GNUNET_OK;
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_token_parse (const char* raw_data,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_IDENTITY_PROVIDER_Token **result)
-{
- char *ecdh_pubkey_str;
- char *enc_token_str;
- char *tmp_buf;
- char *token_str;
- char *enc_token;
- char *header;
- char *header_base64;
- char *payload;
- char *payload_base64;
- size_t enc_token_len;
- json_error_t err_json;
- struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
-
- GNUNET_asprintf (&tmp_buf, "%s", raw_data);
- ecdh_pubkey_str = strtok (tmp_buf, ",");
- enc_token_str = strtok (NULL, ",");
-
- GNUNET_STRINGS_string_to_data (ecdh_pubkey_str,
- strlen (ecdh_pubkey_str),
- &ecdh_pubkey,
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
- enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str,
- strlen (enc_token_str),
- &enc_token);
- if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
- &ecdh_pubkey,
- enc_token,
- enc_token_len,
- &token_str))
- {
- GNUNET_free (tmp_buf);
- GNUNET_free (enc_token);
- return GNUNET_SYSERR;
- }
-
- header_base64 = strtok (token_str, ".");
- payload_base64 = strtok (NULL, ".");
-
- GNUNET_STRINGS_base64_decode (header_base64,
- strlen (header_base64),
- &header);
- GNUNET_STRINGS_base64_decode (payload_base64,
- strlen (payload_base64),
- &payload);
- //TODO signature and aud key
-
-
- *result = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Token));
- (*result)->header = json_loads (header, JSON_DECODE_ANY, &err_json);
- (*result)->payload = json_loads (payload, JSON_DECODE_ANY, &err_json);
- GNUNET_free (enc_token);
- GNUNET_free (token_str);
- GNUNET_free (tmp_buf);
- GNUNET_free (payload);
- GNUNET_free (header);
- return GNUNET_OK;
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- char **result)
-{
- char *payload_str;
- char *header_str;
- char *payload_base64;
- char *header_base64;
- char *padding;
- char *signature_target;
- char *signature_str;
- struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
- header_str = json_dumps (token->header, JSON_COMPACT);
- GNUNET_STRINGS_base64_encode (header_str,
- strlen (header_str),
- &header_base64);
- //Remove GNUNET padding of base64
- padding = strtok(header_base64, "=");
- while (NULL != padding)
- padding = strtok(NULL, "=");
-
- payload_str = json_dumps (token->payload, JSON_COMPACT);
- GNUNET_STRINGS_base64_encode (payload_str,
- strlen (payload_str),
- &payload_base64);
-
- //Remove GNUNET padding of base64
- padding = strtok(payload_base64, "=");
- while (NULL != padding)
- padding = strtok(NULL, "=");
-
- GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64);
- purpose =
- GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- strlen (signature_target));
- purpose->size =
- htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
- purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
- memcpy (&purpose[1], signature_target, strlen (signature_target));
- if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
- purpose,
- (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature))
- {
- GNUNET_free (signature_target);
- GNUNET_free (payload_str);
- GNUNET_free (header_str);
- GNUNET_free (payload_base64);
- GNUNET_free (header_base64);
- GNUNET_free (purpose);
- return GNUNET_SYSERR;
- }
-
- GNUNET_STRINGS_base64_encode ((const char*)&token->signature,
- sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
- &signature_str);
- GNUNET_asprintf (result, "%s.%s.%s",
- header_base64, payload_base64, signature_str);
- GNUNET_free (signature_target);
- GNUNET_free (payload_str);
- GNUNET_free (header_str);
- GNUNET_free (signature_str);
- GNUNET_free (payload_base64);
- GNUNET_free (header_base64);
- GNUNET_free (purpose);
- return GNUNET_OK;
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_token_serialize (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
- char **result)
-{
- char *token_str;
- char *enc_token;
- char *dh_key_str;
- char *enc_token_base64;
- struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
-
- GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (token,
- priv_key,
- &token_str));
-
- GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str,
- &token->aud_key,
- &enc_token,
- ecdh_privkey,
- &ecdh_pubkey));
- GNUNET_STRINGS_base64_encode (enc_token,
- strlen (token_str),
- &enc_token_base64);
- dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey,
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
- GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64);
- GNUNET_free (dh_key_str);
- GNUNET_free (enc_token_base64);
- GNUNET_free (enc_token);
- GNUNET_free (token_str);
- return GNUNET_OK;
-}
-
-struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload*
-GNUNET_IDENTITY_PROVIDER_ticket_payload_create (const char* nonce,
- const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
- const char* lbl_str)
-{
- struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload;
-
- payload = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload));
- GNUNET_asprintf (&payload->nonce, nonce, strlen (nonce));
- payload->identity_key = *identity_pkey;
- GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str));
- return payload;
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload* payload)
-{
- GNUNET_free (payload->nonce);
- GNUNET_free (payload->label);
- GNUNET_free (payload);
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *payload,
- char **result)
-{
- char* identity_key_str;
-
- identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
- GNUNET_asprintf (result,
- "{\"nonce\": \"%u\",\"identity\": \"%s\",\"label\": \"%s\"}",
- payload->nonce, identity_key_str, payload->label);
- GNUNET_free (identity_key_str);
-
-}
-
-
-/**
- * Create the token code
- * The metadata is encrypted with a share ECDH derived secret using B (aud_key)
- * and e (ecdh_privkey)
- * The ticket also contains E (ecdh_pubkey) and a signature over the
- * metadata and E
- */
-struct GNUNET_IDENTITY_PROVIDER_TokenTicket*
-GNUNET_IDENTITY_PROVIDER_ticket_create (const char* nonce_str,
- const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey,
- const char* lbl_str,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key)
-{
- struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
- struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *code_payload;
-
- ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
- code_payload = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
- identity_pkey,
- lbl_str);
- ticket->aud_key = *aud_key;
- ticket->payload = code_payload;
-
-
- return ticket;
-}
-
-void
-GNUNET_IDENTITY_PROVIDER_ticket_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket)
-{
- GNUNET_IDENTITY_PROVIDER_ticket_payload_destroy (ticket->payload);
- GNUNET_free (ticket);
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_ticket_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- char **result)
-{
- char *code_payload_str;
- char *enc_ticket_payload;
- char *ticket_payload_str;
- char *ticket_sig_str;
- char *ticket_str;
- char *dh_key_str;
- char *write_ptr;
- struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
-
- struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
-
- GNUNET_IDENTITY_PROVIDER_ticket_payload_serialize (ticket->payload,
- &code_payload_str);
-
- GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str,
- &ticket->aud_key,
- &enc_ticket_payload,
- &ecdhe_privkey,
- &ticket->ecdh_pubkey));
-
- GNUNET_free (ecdhe_privkey);
-
- purpose =
- GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
- strlen (code_payload_str)); // E_K (code_str)
- purpose->size =
- htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
- strlen (code_payload_str));
- purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
- write_ptr = (char*) &purpose[1];
- memcpy (write_ptr,
- &ticket->ecdh_pubkey,
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
- memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
- GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
- purpose,
- &ticket->signature));
- GNUNET_STRINGS_base64_encode (enc_ticket_payload,
- strlen (code_payload_str),
- &ticket_payload_str);
- ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature,
- sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
-
- dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey,
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s to encrypt\n", dh_key_str);
- GNUNET_asprintf (&ticket_str, "{\"meta\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}",
- ticket_payload_str, dh_key_str, ticket_sig_str);
- GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result);
- GNUNET_free (dh_key_str);
- GNUNET_free (purpose);
- GNUNET_free (ticket_str);
- GNUNET_free (ticket_sig_str);
- GNUNET_free (code_payload_str);
- GNUNET_free (enc_ticket_payload);
- GNUNET_free (ticket_payload_str);
- return GNUNET_OK;
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_ticket_payload_parse(const char *raw_data,
- ssize_t data_len,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey,
- struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload **result)
-{
- const char* label_str;
- const char* nonce_str;
- const char* identity_key_str;
-
- json_t *root;
- json_t *label_json;
- json_t *identity_json;
- json_t *nonce_json;
- json_error_t err_json;
- char* meta_str;
- struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey;
-
- if (GNUNET_OK != decrypt_str_ecdhe (priv_key,
- ecdhe_pkey,
- raw_data,
- data_len,
- &meta_str))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata decryption failed\n");
- return GNUNET_SYSERR;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Metadata: %s\n", meta_str);
- root = json_loads (meta_str, JSON_DECODE_ANY, &err_json);
- if (!root)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing metadata: %s\n", err_json.text);
- GNUNET_free (meta_str);
- return GNUNET_SYSERR;
- }
-
- identity_json = json_object_get (root, "identity");
- if (!json_is_string (identity_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing metadata: %s\n", err_json.text);
- json_decref (root);
- GNUNET_free (meta_str);
- return GNUNET_SYSERR;
- }
- identity_key_str = json_string_value (identity_json);
- GNUNET_STRINGS_string_to_data (identity_key_str,
- strlen (identity_key_str),
- &id_pkey,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
-
- label_json = json_object_get (root, "label");
- if (!json_is_string (label_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing metadata: %s\n", err_json.text);
- json_decref (root);
- GNUNET_free (meta_str);
- return GNUNET_SYSERR;
- }
-
- label_str = json_string_value (label_json);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found label: %s\n", label_str);
-
- nonce_json = json_object_get (root, "nonce");
- if (!json_is_string (label_json))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error parsing metadata: %s\n", err_json.text);
- json_decref (root);
- GNUNET_free (meta_str);
- return GNUNET_SYSERR;
- }
-
- nonce_str = json_string_value (nonce_json);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found nonce: %s\n", nonce_str);
-
- *result = GNUNET_IDENTITY_PROVIDER_ticket_payload_create (nonce_str,
- (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey,
- label_str);
- GNUNET_free (meta_str);
- json_decref (root);
- return GNUNET_OK;
-
-}
-
-int
-GNUNET_IDENTITY_PROVIDER_ticket_parse (const char *raw_data,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_IDENTITY_PROVIDER_TokenTicket **result)
-{
- const char* enc_meta_str;
- const char* ecdh_enc_str;
- const char* signature_enc_str;
-
- json_t *root;
- json_t *signature_json;
- json_t *ecdh_json;
- json_t *enc_meta_json;
- json_error_t err_json;
- char* enc_meta;
- char* ticket_decoded;
- char* write_ptr;
- size_t enc_meta_len;
- struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
- struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket;
- struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *ticket_payload;
-
- ticket_decoded = NULL;
- GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Token Code: %s\n", ticket_decoded);
- root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json);
- if (!root)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%s\n", err_json.text);
- return GNUNET_SYSERR;
- }
-
- signature_json = json_object_get (root, "signature");
- ecdh_json = json_object_get (root, "ecdh");
- enc_meta_json = json_object_get (root, "meta");
-
- signature_enc_str = json_string_value (signature_json);
- ecdh_enc_str = json_string_value (ecdh_json);
- enc_meta_str = json_string_value (enc_meta_json);
-
- ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_TokenTicket));
-
- if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str,
- strlen (ecdh_enc_str),
- &ticket->ecdh_pubkey,
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in metadata\n", ecdh_enc_str);
- json_decref (root);
- GNUNET_free (ticket);
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using ECDH pubkey %s for metadata decryption\n", ecdh_enc_str);
- if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str,
- strlen (signature_enc_str),
- &ticket->signature,
- sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
- {
- json_decref (root);
- GNUNET_free (ticket_decoded);
- GNUNET_free (ticket);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in metadata\n");
- return GNUNET_SYSERR;
- }
-
- enc_meta_len = GNUNET_STRINGS_base64_decode (enc_meta_str,
- strlen (enc_meta_str),
- &enc_meta);
-
-
- GNUNET_IDENTITY_PROVIDER_ticket_payload_parse (enc_meta,
- enc_meta_len,
- priv_key,
- (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey,
- &ticket_payload);
-
- ticket->payload = ticket_payload;
- //TODO: check signature here
- purpose =
- GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E
- enc_meta_len); // E_K (code_str)
- purpose->size =
- htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
- sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) +
- enc_meta_len);
- purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
- write_ptr = (char*) &purpose[1];
- memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
- memcpy (write_ptr, enc_meta, enc_meta_len);
-
- if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET,
- purpose,
- &ticket->signature,
- &ticket_payload->identity_key))
- {
- GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
- GNUNET_free (ticket_decoded);
- json_decref (root);
- GNUNET_free (purpose);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Error verifying signature for token code\n");
- return GNUNET_SYSERR;
- }
- *result = ticket;
- GNUNET_free (purpose);
-
- GNUNET_free (enc_meta);
- GNUNET_free (ticket_decoded);
- json_decref (root);
- return GNUNET_OK;
-
-}
-
-
-
-/* end of identity-token.c */
+++ /dev/null
-[identity-token]
-BINARY=gnunet-service-identity-token
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
- */
-/**
- * @author Martin Schanzenbach
- * @file include/gnunet_identity_provider_lib.h
- * @brief GNUnet Identity Provider library
- *
- */
-#ifndef GNUNET_IDENTITY_PROVIDER_LIB_H
-#define GNUNET_IDENTITY_PROVIDER_LIB_H
-
-#include "gnunet_crypto_lib.h"
-#include <jansson.h>
-
-struct GNUNET_IDENTITY_PROVIDER_Token
-{
- /**
- * JSON header
- */
- json_t *header;
-
- /**
- * JSON Payload
- */
- json_t *payload;
-
- /**
- * Token Signature
- */
- struct GNUNET_CRYPTO_EcdsaSignature signature;
-
- /**
- * Audience Pubkey
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
-};
-
-struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload
-{
- /**
- * Nonce
- */
- char* nonce;
-
- /**
- * Label
- */
- char *label;
-
- /**
- * Issuing Identity
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey identity_key;
-};
-
-
-struct GNUNET_IDENTITY_PROVIDER_TokenTicket
-{
- /**
- * Meta info
- */
- struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *payload;
-
- /**
- * ECDH Pubkey
- */
- struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
-
- /**
- * Signature
- */
- struct GNUNET_CRYPTO_EcdsaSignature signature;
-
- /**
- * Target identity
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
-};
-
-
-
-/**
- * Create an identity token
- *
- * @param iss the issuer string for the token
- * @param aud the audience of the token
- *
- * @return a new token
- */
-struct GNUNET_IDENTITY_PROVIDER_Token*
-GNUNET_IDENTITY_PROVIDER_token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *iss,
- const struct GNUNET_CRYPTO_EcdsaPublicKey* aud);
-
-/**
- * Destroy an identity token
- *
- * @param token the token to destroy
- */
-void
-GNUNET_IDENTITY_PROVIDER_token_destroy (struct GNUNET_IDENTITY_PROVIDER_Token *token);
-
-/**
- * Add a new key value pair to the token
- *
- * @param token the token to modify
- * @param key the key
- * @param value the value
- */
-void
-GNUNET_IDENTITY_PROVIDER_token_add_attr (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const char* key,
- const char* value);
-
-/**
- * Add a new key value pair to the token with the value as json
- *
- * @param the token to modify
- * @param key the key
- * @param value the value
- *
- */
-void
-GNUNET_IDENTITY_PROVIDER_token_add_json (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const char* key,
- json_t* value);
-
-/**
- * Serialize a token. The token will be signed and base64 according to the
- * JWT format. The signature is base32-encoded ECDSA.
- * The resulting JWT is encrypted using
- * ECDHE for the audience and Base64
- * encoded in result. The audience requires the ECDHE public key P
- * to decrypt the token T. The key P is included in the result and prepended
- * before the token
- *
- * @param token the token to serialize
- * @param priv_key the private key used to sign the token
- * @param ecdhe_privkey the ECDHE private key used to encrypt the token
- * @param result P,Base64(E(T))
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_token_serialize (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_CRYPTO_EcdhePrivateKey **ecdhe_privkey,
- char **result);
-
-/**
- * Parses the serialized token and returns a token
- *
- * @param data the serialized token
- * @param priv_key the private key of the audience
- * @param result the token
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_token_parse (const char* data,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_IDENTITY_PROVIDER_Token **result);
-
-/**
- * Parses the serialized token and returns a token
- * This variant is intended for the party that issued the token and also
- * wants to decrypt the serialized token.
- *
- * @param data the serialized token
- * @param priv_key the private (!) ECDHE key
- * @param aud_key the identity of the audience
- * @param result the token
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_token_parse2 (const char* data,
- const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
- struct GNUNET_IDENTITY_PROVIDER_Token **result);
-
-
-/**
- *
- * Returns a JWT-string representation of the token
- *
- * @param token the token
- * @param priv_key the private key used to sign the JWT
- * @param result the JWT
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- char **result);
-
-/**
- *
- * Creates a ticket that can be exchanged by the audience for
- * the token. The token must be placed under the label
- *
- * @param nonce_str nonce provided by the audience that requested the ticket
- * @param iss_pkey the issuer pubkey used to sign the ticket
- * @param label the label encoded in the ticket
- * @param aud_ley the audience pubkey used to encrypt the ticket payload
- *
- * @return the ticket
- */
-struct GNUNET_IDENTITY_PROVIDER_TokenTicket*
-GNUNET_IDENTITY_PROVIDER_ticket_create (const char* nonce_str,
- const struct GNUNET_CRYPTO_EcdsaPublicKey* iss_pkey,
- const char* lbl_str,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key);
-
-/**
- * Serialize a ticket. Returns the Base64 representation of the ticket.
- * Format: Base64( { payload: E(Payload), ecdhe: K, signature: signature } )
- *
- * @param ticket the ticket to serialize
- * @param priv_key the issuer private key to sign the ticket payload
- * @param result the serialized ticket
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_ticket_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- char **result);
-
-/**
- * Destroys a ticket
- *
- * @param the ticket to destroy
- */
-void
-GNUNET_IDENTITY_PROVIDER_ticket_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket);
-
-/**
- * Parses a serialized ticket
- *
- * @param data the serialized ticket
- * @param priv_key the audience private key
- * @param ticket the ticket
- *
- * @return GNUNET_OK on success
- */
-int
-GNUNET_IDENTITY_PROVIDER_ticket_parse (const char* raw_data,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
- struct GNUNET_IDENTITY_PROVIDER_TokenTicket **ticket);
-
-#endif
+++ /dev/null
-/*
- This file is part of GNUnet.
- Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
-
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- GNUnet is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
- */
-/**
- * @author Martin Schanzenbach
- * @file identity/plugin_rest_identity.c
- * @brief GNUnet Namestore REST plugin
- *
- */
-
-#include "platform.h"
-#include "gnunet_rest_plugin.h"
-#include "gnunet_identity_service.h"
-#include "gnunet_gns_service.h"
-#include "gnunet_gnsrecord_lib.h"
-#include "gnunet_namestore_service.h"
-#include "gnunet_rest_lib.h"
-#include "microhttpd.h"
-#include <jansson.h>
-#include "gnunet_signatures.h"
-#include "gnunet_identity_provider_lib.h"
-
-/**
- * REST root namespace
- */
-#define GNUNET_REST_API_NS_IDENTITY_TOKEN "/gnuid"
-
-/**
- * Issue namespace
- */
-#define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/gnuid/issue"
-
-/**
- * Check namespace
- */
-#define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/gnuid/check"
-
-/**
- * Token namespace
- */
-#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/gnuid/token"
-
-/**
- * Authorize namespace
- */
-#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_AUTHORIZE "/gnuid/authorize"
-
-#define GNUNET_REST_JSONAPI_IDENTITY_token_ticket "code"
-
-#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE_CODE "authorization_code"
-
-#define GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE "grant_type"
-
-#define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
-
-/**
- * State while collecting all egos
- */
-#define ID_REST_STATE_INIT 0
-
-/**
- * Done collecting egos
- */
-#define ID_REST_STATE_POST_INIT 1
-
-/**
- * Resource type
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
-
-/**
- * URL parameter to create a GNUid token for a specific audience
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
-
-/**
- * URL parameter to create a GNUid token for a specific issuer (EGO)
- */
-#define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
-
-/**
- * Attributes passed to issue request
- */
-#define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
-
-/**
- * Token expiration string
- */
-#define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
-
-/**
- * Renew token w/ relative expirations
- */
-#define GNUNET_IDENTITY_TOKEN_RENEW_TOKEN "renew_token"
-
-/**
- * Error messages
- */
-#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
-#define GNUNET_REST_ERROR_NO_DATA "No data"
-
-/**
- * GNUid token lifetime
- */
-#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
-
-/**
- * The configuration handle
- */
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * HTTP methods allows for this plugin
- */
-static char* allow_methods;
-
-/**
- * @brief struct returned by the initialization function of the plugin
- */
-struct Plugin
-{
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-};
-
-/**
- * The ego list
- */
-struct EgoEntry
-{
- /**
- * DLL
- */
- struct EgoEntry *next;
-
- /**
- * DLL
- */
- struct EgoEntry *prev;
-
- /**
- * Ego Identifier
- */
- char *identifier;
-
- /**
- * Public key string
- */
- char *keystring;
-
- /**
- * The Ego
- */
- struct GNUNET_IDENTITY_Ego *ego;
-};
-
-
-struct RequestHandle
-{
- /**
- * Ego list
- */
- struct EgoEntry *ego_head;
-
- /**
- * Ego list
- */
- struct EgoEntry *ego_tail;
-
- /**
- * Selected ego
- */
- struct EgoEntry *ego_entry;
-
- /**
- * Ptr to current ego private key
- */
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
-
- /**
- * Handle to the rest connection
- */
- struct RestConnectionDataHandle *conndata_handle;
-
- /**
- * The processing state
- */
- int state;
-
- /**
- * Handle to Identity service.
- */
- struct GNUNET_IDENTITY_Handle *identity_handle;
-
- /**
- * IDENTITY Operation
- */
- struct GNUNET_IDENTITY_Operation *op;
-
- /**
- * Handle to NS service
- */
- struct GNUNET_NAMESTORE_Handle *ns_handle;
-
- /**
- * Handle to GNS service
- */
- struct GNUNET_GNS_Handle *gns_handle;
-
- /**
- * NS iterator
- */
- struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
-
- /**
- * NS Handle
- */
- struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
-
- /**
- * Desired timeout for the lookup (default is no timeout).
- */
- struct GNUNET_TIME_Relative timeout;
-
- /**
- * ID of a task associated with the resolution process.
- */
- struct GNUNET_SCHEDULER_Task * timeout_task;
-
- /**
- * GNS lookup
- */
- struct GNUNET_GNS_LookupRequest *lookup_request;
-
- /**
- * The plugin result processor
- */
- GNUNET_REST_ResultProcessor proc;
-
- /**
- * The closure of the result processor
- */
- void *proc_cls;
-
- /**
- * The name to look up
- */
- char *name;
-
- /**
- * The url
- */
- char *url;
-
- /**
- * The data from the REST request
- */
- const char* data;
-
- /**
- * the length of the REST data
- */
- size_t data_size;
-
- /**
- * HTTP method
- */
- const char* method;
-
- /**
- * Error response message
- */
- char *emsg;
-
- /**
- * Identity Token
- */
- struct GNUNET_IDENTITY_PROVIDER_Token *token;
-
- /**
- * Identity Token Code
- */
- struct GNUNET_IDENTITY_PROVIDER_TokenTicket *token_ticket;
-
- /**
- * Response object
- */
- struct JsonApiObject *resp_object;
-
- /**
- * ID Attribute list given
- */
- struct GNUNET_CONTAINER_MultiHashMap *attr_map;
-
-
-};
-
-
-/**
- * Cleanup lookup handle
- * @param handle Handle to clean up
- */
-static void
-cleanup_handle (struct RequestHandle *handle)
-{
- struct EgoEntry *ego_entry;
- struct EgoEntry *ego_tmp;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Cleaning up\n");
- if (NULL != handle->resp_object)
- GNUNET_REST_jsonapi_object_delete (handle->resp_object);
- if (NULL != handle->name)
- GNUNET_free (handle->name);
- if (NULL != handle->timeout_task)
- GNUNET_SCHEDULER_cancel (handle->timeout_task);
- if (NULL != handle->identity_handle)
- GNUNET_IDENTITY_disconnect (handle->identity_handle);
- if (NULL != handle->gns_handle)
- GNUNET_GNS_disconnect (handle->gns_handle);
- if (NULL != handle->ns_it)
- GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
- if (NULL != handle->ns_qe)
- GNUNET_NAMESTORE_cancel (handle->ns_qe);
- if (NULL != handle->ns_handle)
- GNUNET_NAMESTORE_disconnect (handle->ns_handle);
- if (NULL != handle->attr_map)
- GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
- if (NULL != handle->token)
- GNUNET_IDENTITY_PROVIDER_token_destroy (handle->token);
- if (NULL != handle->token_ticket)
- GNUNET_IDENTITY_PROVIDER_ticket_destroy (handle->token_ticket);
- if (NULL != handle->url)
- GNUNET_free (handle->url);
- if (NULL != handle->emsg)
- GNUNET_free (handle->emsg);
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;)
- {
- ego_tmp = ego_entry;
- ego_entry = ego_entry->next;
- GNUNET_free (ego_tmp->identifier);
- GNUNET_free (ego_tmp->keystring);
- GNUNET_free (ego_tmp);
- }
- GNUNET_free (handle);
-}
-
-
-/**
- * Task run on shutdown. Cleans up everything.
- *
- * @param cls unused
- * @param tc scheduler context
- */
-static void
-do_error (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
- char *json_error;
-
- GNUNET_asprintf (&json_error,
- "{Error while processing request: %s}",
- handle->emsg);
-
- resp = GNUNET_REST_create_json_response (json_error);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- cleanup_handle (handle);
- GNUNET_free (json_error);
-}
-
-/**
- * Task run on shutdown. Cleans up everything.
- *
- * @param cls unused
- * @param tc scheduler context
- */
-static void
-do_cleanup_handle_delayed (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct RequestHandle *handle = cls;
- cleanup_handle(handle);
-}
-
-void
-store_token_cont (void *cls,
- int32_t success,
- const char *emsg)
-{
- char *result_str;
- struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
-
- handle->ns_qe = NULL;
- if (GNUNET_SYSERR == success)
- {
- handle->emsg = GNUNET_strdup (emsg);
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
- resp = GNUNET_REST_create_json_response (result_str);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
-}
-
-
-
-
-
-
-
-
-
-/**
- * Build a GNUid token for identity
- * @param handle the handle
- * @param ego_entry the ego to build the token for
- * @param name name of the ego
- * @param token_aud token audience
- * @param token the resulting gnuid token
- * @return identifier string of token (label)
- */
-static void
-sign_and_return_token (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
- struct GNUNET_CRYPTO_EcdsaPublicKey aud_pkey;
- struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
- struct JsonApiResource *json_resource;
- struct RequestHandle *handle = cls;
- struct GNUNET_GNSRECORD_Data token_record[2];
- struct GNUNET_HashCode key;
- struct GNUNET_TIME_Relative etime_rel;
- json_t *token_str;
- json_t *name_str;
- json_t *token_ticket_json;
- char *lbl_str;
- char *exp_str;
- char *token_ticket_str;
- char *audience;
- char *nonce_str;
- char *enc_token_str;
- char *token_metadata;
- char *scopes;
- char* write_ptr;
- uint64_t time;
- uint64_t exp_time;
- uint64_t rnd_key;
- size_t token_metadata_len;
-
- //Remote nonce
- nonce_str = NULL;
- GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
- strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
- &key);
- if ( GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
- //Token audience
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
- &key);
- audience = NULL;
- if ( GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- handle->emsg = GNUNET_strdup ("Audience missing!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience to issue token for: %s\n", audience);
-
- //Audience pubkey (B = bG)
- if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (audience,
- strlen (audience),
- &aud_pkey))
- {
- handle->emsg = GNUNET_strdup ("Client PKEY invalid!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
-
- rnd_key = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
- GNUNET_STRINGS_base64_encode ((char*)&rnd_key, sizeof (uint64_t), &lbl_str);
- priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
- GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
- &pub_key);
-
- handle->token_ticket = GNUNET_IDENTITY_PROVIDER_ticket_create (nonce_str,
- &pub_key,
- lbl_str,
- &aud_pkey);
-
- if (GNUNET_OK != GNUNET_IDENTITY_PROVIDER_ticket_serialize (handle->token_ticket,
- priv_key,
- &token_ticket_str))
- {
- handle->emsg = GNUNET_strdup ("Unable to create ref token!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
- GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
- strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
- &key);
- //Get expiration for token from URL parameter
- exp_str = NULL;
- if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key))
- {
- exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- }
- if (NULL == exp_str) {
- handle->emsg = GNUNET_strdup ("No expiration given!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
- if (GNUNET_OK !=
- GNUNET_STRINGS_fancy_time_to_relative (exp_str,
- &etime_rel))
- {
- handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- time = GNUNET_TIME_absolute_get().abs_value_us;
- exp_time = time + etime_rel.rel_value_us;
-
- //json_object_set_new (handle->payload, "lbl", json_string (lbl_str));
- GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "sub", handle->ego_entry->identifier);
- GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "nbf", json_integer (time));
- GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "iat", json_integer (time));
- GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, "exp", json_integer (exp_time));
- GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, "nonce", nonce_str);
-
-
- handle->resp_object = GNUNET_REST_jsonapi_object_new ();
-
- json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
- lbl_str);
- name_str = json_string (handle->ego_entry->identifier);
- GNUNET_REST_jsonapi_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
- name_str);
- json_decref (name_str);
- token_str = json_string (enc_token_str);
- GNUNET_REST_jsonapi_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
- token_str);
- token_ticket_json = json_string (token_ticket_str);
- GNUNET_REST_jsonapi_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
- token_ticket_json);
- GNUNET_free (token_ticket_str);
- json_decref (token_ticket_json);
- GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
- //Token in a serialized encrypted format
- GNUNET_assert (GNUNET_IDENTITY_PROVIDER_token_serialize (handle->token,
- priv_key,
- &ecdhe_privkey,
- &enc_token_str));
-
- //Token record E,E_K (Token)
- token_record[0].data = enc_token_str;
- token_record[0].data_size = strlen (enc_token_str) + 1;
- token_record[0].expiration_time = exp_time;
- token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
- token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
-
-
- //Meta info
- GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
- strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
- &key);
-
- scopes = NULL;
- if ( GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- handle->emsg = GNUNET_strdup ("Scopes missing!\n");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
-
- token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
- + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
- + strlen (scopes) + 1; //With 0-Terminator
- token_metadata = GNUNET_malloc (token_metadata_len);
- write_ptr = token_metadata;
- memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
- memcpy (write_ptr, &aud_pkey, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
- write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
- memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
-
- GNUNET_free (ecdhe_privkey);
-
- token_record[1].data = token_metadata;
- token_record[1].data_size = token_metadata_len;
- token_record[1].expiration_time = exp_time;
- token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
- token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
-
- //Persist token
- handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
- priv_key,
- lbl_str,
- 2,
- token_record,
- &store_token_cont,
- handle);
- GNUNET_free (lbl_str);
- GNUNET_free (enc_token_str);
- json_decref (token_str);
-}
-
-
-
-
-
-static void
-attr_collect (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- int i;
- char* data;
- json_t *attr_arr;
- struct RequestHandle *handle = cls;
- struct GNUNET_HashCode key;
-
- if (NULL == label)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
- handle->ns_it = NULL;
- GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
- return;
- }
-
- GNUNET_CRYPTO_hash (label,
- strlen (label),
- &key);
-
- if (0 == rd_count ||
- ( (NULL != handle->attr_map) &&
- (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
- &key))
- )
- )
- {
- GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
-
- if (1 == rd_count)
- {
- if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
- {
- data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- rd->data,
- rd->data_size);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
- GNUNET_IDENTITY_PROVIDER_token_add_attr (handle->token, label, data);
- GNUNET_free (data);
- }
- GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
- return;
- }
-
- i = 0;
- attr_arr = json_array();
- for (; i < rd_count; i++)
- {
- if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
- {
- data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
- rd[i].data,
- rd[i].data_size);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
- json_array_append_new (attr_arr, json_string (data));
- GNUNET_free (data);
- }
- }
-
- if (0 < json_array_size (attr_arr))
- {
- GNUNET_IDENTITY_PROVIDER_token_add_json (handle->token, label, attr_arr);
- }
- json_decref (attr_arr);
- GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-}
-
-
-/**
- * Create a response with requested ego(s)
- *
- * @param con the Rest handle
- * @param url the requested url
- * @param cls the request handle
- */
-static void
-issue_token_cont (struct RestConnectionDataHandle *con,
- const char *url,
- void *cls)
-{
- const char *egoname;
- char *ego_val;
- char *audience;
- struct RequestHandle *handle = cls;
- struct EgoEntry *ego_entry;
- struct GNUNET_HashCode key;
- struct MHD_Response *resp;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
- struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
-
- if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
- GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
- resp = GNUNET_REST_create_json_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- cleanup_handle (handle);
- return;
- }
-
- egoname = NULL;
- ego_entry = NULL;
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
- &key);
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- if (NULL == ego_val)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
- if (NULL != ego_val)
- {
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;
- ego_entry = ego_entry->next)
- {
- if (0 != strcmp (ego_val, ego_entry->identifier))
- continue;
- egoname = ego_entry->identifier;
- break;
- }
- if (NULL == egoname || NULL == ego_entry)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
- resp = GNUNET_REST_create_json_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- cleanup_handle (handle);
- return;
- }
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
- &key);
-
- //Token audience
- audience = NULL;
- if ( GNUNET_YES !=
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
- resp = GNUNET_REST_create_json_response (NULL);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
- cleanup_handle (handle);
- return;
- }
- audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
-
- priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
- GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
- &pub_key);
- GNUNET_STRINGS_string_to_data (audience,
- strlen (audience),
- &aud_key,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
- handle->token = GNUNET_IDENTITY_PROVIDER_token_create (&pub_key,
- aud_key);
- GNUNET_free (aud_key);
-
-
- //Get identity attributes
- handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
- handle->ego_entry = ego_entry;
- handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
- priv_key,
- &attr_collect,
- handle);
-}
-
-
-/**
- * Build a GNUid token for identity
- * @param handle the handle
- * @param ego_entry the ego to build the token for
- * @param name name of the ego
- * @param token_aud token audience
- * @param token the resulting gnuid token
- * @return identifier string of token (label)
- */
-static void
-return_token_list (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- char* result_str;
- struct RequestHandle *handle = cls;
- struct MHD_Response *resp;
-
- GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
- resp = GNUNET_REST_create_json_response (result_str);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- GNUNET_free (result_str);
- cleanup_handle (handle);
-}
-
-/**
- * Collect all tokens for ego
- */
-static void
-token_collect (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- int i;
- char* data;
- struct RequestHandle *handle = cls;
- struct EgoEntry *ego_tmp;
- struct JsonApiResource *json_resource;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- json_t *issuer;
- json_t *token;
-
- if (NULL == label)
- {
- ego_tmp = handle->ego_head;
- GNUNET_CONTAINER_DLL_remove (handle->ego_head,
- handle->ego_tail,
- ego_tmp);
- GNUNET_free (ego_tmp->identifier);
- GNUNET_free (ego_tmp->keystring);
- GNUNET_free (ego_tmp);
-
- if (NULL == handle->ego_head)
- {
- //Done
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
- handle->ns_it = NULL;
- GNUNET_SCHEDULER_add_now (&return_token_list, handle);
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
- priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
- handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
- priv_key,
- &token_collect,
- handle);
- return;
- }
-
- for (i = 0; i < rd_count; i++)
- {
- if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
- {
- data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
- rd[i].data,
- rd[i].data_size);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
- json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
- label);
- issuer = json_string (handle->ego_head->identifier);
- GNUNET_REST_jsonapi_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
- issuer);
- json_decref (issuer);
- token = json_string (data);
- GNUNET_REST_jsonapi_resource_add_attr (json_resource,
- GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
- token);
- json_decref (token);
-
- GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
- GNUNET_free (data);
- }
- }
-
- GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-}
-
-
-
-/**
- * Respond to OPTIONS request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
-static void
-list_token_cont (struct RestConnectionDataHandle *con_handle,
- const char* url,
- void *cls)
-{
- char* ego_val;
- struct GNUNET_HashCode key;
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
- struct RequestHandle *handle = cls;
- struct EgoEntry *ego_entry;
- struct EgoEntry *ego_tmp;
-
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
- &key);
-
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- //Remove non-matching egos
- for (ego_entry = handle->ego_head;
- NULL != ego_entry;)
- {
- ego_tmp = ego_entry;
- ego_entry = ego_entry->next;
- if (0 != strcmp (ego_val, ego_tmp->identifier))
- {
- GNUNET_CONTAINER_DLL_remove (handle->ego_head,
- handle->ego_tail,
- ego_tmp);
- GNUNET_free (ego_tmp->identifier);
- GNUNET_free (ego_tmp->keystring);
- GNUNET_free (ego_tmp);
- }
- }
- }
- handle->resp_object = GNUNET_REST_jsonapi_object_new ();
- if (NULL == handle->ego_head)
- {
- //Done
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
- GNUNET_SCHEDULER_add_now (&return_token_list, handle);
- return;
- }
- priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
- handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
- handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
- priv_key,
- &token_collect,
- handle);
-
-}
-
-
-
-
-static void
-process_lookup_result (void *cls, uint32_t rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
-{
- struct RequestHandle *handle = cls;
- json_t *root;
- struct MHD_Response *resp;
- char *result;
- char* token_str;
- char* record_str;
-
- handle->lookup_request = NULL;
- if (2 != rd_count)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Number of tokens %d != 2.",
- rd_count);
- handle->emsg = GNUNET_strdup ("Number of tokens != 2.");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
- root = json_object();
- record_str =
- GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
- rd->data,
- rd->data_size);
-
- //Decrypt and parse
- GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_parse (record_str,
- handle->priv_key,
- &handle->token));
-
- //Readable
- GNUNET_assert (GNUNET_OK == GNUNET_IDENTITY_PROVIDER_token_to_string (handle->token,
- handle->priv_key,
- &token_str));
-
- json_object_set_new (root, "access_token", json_string (token_str));
- json_object_set_new (root, "token_type", json_string ("gnuid"));
- GNUNET_free (token_str);
- GNUNET_free (record_str);
-
- result = json_dumps (root, JSON_INDENT(1));
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", result);
- resp = GNUNET_REST_create_json_response (result);
- GNUNET_free (result);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
- json_decref (root);
-}
-
-
-static void
-exchange_token_ticket_cb (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *name)
-{
- struct RequestHandle *handle = cls;
- struct GNUNET_HashCode key;
- char* code;
- char* lookup_query;
-
- handle->op = NULL;
-
- if (NULL == ego)
- {
- handle->emsg = GNUNET_strdup ("No GNS identity found.");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
-
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_token_ticket,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_token_ticket),
- &key);
-
- if ( GNUNET_NO ==
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- handle->emsg = GNUNET_strdup ("No code given.");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- code = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
-
- handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
-
- if (GNUNET_SYSERR == GNUNET_IDENTITY_PROVIDER_ticket_parse (code,
- handle->priv_key,
- &handle->token_ticket))
- {
- handle->emsg = GNUNET_strdup ("Error extracting values from token code.");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Looking for token under %s\n",
- handle->token_ticket->payload->label);
- handle->gns_handle = GNUNET_GNS_connect (cfg);
- GNUNET_asprintf (&lookup_query, "%s.gnu", handle->token_ticket->payload->label);
- handle->lookup_request = GNUNET_GNS_lookup (handle->gns_handle,
- lookup_query,
- &handle->token_ticket->payload->identity_key,
- GNUNET_GNSRECORD_TYPE_ID_TOKEN,
- GNUNET_GNS_LO_LOCAL_MASTER,
- NULL,
- &process_lookup_result,
- handle);
- GNUNET_free (lookup_query);
-}
-
-/**
- * Respond to OAuth2 /token request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
-static void
-exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
- const char* url,
- void *cls)
-{
- struct RequestHandle *handle = cls;
- char* grant_type;
- struct GNUNET_HashCode key;
-
- GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE,
- strlen (GNUNET_REST_JSONAPI_IDENTITY_OAUTH2_GRANT_TYPE),
- &key);
-
- if ( GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key) )
- {
- grant_type = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- }
-
- if (0 == strcmp ("authorization_code", grant_type)) {
- //Get token from GNS
- handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
- "gns-master",
- &exchange_token_ticket_cb,
- handle);
- }
-
- //TODO fail here
-}
-
-/**
- * Respond to OPTIONS request
- *
- * @param con_handle the connection handle
- * @param url the url
- * @param cls the RequestHandle
- */
-static void
-options_cont (struct RestConnectionDataHandle *con_handle,
- const char* url,
- void *cls)
-{
- struct MHD_Response *resp;
- struct RequestHandle *handle = cls;
-
- //For now, independent of path return all options
- resp = GNUNET_REST_create_json_response (NULL);
- MHD_add_response_header (resp,
- "Access-Control-Allow-Methods",
- allow_methods);
- handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
- cleanup_handle (handle);
- return;
-}
-
-/**
- * Handle rest request
- *
- * @param handle the request handle
- */
-static void
-init_cont (struct RequestHandle *handle)
-{
- static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
- //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
- {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN, &list_token_cont},
- {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_TOKEN, &options_cont},
- {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
- GNUNET_REST_HANDLER_END
- };
-
- if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
- {
- handle->emsg = GNUNET_strdup ("Request unsupported");
- GNUNET_SCHEDULER_add_now (&do_error, handle);
- }
-}
-
-/**
- * If listing is enabled, prints information about the egos.
- *
- * This function is initially called for all egos and then again
- * whenever a ego's identifier changes or if it is deleted. At the
- * end of the initial pass over all egos, the function is once called
- * with 'NULL' for 'ego'. That does NOT mean that the callback won't
- * be invoked in the future or that there was an error.
- *
- * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
- * this function is only called ONCE, and 'NULL' being passed in
- * 'ego' does indicate an error (i.e. name is taken or no default
- * value is known). If 'ego' is non-NULL and if '*ctx'
- * is set in those callbacks, the value WILL be passed to a subsequent
- * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
- * that one was not NULL).
- *
- * When an identity is renamed, this function is called with the
- * (known) ego but the NEW identifier.
- *
- * When an identity is deleted, this function is called with the
- * (known) ego and "NULL" for the 'identifier'. In this case,
- * the 'ego' is henceforth invalid (and the 'ctx' should also be
- * cleaned up).
- *
- * @param cls closure
- * @param ego ego handle
- * @param ctx context for application to store data for this ego
- * (during the lifetime of this process, initially NULL)
- * @param identifier identifier assigned by the user for this ego,
- * NULL if the user just deleted the ego and it
- * must thus no longer be used
- */
-static void
-list_ego (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *identifier)
-{
- struct RequestHandle *handle = cls;
- struct EgoEntry *ego_entry;
- struct GNUNET_CRYPTO_EcdsaPublicKey pk;
-
- if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
- {
- handle->state = ID_REST_STATE_POST_INIT;
- init_cont (handle);
- return;
- }
- if (ID_REST_STATE_INIT == handle->state) {
- ego_entry = GNUNET_new (struct EgoEntry);
- GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
- ego_entry->keystring =
- GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
- ego_entry->ego = ego;
- GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
- GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
- }
-
-}
-
-/**
- * Function processing the REST call
- *
- * @param method HTTP method
- * @param url URL of the HTTP request
- * @param data body of the HTTP request (optional)
- * @param data_size length of the body
- * @param proc callback function for the result
- * @param proc_cls closure for callback function
- * @return GNUNET_OK if request accepted
- */
-static void
-rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
- GNUNET_REST_ResultProcessor proc,
- void *proc_cls)
-{
- struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
- struct GNUNET_HashCode key;
- char* attr_list;
- char* attr_list_tmp;
- char* attr;
-
- GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
- strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
- &key);
-
- handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-
- handle->proc_cls = proc_cls;
- handle->proc = proc;
- handle->state = ID_REST_STATE_INIT;
- handle->conndata_handle = conndata_handle;
- handle->data = conndata_handle->data;
- handle->data_size = conndata_handle->data_size;
- handle->method = conndata_handle->method;
- if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
- &key))
- {
- handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
- GNUNET_NO);
- attr_list = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
- &key);
- if (NULL != attr_list)
- {
- attr_list_tmp = GNUNET_strdup (attr_list);
- attr = strtok(attr_list_tmp, ",");
- for (; NULL != attr; attr = strtok (NULL, ","))
- {
- GNUNET_CRYPTO_hash (attr,
- strlen (attr),
- &key);
- GNUNET_CONTAINER_multihashmap_put (handle->attr_map,
- &key,
- attr,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
- }
- GNUNET_free (attr_list_tmp);
- }
- }
-
-
- GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
- if (handle->url[strlen (handle->url)-1] == '/')
- handle->url[strlen (handle->url)-1] = '\0';
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connecting...\n");
- handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
- &list_ego,
- handle);
- handle->timeout_task =
- GNUNET_SCHEDULER_add_delayed (handle->timeout,
- &do_error,
- handle);
-
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Connected\n");
-}
-
-/**
- * Entry point for the plugin.
- *
- * @param cls Config info
- * @return NULL on error, otherwise the plugin context
- */
-void *
-libgnunet_plugin_rest_identity_token_init (void *cls)
-{
- static struct Plugin plugin;
- struct GNUNET_REST_Plugin *api;
-
- cfg = cls;
- if (NULL != plugin.cfg)
- return NULL; /* can only initialize once! */
- memset (&plugin, 0, sizeof (struct Plugin));
- plugin.cfg = cfg;
- api = GNUNET_new (struct GNUNET_REST_Plugin);
- api->cls = &plugin;
- api->name = GNUNET_REST_API_NS_IDENTITY_TOKEN;
- api->process_request = &rest_identity_process_request;
- GNUNET_asprintf (&allow_methods,
- "%s, %s, %s, %s, %s",
- MHD_HTTP_METHOD_GET,
- MHD_HTTP_METHOD_POST,
- MHD_HTTP_METHOD_PUT,
- MHD_HTTP_METHOD_DELETE,
- MHD_HTTP_METHOD_OPTIONS);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Identity Token REST API initialized\n"));
- return api;
-}
-
-
-/**
- * Exit point from the plugin.
- *
- * @param cls the plugin context (as returned by "init")
- * @return always NULL
- */
-void *
-libgnunet_plugin_rest_identity_token_done (void *cls)
-{
- struct GNUNET_REST_Plugin *api = cls;
- struct Plugin *plugin = api->cls;
-
- plugin->cfg = NULL;
- GNUNET_free_non_null (allow_methods);
- GNUNET_free (api);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Identity Token REST plugin is finished\n");
- return NULL;
-}
-
-/* end of plugin_rest_gns.c */
const void *data,
size_t data_size)
{
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *audience_pubkey;
+ const char *scopes;
+ char *ecdhe_str;
+ char *aud_str;
+ char *result;
+
switch (type)
{
case GNUNET_GNSRECORD_TYPE_ID_ATTR:
case GNUNET_GNSRECORD_TYPE_ID_TOKEN:
return GNUNET_strndup (data, data_size);
+ case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA:
+ ecdhe_privkey = data;
+ audience_pubkey = data+sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
+ scopes = (char*) audience_pubkey+(sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ ecdhe_str = GNUNET_STRINGS_data_to_string_alloc (ecdhe_privkey,
+ sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+ aud_str = GNUNET_STRINGS_data_to_string_alloc (audience_pubkey,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ GNUNET_asprintf (&result,
+ "%s;%s;%s",
+ ecdhe_str, aud_str, scopes);
+ return result;
+
default:
return NULL;
}
void **data,
size_t *data_size)
{
+ char* ecdhe_str;
+ char* aud_keystr;
+ char* write_ptr;
+ char* tmp_tok;
+ char* str;
+
if (NULL == s)
return GNUNET_SYSERR;
switch (type)
*data = GNUNET_strdup (s);
*data_size = strlen (s);
return GNUNET_OK;
+ case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA:
+ tmp_tok = GNUNET_strdup (s);
+ ecdhe_str = strtok (tmp_tok, ";");
+ if (NULL == ecdhe_str)
+ {
+ GNUNET_free (tmp_tok);
+ return GNUNET_SYSERR;
+ }
+ aud_keystr = strtok (NULL, ";");
+ if (NULL == aud_keystr)
+ {
+ GNUNET_free (tmp_tok);
+ return GNUNET_SYSERR;
+ }
+ str = strtok (NULL, ";");
+ if (NULL == str)
+ {
+ GNUNET_free (tmp_tok);
+ return GNUNET_SYSERR;
+ }
+ *data_size = strlen (str) + 1
+ +sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
+ +sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ *data = GNUNET_malloc (*data_size);
+
+ write_ptr = *data;
+ GNUNET_STRINGS_string_to_data (ecdhe_str,
+ strlen (ecdhe_str),
+ write_ptr,
+ sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
+ GNUNET_STRINGS_string_to_data (aud_keystr,
+ strlen (aud_keystr),
+ write_ptr,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
+ memcpy (write_ptr, str, strlen (str) + 1); //with 0-Terminator
+ GNUNET_free (tmp_tok);
+ return GNUNET_OK;
+
default:
return GNUNET_SYSERR;
}
* Mapping of record type numbers to human-readable
* record type names.
*/
-static struct {
- const char *name;
- uint32_t number;
-} name_map[] = {
- { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR },
- { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN },
- { NULL, UINT32_MAX }
-};
+ static struct {
+ const char *name;
+ uint32_t number;
+ } name_map[] = {
+ { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR },
+ { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN },
+ { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA },
+ { NULL, UINT32_MAX }
+ };
/**
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+/**
+ * @author Martin Schanzenbach
+ * @file include/gnunet_identity_provider_lib.h
+ * @brief GNUnet Identity Provider library
+ *
+ */
+#ifndef GNUNET_IDENTITY_PROVIDER_LIB_H
+#define GNUNET_IDENTITY_PROVIDER_LIB_H
+
+#include "gnunet_crypto_lib.h"
+#include <jansson.h>
+
+struct GNUNET_IDENTITY_PROVIDER_Token
+{
+ /**
+ * JSON header
+ */
+ json_t *header;
+
+ /**
+ * JSON Payload
+ */
+ json_t *payload;
+
+ /**
+ * Token Signature
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+ /**
+ * Audience Pubkey
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
+};
+
+struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload
+{
+ /**
+ * Nonce
+ */
+ char* nonce;
+
+ /**
+ * Label
+ */
+ char *label;
+
+ /**
+ * Issuing Identity
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey identity_key;
+};
+
+
+struct GNUNET_IDENTITY_PROVIDER_TokenTicket
+{
+ /**
+ * Meta info
+ */
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicketPayload *payload;
+
+ /**
+ * ECDH Pubkey
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
+
+ /**
+ * Signature
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+ /**
+ * Target identity
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
+};
+
+
+
+/**
+ * Create an identity token
+ *
+ * @param iss the issuer string for the token
+ * @param aud the audience of the token
+ *
+ * @return a new token
+ */
+struct GNUNET_IDENTITY_PROVIDER_Token*
+GNUNET_IDENTITY_PROVIDER_token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *iss,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey* aud);
+
+/**
+ * Destroy an identity token
+ *
+ * @param token the token to destroy
+ */
+void
+GNUNET_IDENTITY_PROVIDER_token_destroy (struct GNUNET_IDENTITY_PROVIDER_Token *token);
+
+/**
+ * Add a new key value pair to the token
+ *
+ * @param token the token to modify
+ * @param key the key
+ * @param value the value
+ */
+void
+GNUNET_IDENTITY_PROVIDER_token_add_attr (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const char* key,
+ const char* value);
+
+/**
+ * Add a new key value pair to the token with the value as json
+ *
+ * @param the token to modify
+ * @param key the key
+ * @param value the value
+ *
+ */
+void
+GNUNET_IDENTITY_PROVIDER_token_add_json (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const char* key,
+ json_t* value);
+
+/**
+ * Serialize a token. The token will be signed and base64 according to the
+ * JWT format. The signature is base32-encoded ECDSA.
+ * The resulting JWT is encrypted using
+ * ECDHE for the audience and Base64
+ * encoded in result. The audience requires the ECDHE public key P
+ * to decrypt the token T. The key P is included in the result and prepended
+ * before the token
+ *
+ * @param token the token to serialize
+ * @param priv_key the private key used to sign the token
+ * @param ecdhe_privkey the ECDHE private key used to encrypt the token
+ * @param result P,Base64(E(T))
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_token_serialize (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_CRYPTO_EcdhePrivateKey **ecdhe_privkey,
+ char **result);
+
+/**
+ * Parses the serialized token and returns a token
+ *
+ * @param data the serialized token
+ * @param priv_key the private key of the audience
+ * @param result the token
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_token_parse (const char* data,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_IDENTITY_PROVIDER_Token **result);
+
+/**
+ * Parses the serialized token and returns a token
+ * This variant is intended for the party that issued the token and also
+ * wants to decrypt the serialized token.
+ *
+ * @param data the serialized token
+ * @param priv_key the private (!) ECDHE key
+ * @param aud_key the identity of the audience
+ * @param result the token
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_token_parse2 (const char* data,
+ const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
+ struct GNUNET_IDENTITY_PROVIDER_Token **result);
+
+
+/**
+ *
+ * Returns a JWT-string representation of the token
+ *
+ * @param token the token
+ * @param priv_key the private key used to sign the JWT
+ * @param result the JWT
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ char **result);
+
+/**
+ *
+ * Creates a ticket that can be exchanged by the audience for
+ * the token. The token must be placed under the label
+ *
+ * @param nonce_str nonce provided by the audience that requested the ticket
+ * @param iss_pkey the issuer pubkey used to sign the ticket
+ * @param label the label encoded in the ticket
+ * @param aud_ley the audience pubkey used to encrypt the ticket payload
+ *
+ * @return the ticket
+ */
+struct GNUNET_IDENTITY_PROVIDER_TokenTicket*
+GNUNET_IDENTITY_PROVIDER_ticket_create (const char* nonce_str,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey* iss_pkey,
+ const char* lbl_str,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key);
+
+/**
+ * Serialize a ticket. Returns the Base64 representation of the ticket.
+ * Format: Base64( { payload: E(Payload), ecdhe: K, signature: signature } )
+ *
+ * @param ticket the ticket to serialize
+ * @param priv_key the issuer private key to sign the ticket payload
+ * @param result the serialized ticket
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_ticket_serialize (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ char **result);
+
+/**
+ * Destroys a ticket
+ *
+ * @param the ticket to destroy
+ */
+void
+GNUNET_IDENTITY_PROVIDER_ticket_destroy (struct GNUNET_IDENTITY_PROVIDER_TokenTicket *ticket);
+
+/**
+ * Parses a serialized ticket
+ *
+ * @param data the serialized ticket
+ * @param priv_key the audience private key
+ * @param ticket the ticket
+ *
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_IDENTITY_PROVIDER_ticket_parse (const char* raw_data,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+ struct GNUNET_IDENTITY_PROVIDER_TokenTicket **ticket);
+
+#endif
#define GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN 26
/**
- * Signature for a GNUid Token Reference
+ * Signature for a GNUid Ticket
*/
-#define GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN_CODE 27
+#define GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET 27
#if 0 /* keep Emacsens' auto-indent happy */
{
}
if (NULL != httpd_task)
GNUNET_SCHEDULER_cancel (httpd_task);
- if ( (MHD_YES != haveto) &&
- (-1 == max))
- {
- /* daemon is idle, kill after timeout */
- httpd_task = GNUNET_SCHEDULER_add_delayed (MHD_CACHE_TIMEOUT,
- &kill_httpd_task,
- NULL);
- }
- else
+ if ( (MHD_YES == haveto) ||
+ (-1 != max))
{
httpd_task =
GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,