From: Schanzenbach, Martin Date: Thu, 19 Jul 2018 21:28:53 +0000 (+0200) Subject: renamed identity-provider subsystem to reclaim X-Git-Tag: v0.11.0~322^2~67 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=4fd677cec39e5621d16bc2c63926b803b31582e3;p=oweals%2Fgnunet.git renamed identity-provider subsystem to reclaim --- diff --git a/configure.ac b/configure.ac index c7314d765..535ce0ffe 100644 --- a/configure.ac +++ b/configure.ac @@ -1759,8 +1759,8 @@ src/zonemaster/Makefile src/zonemaster/zonemaster.conf src/rest/Makefile src/abe/Makefile -src/identity-attribute/Makefile -src/identity-provider/Makefile +src/reclaim-attribute/Makefile +src/reclaim/Makefile pkgconfig/Makefile pkgconfig/gnunetarm.pc pkgconfig/gnunetats.pc diff --git a/po/POTFILES.in b/po/POTFILES.in index 83c3c7bdd..86235f860 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -198,16 +198,6 @@ src/hello/hello.c src/hostlist/gnunet-daemon-hostlist.c src/hostlist/gnunet-daemon-hostlist_client.c src/hostlist/gnunet-daemon-hostlist_server.c -src/identity-attribute/identity_attribute.c -src/identity-attribute/plugin_identity_attribute_gnuid.c -src/identity-provider/gnunet-idp.c -src/identity-provider/gnunet-service-identity-provider.c -src/identity-provider/identity_provider_api.c -src/identity-provider/jwt.c -src/identity-provider/plugin_gnsrecord_identity_provider.c -src/identity-provider/plugin_identity_provider_sqlite.c -src/identity-provider/plugin_rest_identity_provider.c -src/identity-provider/plugin_rest_openid_connect.c src/identity/gnunet-identity.c src/identity/gnunet-service-identity.c src/identity/identity_api.c @@ -297,6 +287,16 @@ src/psycutil/psyc_env.c src/psycutil/psyc_message.c src/psycutil/psyc_slicer.c src/pt/gnunet-daemon-pt.c +src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c +src/reclaim-attribute/reclaim_attribute.c +src/reclaim/gnunet-reclaim.c +src/reclaim/gnunet-service-reclaim.c +src/reclaim/jwt.c +src/reclaim/plugin_gnsrecord_reclaim.c +src/reclaim/plugin_reclaim_sqlite.c +src/reclaim/plugin_rest_openid_connect.c +src/reclaim/plugin_rest_reclaim.c +src/reclaim/reclaim_api.c src/regex/gnunet-daemon-regexprofiler.c src/regex/gnunet-regex-profiler.c src/regex/gnunet-regex-simulation-profiler.c diff --git a/src/Makefile.am b/src/Makefile.am index 00f30adc3..4ded81891 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,11 +19,13 @@ if HAVE_EXPERIMENTAL social # dv (FTBFS) if HAVE_ABE +if HAVE_JSON EXP_DIR += \ abe \ credential \ - identity-attribute \ - identity-provider + reclaim-attribute \ + reclaim +endif endif if HAVE_JSON EXP_DIR += \ diff --git a/src/identity-attribute/Makefile.am b/src/identity-attribute/Makefile.am deleted file mode 100644 index 2c73a443e..000000000 --- a/src/identity-attribute/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -plugindir = $(libdir)/gnunet - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = --coverage -O0 - XLIBS = -lgcov -endif - -lib_LTLIBRARIES = \ - libgnunetidentityattribute.la - -libgnunetidentityattribute_la_SOURCES = \ - identity_attribute.c -libgnunetidentityattribute_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) -libgnunetidentityattribute_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - - -plugin_LTLIBRARIES = \ - libgnunet_plugin_identity_attribute_gnuid.la - - -libgnunet_plugin_identity_attribute_gnuid_la_SOURCES = \ - plugin_identity_attribute_gnuid.c -libgnunet_plugin_identity_attribute_gnuid_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(LTLIBINTL) -libgnunet_plugin_identity_attribute_gnuid_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - diff --git a/src/identity-attribute/identity_attribute.c b/src/identity-attribute/identity_attribute.c deleted file mode 100644 index 7d47c46a7..000000000 --- a/src/identity-attribute/identity_attribute.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -/** - * @file identity-attribute/identity_attribute.c - * @brief helper library to manage identity attributes - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "identity_attribute.h" -#include "gnunet_identity_attribute_plugin.h" - -/** - * Handle for a plugin - */ -struct Plugin -{ - /** - * Name of the plugin - */ - char *library_name; - - /** - * Plugin API - */ - struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api; -}; - -/** - * Plugins - */ -static struct Plugin **attr_plugins; - -/** - * Number of plugins - */ -static unsigned int num_plugins; - -/** - * Init canary - */ -static int initialized; - -/** - * Add a plugin - */ -static void -add_plugin (void* cls, - const char *library_name, - void *lib_ret) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api = lib_ret; - struct Plugin *plugin; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Loading attribute plugin `%s'\n", - library_name); - plugin = GNUNET_new (struct Plugin); - plugin->api = api; - plugin->library_name = GNUNET_strdup (library_name); - GNUNET_array_append (attr_plugins, num_plugins, plugin); -} - -/** - * Load plugins - */ -static void -init() -{ - if (GNUNET_YES == initialized) - return; - initialized = GNUNET_YES; - GNUNET_PLUGIN_load_all ("libgnunet_plugin_identity_attribute_", NULL, - &add_plugin, NULL); -} - -/** - * Convert a type name to the corresponding number - * - * @param typename name to convert - * @return corresponding number, UINT32_MAX on error - */ -uint32_t -GNUNET_IDENTITY_ATTRIBUTE_typename_to_number (const char *typename) -{ - unsigned int i; - struct Plugin *plugin; - uint32_t ret; - - init (); - for (i = 0; i < num_plugins; i++) - { - plugin = attr_plugins[i]; - if (UINT32_MAX != (ret = plugin->api->typename_to_number (plugin->api->cls, - typename))) - return ret; - } - return UINT32_MAX; -} - -/** - * Convert a type number to the corresponding type string - * - * @param type number of a type - * @return corresponding typestring, NULL on error - */ -const char* -GNUNET_IDENTITY_ATTRIBUTE_number_to_typename (uint32_t type) -{ - unsigned int i; - struct Plugin *plugin; - const char *ret; - - init (); - for (i = 0; i < num_plugins; i++) - { - plugin = attr_plugins[i]; - if (NULL != (ret = plugin->api->number_to_typename (plugin->api->cls, - type))) - return ret; - } - return NULL; -} - -/** - * Convert human-readable version of a 'claim' of an attribute to the binary - * representation - * - * @param type type of the claim - * @param s human-readable string - * @param data set to value in binary encoding (will be allocated) - * @param data_size set to number of bytes in @a data - * @return #GNUNET_OK on success - */ -int -GNUNET_IDENTITY_ATTRIBUTE_string_to_value (uint32_t type, - const char *s, - void **data, - size_t *data_size) -{ - unsigned int i; - struct Plugin *plugin; - - init (); - for (i = 0; i < num_plugins; i++) - { - plugin = attr_plugins[i]; - if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls, - type, - s, - data, - data_size)) - return GNUNET_OK; - } - return GNUNET_SYSERR; -} - -/** - * Convert the 'claim' of an attribute to a string - * - * @param type the type of attribute - * @param data claim in binary encoding - * @param data_size number of bytes in @a data - * @return NULL on error, otherwise human-readable representation of the claim - */ -char * -GNUNET_IDENTITY_ATTRIBUTE_value_to_string (uint32_t type, - const void* data, - size_t data_size) -{ - unsigned int i; - struct Plugin *plugin; - char *ret; - - init(); - for (i = 0; i < num_plugins; i++) - { - plugin = attr_plugins[i]; - if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls, - type, - data, - data_size))) - return ret; - } - return NULL; -} - -/** - * Create a new attribute. - * - * @param attr_name the attribute name - * @param type the attribute type - * @param data the attribute value - * @param data_size the attribute value size - * @return the new attribute - */ -struct GNUNET_IDENTITY_ATTRIBUTE_Claim * -GNUNET_IDENTITY_ATTRIBUTE_claim_new (const char* attr_name, - uint32_t type, - const void* data, - size_t data_size) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; - char *write_ptr; - - attr = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ATTRIBUTE_Claim) + - strlen (attr_name) + 1 + - data_size); - attr->type = type; - attr->data_size = data_size; - attr->version = 0; - write_ptr = (char*)&attr[1]; - GNUNET_memcpy (write_ptr, - attr_name, - strlen (attr_name) + 1); - attr->name = write_ptr; - write_ptr += strlen (attr->name) + 1; - GNUNET_memcpy (write_ptr, - data, - data_size); - attr->data = write_ptr; - return attr; -} - -/** - * Add a new claim list entry. - * - * @param claim_list the attribute name - * @param attr_name the attribute name - * @param type the attribute type - * @param data the attribute value - * @param data_size the attribute value size - * @return - */ -void -GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *claim_list, - const char* attr_name, - uint32_t type, - const void* data, - size_t data_size) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr_name, - type, - data, - data_size); - GNUNET_CONTAINER_DLL_insert (claim_list->list_head, - claim_list->list_tail, - le); -} - -size_t -GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - size_t len = 0; - for (le = attrs->list_head; NULL != le; le = le->next) - len += GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (le->claim); - return len; -} - -size_t -GNUNET_IDENTITY_ATTRIBUTE_list_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - char *result) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - size_t len; - size_t total_len; - char* write_ptr; - - write_ptr = result; - total_len = 0; - for (le = attrs->list_head; NULL != le; le = le->next) - { - len = GNUNET_IDENTITY_ATTRIBUTE_serialize (le->claim, - write_ptr); - total_len += len; - write_ptr += len; - } - return total_len; -} - -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList * -GNUNET_IDENTITY_ATTRIBUTE_list_deserialize (const char* data, - size_t data_size) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - size_t attr_len; - const char* read_ptr; - - if (data_size < sizeof (struct Attribute)) - return NULL; - - attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - read_ptr = data; - while (((data + data_size) - read_ptr) >= sizeof (struct Attribute)) - { - - le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize (read_ptr, - data_size - (read_ptr - data)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Deserialized attribute %s\n", le->claim->name); - GNUNET_CONTAINER_DLL_insert (attrs->list_head, - attrs->list_tail, - le); - attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (le->claim); - read_ptr += attr_len; - } - return attrs; -} - -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList* -GNUNET_IDENTITY_ATTRIBUTE_list_dup (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *result_le; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *result; - - result = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - for (le = attrs->list_head; NULL != le; le = le->next) - { - result_le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - result_le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (le->claim->name, - le->claim->type, - le->claim->data, - le->claim->data_size); - GNUNET_CONTAINER_DLL_insert (result->list_head, - result->list_tail, - result_le); - } - return result; -} - - -void -GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *tmp_le; - - for (le = attrs->list_head; NULL != le;) - { - GNUNET_free (le->claim); - tmp_le = le; - le = le->next; - GNUNET_free (tmp_le); - } - GNUNET_free (attrs); - -} - -size_t -GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - return sizeof (struct Attribute) - + strlen (attr->name) - + attr->data_size; -} - -size_t -GNUNET_IDENTITY_ATTRIBUTE_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, - char *result) -{ - size_t data_len_ser; - size_t name_len; - struct Attribute *attr_ser; - char* write_ptr; - - attr_ser = (struct Attribute*)result; - attr_ser->attribute_type = htons (attr->type); - attr_ser->attribute_version = htonl (attr->version); - name_len = strlen (attr->name); - attr_ser->name_len = htons (name_len); - write_ptr = (char*)&attr_ser[1]; - GNUNET_memcpy (write_ptr, attr->name, name_len); - write_ptr += name_len; - //TODO plugin-ize - //data_len_ser = plugin->serialize_attribute_value (attr, - // &attr_ser[1]); - data_len_ser = attr->data_size; - GNUNET_memcpy (write_ptr, attr->data, attr->data_size); - attr_ser->data_size = htons (data_len_ser); - - return sizeof (struct Attribute) + strlen (attr->name) + attr->data_size; -} - -struct GNUNET_IDENTITY_ATTRIBUTE_Claim * -GNUNET_IDENTITY_ATTRIBUTE_deserialize (const char* data, - size_t data_size) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; - struct Attribute *attr_ser; - size_t data_len; - size_t name_len; - char* write_ptr; - - if (data_size < sizeof (struct Attribute)) - return NULL; - - attr_ser = (struct Attribute*)data; - data_len = ntohs (attr_ser->data_size); - name_len = ntohs (attr_ser->name_len); - attr = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ATTRIBUTE_Claim) - + data_len + name_len + 1); - attr->type = ntohs (attr_ser->attribute_type); - attr->version = ntohl (attr_ser->attribute_version); - attr->data_size = ntohs (attr_ser->data_size); - - write_ptr = (char*)&attr[1]; - GNUNET_memcpy (write_ptr, - &attr_ser[1], - name_len); - write_ptr[name_len] = '\0'; - attr->name = write_ptr; - - write_ptr += name_len + 1; - GNUNET_memcpy (write_ptr, - (char*)&attr_ser[1] + name_len, - attr->data_size); - attr->data = write_ptr; - return attr; - -} - -/* end of identity_attribute.c */ diff --git a/src/identity-attribute/identity_attribute.h b/src/identity-attribute/identity_attribute.h deleted file mode 100644 index 2346dcde1..000000000 --- a/src/identity-attribute/identity_attribute.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @file identity-attribute/identity_attribute.h - * @brief GNUnet Identity attributes - * - */ -#ifndef IDENTITY_ATTRIBUTE_H -#define IDENTITY_ATTRIBUTE_H - -#include "gnunet_identity_provider_service.h" - -struct Attribute -{ - /** - * Attribute type - */ - uint32_t attribute_type; - - /** - * Attribute version - */ - uint32_t attribute_version; - - /** - * Name length - */ - uint32_t name_len; - - /** - * Data size - */ - uint32_t data_size; - - //followed by data_size Attribute value data -}; - -#endif diff --git a/src/identity-attribute/plugin_identity_attribute_gnuid.c b/src/identity-attribute/plugin_identity_attribute_gnuid.c deleted file mode 100644 index c09b167f5..000000000 --- a/src/identity-attribute/plugin_identity_attribute_gnuid.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2013, 2014, 2016 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @file identity-attribute/plugin_identity_attribute_gnuid.c - * @brief identity attribute plugin to provide the API for fundamental - * attribute types. - * - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_identity_attribute_plugin.h" -#include - - -/** - * Convert the 'value' of an attribute to a string. - * - * @param cls closure, unused - * @param type type of the attribute - * @param data value in binary encoding - * @param data_size number of bytes in @a data - * @return NULL on error, otherwise human-readable representation of the value - */ -static char * -gnuid_value_to_string (void *cls, - uint32_t type, - const void *data, - size_t data_size) -{ - - switch (type) - { - case GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING: - return GNUNET_strndup (data, data_size); - default: - return NULL; - } -} - - -/** - * Convert human-readable version of a 'value' of an attribute to the binary - * representation. - * - * @param cls closure, unused - * @param type type of the attribute - * @param s human-readable string - * @param data set to value in binary encoding (will be allocated) - * @param data_size set to number of bytes in @a data - * @return #GNUNET_OK on success - */ -static int -gnuid_string_to_value (void *cls, - uint32_t type, - const char *s, - void **data, - size_t *data_size) -{ - if (NULL == s) - return GNUNET_SYSERR; - switch (type) - { - - case GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING: - *data = GNUNET_strdup (s); - *data_size = strlen (s); - return GNUNET_OK; - default: - return GNUNET_SYSERR; - } -} - - -/** - * Mapping of attribute type numbers to human-readable - * attribute type names. - */ -static struct { - const char *name; - uint32_t number; -} gnuid_name_map[] = { - { "STRING", GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING }, - { NULL, UINT32_MAX } -}; - - -/** - * Convert a type name to the corresponding number. - * - * @param cls closure, unused - * @param gnuid_typename name to convert - * @return corresponding number, UINT32_MAX on error - */ -static uint32_t -gnuid_typename_to_number (void *cls, - const char *gnuid_typename) -{ - unsigned int i; - - i=0; - while ( (NULL != gnuid_name_map[i].name) && - (0 != strcasecmp (gnuid_typename, - gnuid_name_map[i].name)) ) - i++; - return gnuid_name_map[i].number; -} - - -/** - * Convert a type number (i.e. 1) to the corresponding type string - * - * @param cls closure, unused - * @param type number of a type to convert - * @return corresponding typestring, NULL on error - */ -static const char * -gnuid_number_to_typename (void *cls, - uint32_t type) -{ - unsigned int i; - - i=0; - while ( (NULL != gnuid_name_map[i].name) && - (type != gnuid_name_map[i].number) ) - i++; - return gnuid_name_map[i].name; -} - - -/** - * Entry point for the plugin. - * - * @param cls NULL - * @return the exported block API - */ -void * -libgnunet_plugin_identity_attribute_gnuid_init (void *cls) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api; - - api = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions); - api->value_to_string = &gnuid_value_to_string; - api->string_to_value = &gnuid_string_to_value; - api->typename_to_number = &gnuid_typename_to_number; - api->number_to_typename = &gnuid_number_to_typename; - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the return value from #libgnunet_plugin_block_test_init() - * @return NULL - */ -void * -libgnunet_plugin_identity_attribute_gnuid_done (void *cls) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api = cls; - - GNUNET_free (api); - return NULL; -} - -/* end of plugin_identity_attribute_type_gnuid.c */ diff --git a/src/identity-provider/.gitignore b/src/identity-provider/.gitignore deleted file mode 100644 index ef77fccdc..000000000 --- a/src/identity-provider/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gnunet-service-identity-provider -gnunet-identity-token diff --git a/src/identity-provider/Makefile.am b/src/identity-provider/Makefile.am deleted file mode 100644 index 2eb699542..000000000 --- a/src/identity-provider/Makefile.am +++ /dev/null @@ -1,140 +0,0 @@ -# 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 - -if HAVE_SQLITE -SQLITE_PLUGIN = libgnunet_plugin_identity_provider_sqlite.la -endif - -EXTRA_DIST = \ - test_idp_defaults.conf \ - test_idp.conf \ - $(check_SCRIPTS) - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - identity-provider.conf - -lib_LTLIBRARIES = \ - libgnunetidentityprovider.la -plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_identity_provider.la \ - libgnunet_plugin_rest_openid_connect.la \ - libgnunet_plugin_gnsrecord_identity_provider.la \ - $(SQLITE_PLUGIN) - -bin_PROGRAMS = \ - gnunet-idp - -libexec_PROGRAMS = \ - gnunet-service-identity-provider - -libgnunet_plugin_gnsrecord_identity_provider_la_SOURCES = \ - plugin_gnsrecord_identity_provider.c -libgnunet_plugin_gnsrecord_identity_provider_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(LTLIBINTL) -libgnunet_plugin_gnsrecord_identity_provider_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - -libgnunet_plugin_identity_provider_sqlite_la_SOURCES = \ - plugin_identity_provider_sqlite.c -libgnunet_plugin_identity_provider_sqlite_la_LIBADD = \ - libgnunetidentityprovider.la \ - $(top_builddir)/src/sq/libgnunetsq.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ - $(LTLIBINTL) -libgnunet_plugin_identity_provider_sqlite_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - - - -gnunet_service_identity_provider_SOURCES = \ - gnunet-service-identity-provider.c -gnunet_service_identity_provider_LDADD = \ - $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/abe/libgnunetabe.la \ - $(top_builddir)/src/credential/libgnunetcredential.la \ - $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ - libgnunetidentityprovider.la \ - $(top_builddir)/src/gns/libgnunetgns.la \ - $(GN_LIBINTL) - -libgnunetidentityprovider_la_SOURCES = \ - identity_provider_api.c \ - identity_provider.h -libgnunetidentityprovider_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) $(XLIB) -libgnunetidentityprovider_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -libgnunet_plugin_rest_identity_provider_la_SOURCES = \ - plugin_rest_identity_provider.c \ - jwt.c -libgnunet_plugin_rest_identity_provider_la_LIBADD = \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - libgnunetidentityprovider.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ - $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_identity_provider_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - -libgnunet_plugin_rest_openid_connect_la_SOURCES = \ - plugin_rest_openid_connect.c \ - jwt.c -libgnunet_plugin_rest_openid_connect_la_LIBADD = \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - libgnunetidentityprovider.la \ - $(top_builddir)/src/rest/libgnunetrest.la \ - $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ - $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ - $(LTLIBINTL) -ljansson -lmicrohttpd -libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - -gnunet_idp_SOURCES = \ - gnunet-idp.c -gnunet_idp_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/namestore/libgnunetnamestore.la \ - libgnunetidentityprovider.la \ - $(top_builddir)/src/identity/libgnunetidentity.la \ - $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ - $(GN_LIBINTL) - -check_SCRIPTS = \ - test_idp_attribute.sh \ - test_idp_issue.sh \ - test_idp_consume.sh \ - test_idp_revoke.sh - -if ENABLE_TEST_RUN - AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; - TESTS = $(check_SCRIPTS) -endif diff --git a/src/identity-provider/gnunet-idp.c b/src/identity-provider/gnunet-idp.c deleted file mode 100644 index 79e4f8d27..000000000 --- a/src/identity-provider/gnunet-idp.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @file src/identity-provider/gnunet-idp.c - * @brief Identity Provider utility - * - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_namestore_service.h" -#include "gnunet_identity_provider_service.h" -#include "gnunet_identity_service.h" -#include "gnunet_signatures.h" - -/** - * return value - */ -static int ret; - -/** - * List attribute flag - */ -static int list; - -/** - * Relying party - */ -static char* rp; - -/** - * The attribute - */ -static char* attr_name; - -/** - * Attribute value - */ -static char* attr_value; - -/** - * Attributes to issue - */ -static char* issue_attrs; - -/** - * Ticket to consume - */ -static char* consume_ticket; - -/** - * Attribute type - */ -static char* type_str; - -/** - * Ticket to revoke - */ -static char* revoke_ticket; - -/** - * Ego name - */ -static char* ego_name; - -/** - * Identity handle - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * IdP handle - */ -static struct GNUNET_IDENTITY_PROVIDER_Handle *idp_handle; - -/** - * IdP operation - */ -static struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op; - -/** - * Attribute iterator - */ -static struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_iterator; - -/** - * Master ABE key - */ -static struct GNUNET_CRYPTO_AbeMasterKey *abe_key; - -/** - * ego private key - */ -static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey; - -/** - * rp public key - */ -static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key; - -/** - * Ticket to consume - */ -static struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - -/** - * Attribute list - */ -static struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list; - -/** - * Attribute expiration interval - */ -static struct GNUNET_TIME_Relative exp_interval; - -/** - * Timeout task - */ -static struct GNUNET_SCHEDULER_Task *timeout; - -static void -do_cleanup(void *cls) -{ - if (NULL != timeout) - GNUNET_SCHEDULER_cancel (timeout); - if (NULL != idp_op) - GNUNET_IDENTITY_PROVIDER_cancel (idp_op); - if (NULL != attr_iterator) - GNUNET_IDENTITY_PROVIDER_get_attributes_stop (attr_iterator); - if (NULL != idp_handle) - GNUNET_IDENTITY_PROVIDER_disconnect (idp_handle); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - if (NULL != abe_key) - GNUNET_free (abe_key); - if (NULL != attr_list) - GNUNET_free (attr_list); -} - -static void -ticket_issue_cb (void* cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) -{ - char* ticket_str; - idp_op = NULL; - if (NULL != ticket) { - ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - printf("%s\n", - ticket_str); - GNUNET_free (ticket_str); - } - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -store_attr_cont (void *cls, - int32_t success, - const char*emsg) -{ - idp_op = NULL; - if (GNUNET_SYSERR == success) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%s\n", emsg); - } - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -process_attrs (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - char *value_str; - if (NULL == identity) - { - idp_op = NULL; - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); - return; - } - if (NULL == attr) - { - ret = 1; - return; - } - value_str = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "%s: %s\n", attr->name, value_str); -} - - -static void -iter_error (void *cls) -{ - attr_iterator = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to iterate over attributes\n"); - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -timeout_task (void *cls) -{ - timeout = NULL; - ret = 1; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Timeout\n"); - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -process_rvk (void *cls, int success, const char* msg) -{ - idp_op = NULL; - if (GNUNET_OK != success) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Revocation failed.\n"); - ret = 1; - } - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -iter_finished (void *cls) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *claim; - char *data; - size_t data_size; - int type; - - attr_iterator = NULL; - if (list) - { - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); - return; - } - - if (issue_attrs) - { - idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (idp_handle, - pkey, - &rp_key, - attr_list, - &ticket_issue_cb, - NULL); - return; - } - if (consume_ticket) - { - idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (idp_handle, - pkey, - &ticket, - &process_attrs, - NULL); - timeout = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), - &timeout_task, - NULL); - return; - } - if (revoke_ticket) - { - idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (idp_handle, - pkey, - &ticket, - &process_rvk, - NULL); - return; - } - if (attr_name) - { - if (NULL == type_str) - type = GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING; - else - type = GNUNET_IDENTITY_ATTRIBUTE_typename_to_number (type_str); - - GNUNET_assert (GNUNET_SYSERR != GNUNET_IDENTITY_ATTRIBUTE_string_to_value (type, - attr_value, - (void**)&data, - &data_size)); - claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr_name, - type, - data, - data_size); - idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (idp_handle, - pkey, - claim, - &exp_interval, - &store_attr_cont, - NULL); - return; - } - GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); -} - -static void -iter_cb (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - char *attrs_tmp; - char *attr_str; - - if (issue_attrs) - { - attrs_tmp = GNUNET_strdup (issue_attrs); - attr_str = strtok (attrs_tmp, ","); - while (NULL != attr_str) { - if (0 != strcmp (attr_str, attr->name)) { - attr_str = strtok (NULL, ","); - continue; - } - le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, - attr->type, - attr->data, - attr->data_size); - GNUNET_CONTAINER_DLL_insert (attr_list->list_head, - attr_list->list_tail, - le); - break; - } - GNUNET_free (attrs_tmp); - } else if (list) { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "%s: %s\n", attr->name, (char*)attr->data); - } - GNUNET_IDENTITY_PROVIDER_get_attributes_next (attr_iterator); -} - -static void -ego_iter_finished (void *cls) -{ - if (NULL == pkey) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Ego %s not found\n", ego_name); - return; - } - - if (NULL != rp) - GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, - strlen (rp), - &rp_key); - if (NULL != consume_ticket) - GNUNET_STRINGS_string_to_data (consume_ticket, - strlen (consume_ticket), - &ticket, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - if (NULL != revoke_ticket) - GNUNET_STRINGS_string_to_data (revoke_ticket, - strlen (revoke_ticket), - &ticket, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - - - attr_list = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - - attr_iterator = GNUNET_IDENTITY_PROVIDER_get_attributes_start (idp_handle, - pkey, - &iter_error, - NULL, - &iter_cb, - NULL, - &iter_finished, - NULL); - - -} - -static int init = GNUNET_YES; - -static void -ego_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) -{ - if (NULL == name) { - if (GNUNET_YES == init) { - init = GNUNET_NO; - GNUNET_SCHEDULER_add_now (&ego_iter_finished, NULL); - } - return; - } - if (0 != strcmp (name, ego_name)) - return; - pkey = GNUNET_IDENTITY_ego_get_private_key (ego); -} - - -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - ret = 0; - if (NULL == ego_name) - { - ret = 1; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - _("Ego is required\n")); - return; - } - - if ( (NULL == attr_value) && (NULL != attr_name) ) - { - ret = 1; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - _("Attribute value missing!\n")); - return; - } - - if ( (NULL == rp) && (NULL != issue_attrs) ) - { - ret = 1; - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - _("Requesting party key is required!\n")); - return; - } - - idp_handle = GNUNET_IDENTITY_PROVIDER_connect (c); - //Get Ego - identity_handle = GNUNET_IDENTITY_connect (c, - &ego_cb, - NULL); - - -} - - -int -main(int argc, char *const argv[]) -{ - exp_interval = GNUNET_TIME_UNIT_HOURS; - struct GNUNET_GETOPT_CommandLineOption options[] = { - - GNUNET_GETOPT_option_string ('a', - "add", - NULL, - gettext_noop ("Add attribute"), - &attr_name), - - GNUNET_GETOPT_option_string ('V', - "value", - NULL, - gettext_noop ("Attribute value"), - &attr_value), - GNUNET_GETOPT_option_string ('e', - "ego", - NULL, - gettext_noop ("Ego"), - &ego_name), - GNUNET_GETOPT_option_string ('r', - "rp", - NULL, - gettext_noop ("Audience (relying party)"), - &rp), - GNUNET_GETOPT_option_flag ('D', - "dump", - gettext_noop ("List attributes for Ego"), - &list), - GNUNET_GETOPT_option_string ('i', - "issue", - NULL, - gettext_noop ("Issue a ticket"), - &issue_attrs), - GNUNET_GETOPT_option_string ('C', - "consume", - NULL, - gettext_noop ("Consume a ticket"), - &consume_ticket), - GNUNET_GETOPT_option_string ('R', - "revoke", - NULL, - gettext_noop ("Revoke a ticket"), - &revoke_ticket), - GNUNET_GETOPT_option_string ('t', - "type", - NULL, - gettext_noop ("Type of attribute"), - &type_str), - GNUNET_GETOPT_option_relative_time ('E', - "expiration", - NULL, - gettext_noop ("Expiration interval of the attribute"), - &exp_interval), - - GNUNET_GETOPT_OPTION_END - }; - if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "ct", - "ct", options, - &run, NULL)) - return 1; - else - return ret; -} diff --git a/src/identity-provider/gnunet-service-identity-provider.c b/src/identity-provider/gnunet-service-identity-provider.c deleted file mode 100644 index 4563fdfa1..000000000 --- a/src/identity-provider/gnunet-service-identity-provider.c +++ /dev/null @@ -1,2786 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @file src/identity-provider/gnunet-service-identity-provider.c - * @brief Identity Token Service - * - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_identity_service.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_namestore_service.h" -#include "gnunet_abe_lib.h" -#include "gnunet_credential_service.h" -#include "gnunet_statistics_service.h" -#include "gnunet_gns_service.h" -#include "gnunet_identity_provider_plugin.h" -#include "gnunet_identity_attribute_lib.h" -#include "gnunet_signatures.h" -#include "identity_provider.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 - -/** - * Standard token expiration time - */ -#define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS - -/** - * Identity handle - */ -static struct GNUNET_IDENTITY_Handle *identity_handle; - -/** - * Database handle - */ -static struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *TKT_database; - -/** - * Name of DB plugin - */ -static char *db_lib_name; - -/** - * Token expiration interval - */ -static struct GNUNET_TIME_Relative token_expiration_interval; - -/** - * Namestore handle - */ -static struct GNUNET_NAMESTORE_Handle *ns_handle; - -/** - * GNS handle - */ -static struct GNUNET_GNS_Handle *gns_handle; - -/** - * Credential handle - */ -static struct GNUNET_CREDENTIAL_Handle *credential_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; - - -/** - * Currently processed token - */ -static struct IdentityToken *token; - -/** - * Label for currently processed token - */ -static char* label; - -/** - * Scopes for processed token - */ -static char* scopes; - -/** - * Handle to the statistics service. - */ -static struct GNUNET_STATISTICS_Handle *stats; - -/** - * Our configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * An idp client - */ -struct IdpClient; - -/** - * A ticket iteration operation. - */ -struct TicketIteration -{ - /** - * DLL - */ - struct TicketIteration *next; - - /** - * DLL - */ - struct TicketIteration *prev; - - /** - * Client which intiated this zone iteration - */ - struct IdpClient *client; - - /** - * Key of the identity we are iterating over. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity; - - /** - * Identity is audience - */ - uint32_t is_audience; - - /** - * The operation id fot the iteration in the response for the client - */ - uint32_t r_id; - - /** - * Offset of the iteration used to address next result of the - * iteration in the store - * - * Initialy set to 0 in handle_iteration_start - * Incremented with by every call to handle_iteration_next - */ - uint32_t offset; - -}; - - - -/** - * Callback after an ABE bootstrap - * - * @param cls closure - * @param abe_key the ABE key that exists or was created - */ -typedef void -(*AbeBootstrapResult) (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key); - - -struct AbeBootstrapHandle -{ - /** - * Function to call when finished - */ - AbeBootstrapResult proc; - - /** - * Callback closure - */ - char *proc_cls; - - /** - * Key of the zone we are iterating over. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Namestore Queue Entry - */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; - - /** - * The issuer egos ABE master key - */ - struct GNUNET_ABE_AbeMasterKey *abe_key; -}; - -/** - * An attribute iteration operation. - */ -struct AttributeIterator -{ - /** - * Next element in the DLL - */ - struct AttributeIterator *next; - - /** - * Previous element in the DLL - */ - struct AttributeIterator *prev; - - /** - * IDP client which intiated this zone iteration - */ - struct IdpClient *client; - - /** - * Key of the zone we are iterating over. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * The issuer egos ABE master key - */ - struct GNUNET_ABE_AbeMasterKey *abe_key; - - /** - * Namestore iterator - */ - struct GNUNET_NAMESTORE_ZoneIterator *ns_it; - - /** - * The operation id fot the zone iteration in the response for the client - */ - uint32_t request_id; - -}; - - - -/** - * An idp client - */ -struct IdpClient -{ - - /** - * The client - */ - struct GNUNET_SERVICE_Client *client; - - /** - * Message queue for transmission to @e client - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Head of the DLL of - * Attribute iteration operations in - * progress initiated by this client - */ - struct AttributeIterator *attr_iter_head; - - /** - * Tail of the DLL of - * Attribute iteration operations - * in progress initiated by this client - */ - struct AttributeIterator *attr_iter_tail; - - /** - * Head of DLL of ticket iteration ops - */ - struct TicketIteration *ticket_iter_head; - - /** - * Tail of DLL of ticket iteration ops - */ - struct TicketIteration *ticket_iter_tail; - - /** - * Head of DLL of ticket revocation ops - */ - struct TicketRevocationHandle *revoke_op_head; - - /** - * Tail of DLL of ticket revocation ops - */ - struct TicketRevocationHandle *revoke_op_tail; - - /** - * Head of DLL of ticket issue ops - */ - struct TicketIssueHandle *issue_op_head; - - /** - * Tail of DLL of ticket issue ops - */ - struct TicketIssueHandle *issue_op_tail; - - /** - * Head of DLL of ticket consume ops - */ - struct ConsumeTicketHandle *consume_op_head; - - /** - * Tail of DLL of ticket consume ops - */ - struct ConsumeTicketHandle *consume_op_tail; - - /** - * Head of DLL of attribute store ops - */ - struct AttributeStoreHandle *store_op_head; - - /** - * Tail of DLL of attribute store ops - */ - struct AttributeStoreHandle *store_op_tail; - -}; - -struct AttributeStoreHandle -{ - /** - * DLL - */ - struct AttributeStoreHandle *next; - - /** - * DLL - */ - struct AttributeStoreHandle *prev; - - /** - * Client connection - */ - struct IdpClient *client; - - /** - * Identity - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Identity pubkey - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey; - - /** - * The issuer egos ABE master key - */ - struct GNUNET_ABE_AbeMasterKey *abe_key; - - /** - * QueueEntry - */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; - - /** - * The attribute to store - */ - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *claim; - - /** - * The attribute expiration interval - */ - struct GNUNET_TIME_Relative exp; - - /** - * request id - */ - uint32_t r_id; -}; - - -/* Prototype */ -struct ParallelLookup; - -struct ConsumeTicketHandle -{ - /** - * DLL - */ - struct ConsumeTicketHandle *next; - - /** - * DLL - */ - struct ConsumeTicketHandle *prev; - - /** - * Client connection - */ - struct IdpClient *client; - - /** - * Ticket - */ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - - /** - * LookupRequest - */ - struct GNUNET_GNS_LookupRequest *lookup_request; - - /** - * Audience Key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Audience Key - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; - - /** - * Lookup DLL - */ - struct ParallelLookup *parallel_lookups_head; - - /** - * Lookup DLL - */ - struct ParallelLookup *parallel_lookups_tail; - - /** - * Kill task - */ - struct GNUNET_SCHEDULER_Task *kill_task; - - /** - * The ABE key - */ - struct GNUNET_ABE_AbeKey *key; - - /** - * Attributes - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - - /** - * Lookup time - */ - struct GNUNET_TIME_Absolute lookup_start_time; - - /** - * request id - */ - uint32_t r_id; -}; - -/** - * Handle for a parallel GNS lookup job - */ -struct ParallelLookup -{ - /* DLL */ - struct ParallelLookup *next; - - /* DLL */ - struct ParallelLookup *prev; - - /* The GNS request */ - struct GNUNET_GNS_LookupRequest *lookup_request; - - /* The handle the return to */ - struct ConsumeTicketHandle *handle; - - /** - * Lookup time - */ - struct GNUNET_TIME_Absolute lookup_start_time; - - /* The label to look up */ - char *label; -}; - -/** - * Ticket revocation request handle - */ -struct TicketRevocationHandle -{ - /** - * DLL - */ - struct TicketRevocationHandle *prev; - - /** - * DLL - */ - struct TicketRevocationHandle *next; - - /** - * Client connection - */ - struct IdpClient *client; - - /** - * Attributes to reissue - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - - /** - * Attributes to revoke - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *rvk_attrs; - - /** - * Issuer Key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Ticket to issue - */ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - - /** - * QueueEntry - */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; - - /** - * Namestore iterator - */ - struct GNUNET_NAMESTORE_ZoneIterator *ns_it; - - /** - * The ABE master key - */ - struct GNUNET_ABE_AbeMasterKey *abe_key; - - /** - * Offset - */ - uint32_t offset; - - /** - * request id - */ - uint32_t r_id; -}; - - - -/** - * Ticket issue request handle - */ -struct TicketIssueHandle -{ - /** - * DLL - */ - struct TicketIssueHandle *prev; - - /** - * DLL - */ - struct TicketIssueHandle *next; - - /** - * Client connection - */ - struct IdpClient *client; - - /** - * Attributes to issue - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - - /** - * Issuer Key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Ticket to issue - */ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - - /** - * QueueEntry - */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; - - /** - * request id - */ - uint32_t r_id; -}; - - -/** - * 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; - -}; - -/** - * Cleanup task - */ -static void -cleanup() -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - - if (NULL != stats) - { - GNUNET_STATISTICS_destroy (stats, GNUNET_NO); - stats = NULL; - } - GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, - TKT_database)); - GNUNET_free (db_lib_name); - db_lib_name = NULL; - 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 != gns_handle) - GNUNET_GNS_disconnect (gns_handle); - if (NULL != credential_handle) - GNUNET_CREDENTIAL_disconnect (credential_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); - GNUNET_free_non_null (token); - GNUNET_free_non_null (label); - -} - -/** - * Shutdown task - * - * @param cls NULL - */ -static void -do_shutdown (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Shutting down...\n"); - cleanup(); -} - -/** - * Finished storing newly bootstrapped ABE key - */ -static void -bootstrap_store_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct AbeBootstrapHandle *abh = cls; - if (GNUNET_SYSERR == success) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to bootstrap ABE master %s\n", - emsg); - abh->proc (abh->proc_cls, NULL); - GNUNET_free (abh->abe_key); - GNUNET_free (abh); - return; - } - abh->proc (abh->proc_cls, abh->abe_key); - GNUNET_free (abh); -} - -/** - * Generates and stores a new ABE key - */ -static void -bootstrap_store_task (void *cls) -{ - struct AbeBootstrapHandle *abh = cls; - struct GNUNET_GNSRECORD_Data rd[1]; - char *key; - - rd[0].data_size = GNUNET_ABE_cpabe_serialize_master_key (abh->abe_key, - (void**)&key); - rd[0].data = key; - rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER; - rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE; - rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane? - abh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &abh->identity, - "+", - 1, - rd, - &bootstrap_store_cont, - abh); - GNUNET_free (key); -} - -/** - * Error checking for ABE master - */ -static void -bootstrap_abe_error (void *cls) -{ - struct AbeBootstrapHandle *abh = cls; - abh->proc (abh->proc_cls, NULL); - GNUNET_free (abh); -} - - -/** - * Handle ABE lookup in namestore - */ -static void -bootstrap_abe_result (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct AbeBootstrapHandle *abh = cls; - struct GNUNET_ABE_AbeMasterKey *abe_key; - - for (uint32_t i=0;iproc (abh->proc_cls, abe_key); - GNUNET_free (abh); - return; - } - - //No ABE master found, bootstrapping... - abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); - GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); -} - -/** - * Bootstrap ABE master if it does not yet exists. - * Will call the AbeBootstrapResult processor when done. - * will always recreate the ABE key of GNUNET_YES == recreate - */ -static void -bootstrap_abe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - AbeBootstrapResult proc, - void* cls, - int recreate) -{ - struct AbeBootstrapHandle *abh; - - abh = GNUNET_new (struct AbeBootstrapHandle); - abh->proc = proc; - abh->proc_cls = cls; - abh->identity = *identity; - if (GNUNET_YES == recreate) - { - abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); - GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); - } else { - abh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, - identity, - "+", - &bootstrap_abe_error, - abh, - &bootstrap_abe_result, - abh); - } -} - - - -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_DEBUG, "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; -} - -/** - * Cleanup ticket consume handle - * @param handle the handle to clean up - */ -static void -cleanup_ticket_issue_handle (struct TicketIssueHandle *handle) -{ - if (NULL != handle->attrs) - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (handle->attrs); - if (NULL != handle->ns_qe) - GNUNET_NAMESTORE_cancel (handle->ns_qe); - GNUNET_free (handle); -} - - -static void -send_ticket_result (struct IdpClient *client, - uint32_t r_id, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct TicketResultMessage *irm; - struct GNUNET_MQ_Envelope *env; - struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket_buf; - - /* store ticket in DB */ - if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, - ticket, - attrs)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to store ticket after issue\n"); - GNUNET_break (0); - } - - env = GNUNET_MQ_msg_extra (irm, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket), - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT); - ticket_buf = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&irm[1]; - *ticket_buf = *ticket; - irm->id = htonl (r_id); - GNUNET_MQ_send (client->mq, - env); -} - -static void -store_ticket_issue_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct TicketIssueHandle *handle = cls; - - handle->ns_qe = NULL; - GNUNET_CONTAINER_DLL_remove (handle->client->issue_op_head, - handle->client->issue_op_tail, - handle); - if (GNUNET_SYSERR == success) - { - cleanup_ticket_issue_handle (handle); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", - "Unknown Error\n"); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; - } - send_ticket_result (handle->client, - handle->r_id, - &handle->ticket, - handle->attrs); - cleanup_ticket_issue_handle (handle); -} - - - -int -serialize_abe_keyinfo2 (const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - const struct GNUNET_ABE_AbeKey *rp_key, - struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, - char **result) -{ - struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - char *enc_keyinfo; - char *serialized_key; - char *buf; - char *write_ptr; - char attrs_str_len; - ssize_t size; - - struct GNUNET_CRYPTO_SymmetricSessionKey skey; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct GNUNET_HashCode new_key_hash; - ssize_t enc_size; - - size = GNUNET_ABE_cpabe_serialize_key (rp_key, - (void**)&serialized_key); - attrs_str_len = 0; - for (le = attrs->list_head; NULL != le; le = le->next) { - attrs_str_len += strlen (le->claim->name) + 1; - } - buf = GNUNET_malloc (attrs_str_len + size); - write_ptr = buf; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Writing attributes\n"); - for (le = attrs->list_head; NULL != le; le = le->next) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s\n", le->claim->name); - - - GNUNET_memcpy (write_ptr, - le->claim->name, - strlen (le->claim->name)); - write_ptr[strlen (le->claim->name)] = ','; - write_ptr += strlen (le->claim->name) + 1; - } - write_ptr--; - write_ptr[0] = '\0'; //replace last , with a 0-terminator - write_ptr++; - GNUNET_memcpy (write_ptr, - serialized_key, - size); - GNUNET_free (serialized_key); - // ECDH keypair E = eG - *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create(); - GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey, - &ecdh_pubkey); - enc_keyinfo = GNUNET_malloc (size + attrs_str_len); - // Derived key K = H(eB) - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey, - &ticket->audience, - &new_key_hash)); - create_sym_key_from_ecdh(&new_key_hash, &skey, &iv); - enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf, - size + attrs_str_len, - &skey, &iv, - enc_keyinfo); - *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+ - enc_size); - GNUNET_memcpy (*result, - &ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), - enc_keyinfo, - enc_size); - GNUNET_free (enc_keyinfo); - GNUNET_free (buf); - return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size; -} - - - -static void -issue_ticket_after_abe_bootstrap (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key) -{ - struct TicketIssueHandle *ih = cls; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; - struct GNUNET_GNSRECORD_Data code_record[1]; - struct GNUNET_ABE_AbeKey *rp_key; - char *code_record_data; - char **attrs; - char *label; - char *policy; - int attrs_len; - uint32_t i; - size_t code_record_len; - - //Create new ABE key for RP - attrs_len = 0; - for (le = ih->attrs->list_head; NULL != le; le = le->next) - attrs_len++; - attrs = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); - i = 0; - for (le = ih->attrs->list_head; NULL != le; le = le->next) { - GNUNET_asprintf (&policy, "%s_%lu", - le->claim->name, - le->claim->version); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Adding attribute to key: %s\n", - policy); - attrs[i] = policy; - i++; - } - attrs[i] = NULL; - rp_key = GNUNET_ABE_cpabe_create_key (abe_key, - attrs); - - //TODO review this wireformat - code_record_len = serialize_abe_keyinfo2 (&ih->ticket, - ih->attrs, - rp_key, - &ecdhe_privkey, - &code_record_data); - code_record[0].data = code_record_data; - code_record[0].data_size = code_record_len; - code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; - code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; - code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - - label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, - sizeof (uint64_t)); - //Publish record - ih->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &ih->identity, - label, - 1, - code_record, - &store_ticket_issue_cont, - ih); - //for (; i > 0; i--) - // GNUNET_free (attrs[i-1]); - GNUNET_free (ecdhe_privkey); - GNUNET_free (label); - GNUNET_free (attrs); - GNUNET_free (code_record_data); - GNUNET_ABE_cpabe_delete_key (rp_key, - GNUNET_YES); - GNUNET_ABE_cpabe_delete_master_key (abe_key); -} - - -static int -check_issue_ticket_message(void *cls, - const struct IssueTicketMessage *im) -{ - uint16_t size; - - size = ntohs (im->header.size); - if (size <= sizeof (struct IssueTicketMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_issue_ticket_message (void *cls, - const struct IssueTicketMessage *im) -{ - struct TicketIssueHandle *ih; - struct IdpClient *idp = cls; - size_t attrs_len; - - ih = GNUNET_new (struct TicketIssueHandle); - attrs_len = ntohs (im->attr_len); - ih->attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len); - ih->r_id = ntohl (im->id); - ih->client = idp; - ih->identity = im->identity; - GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity, - &ih->ticket.identity); - ih->ticket.audience = im->rp; - ih->ticket.rnd = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, - UINT64_MAX); - GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, - idp->issue_op_tail, - ih); - bootstrap_abe (&ih->identity, &issue_ticket_after_abe_bootstrap, ih, GNUNET_NO); - GNUNET_SERVICE_client_continue (idp->client); - -} - -/********************************************************** - * Revocation - **********************************************************/ - -/** - * Cleanup revoke handle - * - * @param rh the ticket revocation handle - */ -static void -cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh) -{ - if (NULL != rh->attrs) - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (rh->attrs); - if (NULL != rh->rvk_attrs) - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (rh->rvk_attrs); - if (NULL != rh->abe_key) - GNUNET_ABE_cpabe_delete_master_key (rh->abe_key); - if (NULL != rh->ns_qe) - GNUNET_NAMESTORE_cancel (rh->ns_qe); - if (NULL != rh->ns_it) - GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it); - GNUNET_free (rh); -} - - -/** - * Send revocation result - * - * @param rh ticket revocation handle - * @param success GNUNET_OK if successful result - */ -static void -send_revocation_finished (struct TicketRevocationHandle *rh, - uint32_t success) -{ - struct GNUNET_MQ_Envelope *env; - struct RevokeTicketResultMessage *trm; - - GNUNET_break(TKT_database->delete_ticket (TKT_database->cls, - &rh->ticket)); - - env = GNUNET_MQ_msg (trm, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT); - trm->id = htonl (rh->r_id); - trm->success = htonl (success); - GNUNET_MQ_send (rh->client->mq, - env); - GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head, - rh->client->revoke_op_tail, - rh); -} - - -/** - * Process ticket from database - * - * @param cls struct TicketIterationProcResult - * @param ticket the ticket - * @param attrs the attributes - */ -static void -ticket_reissue_proc (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - -static void -revocation_reissue_tickets (struct TicketRevocationHandle *rh); - - -static void reissue_next (void *cls) -{ - struct TicketRevocationHandle *rh = cls; - revocation_reissue_tickets (rh); -} - - -static void -reissue_ticket_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct TicketRevocationHandle *rh = cls; - - rh->ns_qe = NULL; - if (GNUNET_SYSERR == success) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", - "Unknown Error\n"); - send_revocation_finished (rh, GNUNET_SYSERR); - cleanup_revoke_ticket_handle (rh); - return; - } - rh->offset++; - GNUNET_SCHEDULER_add_now (&reissue_next, rh); -} - - -/** - * Process ticket from database - * - * @param cls struct TicketIterationProcResult - * @param ticket the ticket - * @param attrs the attributes - */ -static void -ticket_reissue_proc (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct TicketRevocationHandle *rh = cls; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le_rollover; - struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; - struct GNUNET_GNSRECORD_Data code_record[1]; - struct GNUNET_ABE_AbeKey *rp_key; - char *code_record_data; - char **attr_arr; - char *label; - char *policy; - int attrs_len; - uint32_t i; - int reissue_ticket; - size_t code_record_len; - - - if (NULL == ticket) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Iteration done\n"); - return; - } - - if (0 == memcmp (&ticket->audience, - &rh->ticket.audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Do not reissue for this identity.!\n"); - label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd, - sizeof (uint64_t)); - //Delete record - rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &rh->identity, - label, - 0, - NULL, - &reissue_ticket_cont, - rh); - - GNUNET_free (label); - return; - } - - /* - * Check if any attribute of this ticket intersects with a rollover attribute - */ - reissue_ticket = GNUNET_NO; - for (le = attrs->list_head; NULL != le; le = le->next) - { - for (le_rollover = rh->rvk_attrs->list_head; - NULL != le_rollover; - le_rollover = le_rollover->next) - { - if (0 == strcmp (le_rollover->claim->name, - le->claim->name)) - { - reissue_ticket = GNUNET_YES; - le->claim->version = le_rollover->claim->version; - } - } - } - - if (GNUNET_NO == reissue_ticket) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Skipping ticket.\n"); - - rh->offset++; - GNUNET_SCHEDULER_add_now (&reissue_next, rh); - - - return; - } - - //Create new ABE key for RP - attrs_len = 0; - - /* If this is the RP we want to revoke attributes of, the do so */ - - for (le = attrs->list_head; NULL != le; le = le->next) - attrs_len++; - attr_arr = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); - i = 0; - for (le = attrs->list_head; NULL != le; le = le->next) { - GNUNET_asprintf (&policy, "%s_%lu", - le->claim->name, - le->claim->version); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Recreating key with %s\n", policy); - attr_arr[i] = policy; - i++; - } - attr_arr[i] = NULL; - rp_key = GNUNET_ABE_cpabe_create_key (rh->abe_key, - attr_arr); - - //TODO review this wireformat - code_record_len = serialize_abe_keyinfo2 (ticket, - attrs, - rp_key, - &ecdhe_privkey, - &code_record_data); - code_record[0].data = code_record_data; - code_record[0].data_size = code_record_len; - code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; - code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; - code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - - label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, - sizeof (uint64_t)); - //Publish record - rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &rh->identity, - label, - 1, - code_record, - &reissue_ticket_cont, - rh); - //for (; i > 0; i--) - // GNUNET_free (attr_arr[i-1]); - GNUNET_free (ecdhe_privkey); - GNUNET_free (label); - GNUNET_free (attr_arr); - GNUNET_free (code_record_data); - GNUNET_ABE_cpabe_delete_key (rp_key, GNUNET_YES); -} - - -/* Prototype for below function */ -static void -attr_reenc_cont (void *cls, - int32_t success, - const char *emsg); - -static void -revocation_reissue_tickets (struct TicketRevocationHandle *rh) -{ - int ret; - /* Done, issue new keys */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Revocation Phase III: Reissuing Tickets\n"); - if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls, - &rh->ticket.identity, - GNUNET_NO, - rh->offset, - &ticket_reissue_proc, - rh))) - { - GNUNET_break (0); - } - if (GNUNET_NO == ret) - { - send_revocation_finished (rh, GNUNET_OK); - cleanup_revoke_ticket_handle (rh); - return; - } -} - -/** - * Failed to check for attribute - */ -static void -check_attr_error (void *cls) -{ - struct TicketRevocationHandle *rh = cls; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to check for existing attribute\n"); - rh->ns_qe = NULL; - send_revocation_finished (rh, GNUNET_SYSERR); - cleanup_revoke_ticket_handle (rh); -} - - -/** - * Revoke next attribte by reencryption with - * new ABE master - */ -static void -reenc_next_attribute (void *cls); - -/** - * Check for existing attribute and overwrite - */ -static void -check_attr_cb (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd_old) -{ - struct TicketRevocationHandle *rh = cls; - struct GNUNET_GNSRECORD_Data rd[1]; - char* buf; - char* enc_buf; - size_t enc_size; - char* rd_buf; - size_t buf_size; - char* policy; - uint32_t attr_ver; - - rh->ns_qe = NULL; - if (1 != rd_count) { - GNUNET_SCHEDULER_add_now (&reenc_next_attribute, - rh); - return; - } - - buf_size = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim); - buf = GNUNET_malloc (buf_size); - GNUNET_IDENTITY_ATTRIBUTE_serialize (rh->attrs->list_head->claim, - buf); - rh->attrs->list_head->claim->version++; - GNUNET_asprintf (&policy, "%s_%lu", - rh->attrs->list_head->claim->name, - rh->attrs->list_head->claim->version); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting with policy %s\n", policy); - /** - * Encrypt the attribute value and store in namestore - */ - enc_size = GNUNET_ABE_cpabe_encrypt (buf, - buf_size, - policy, //Policy - rh->abe_key, - (void**)&enc_buf); - GNUNET_free (buf); - if (GNUNET_SYSERR == enc_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to re-encrypt with policy %s\n", - policy); - GNUNET_free (policy); - send_revocation_finished (rh, GNUNET_SYSERR); - cleanup_revoke_ticket_handle (rh); - return; - } - GNUNET_free (policy); - - rd[0].data_size = enc_size + sizeof (uint32_t); - rd_buf = GNUNET_malloc (rd[0].data_size); - attr_ver = htonl (rh->attrs->list_head->claim->version); - GNUNET_memcpy (rd_buf, - &attr_ver, - sizeof (uint32_t)); - GNUNET_memcpy (rd_buf+sizeof (uint32_t), - enc_buf, - enc_size); - rd[0].data = rd_buf; - rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; - rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd[0].expiration_time = rd_old[0].expiration_time; - rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &rh->identity, - rh->attrs->list_head->claim->name, - 1, - rd, - &attr_reenc_cont, - rh); - GNUNET_free (enc_buf); - GNUNET_free (rd_buf); -} - - -/** - * Revoke next attribte by reencryption with - * new ABE master - */ -static void -reenc_next_attribute (void *cls) -{ - struct TicketRevocationHandle *rh = cls; - if (NULL == rh->attrs->list_head) - { - revocation_reissue_tickets (rh); - return; - } - /* First check if attribute still exists */ - rh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, - &rh->identity, - rh->attrs->list_head->claim->name, - &check_attr_error, - rh, - &check_attr_cb, - rh); -} - - -/** - * Namestore callback after revoked attribute - * is stored - */ -static void -attr_reenc_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct TicketRevocationHandle *rh = cls; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - - rh->ns_qe = NULL; - if (GNUNET_SYSERR == success) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to reencrypt attribute %s\n", - emsg); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; - } - if (NULL == rh->attrs->list_head) - { - revocation_reissue_tickets (rh); - return; - } - le = rh->attrs->list_head; - GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head, - rh->attrs->list_tail, - le); - GNUNET_assert (NULL != rh->rvk_attrs); - GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head, - rh->rvk_attrs->list_tail, - le); - - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Re-encrypting next attribute\n"); - reenc_next_attribute (rh); -} - - -static void -process_attributes_to_update (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct TicketRevocationHandle *rh = cls; - - rh->attrs = GNUNET_IDENTITY_ATTRIBUTE_list_dup (attrs); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Revocation Phase I: Collecting attributes\n"); - /* Reencrypt all attributes with new key */ - if (NULL == rh->attrs->list_head) - { - /* No attributes to reencrypt */ - send_revocation_finished (rh, GNUNET_OK); - cleanup_revoke_ticket_handle (rh); - return; - } else { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Revocation Phase II: Re-encrypting attributes\n"); - reenc_next_attribute (rh); - } - -} - - - -static void -get_ticket_after_abe_bootstrap (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finished ABE bootstrap\n"); - struct TicketRevocationHandle *rh = cls; - rh->abe_key = abe_key; - TKT_database->get_ticket_attributes (TKT_database->cls, - &rh->ticket, - &process_attributes_to_update, - rh); -} - -static int -check_revoke_ticket_message(void *cls, - const struct RevokeTicketMessage *im) -{ - uint16_t size; - - size = ntohs (im->header.size); - if (size <= sizeof (struct RevokeTicketMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - -static void -handle_revoke_ticket_message (void *cls, - const struct RevokeTicketMessage *rm) -{ - struct TicketRevocationHandle *rh; - struct IdpClient *idp = cls; - struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; - - rh = GNUNET_new (struct TicketRevocationHandle); - ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket*)&rm[1]; - rh->rvk_attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - rh->ticket = *ticket; - rh->r_id = ntohl (rm->id); - rh->client = idp; - rh->identity = rm->identity; - GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity, - &rh->ticket.identity); - GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, - idp->revoke_op_tail, - rh); - bootstrap_abe (&rh->identity, &get_ticket_after_abe_bootstrap, rh, GNUNET_NO); - GNUNET_SERVICE_client_continue (idp->client); - -} - -/** - * Cleanup ticket consume handle - * @param handle the handle to clean up - */ -static void -cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle) -{ - struct ParallelLookup *lu; - struct ParallelLookup *tmp; - if (NULL != handle->lookup_request) - GNUNET_GNS_lookup_cancel (handle->lookup_request); - for (lu = handle->parallel_lookups_head; - NULL != lu;) { - GNUNET_GNS_lookup_cancel (lu->lookup_request); - GNUNET_free (lu->label); - tmp = lu->next; - GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, - handle->parallel_lookups_tail, - lu); - GNUNET_free (lu); - lu = tmp; - } - - if (NULL != handle->key) - GNUNET_ABE_cpabe_delete_key (handle->key, - GNUNET_YES); - if (NULL != handle->attrs) - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (handle->attrs); - GNUNET_free (handle); -} - - - -static int -check_consume_ticket_message(void *cls, - const struct ConsumeTicketMessage *cm) -{ - uint16_t size; - - size = ntohs (cm->header.size); - if (size <= sizeof (struct ConsumeTicketMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - -static void -process_parallel_lookup2 (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Parallel lookup finished (count=%u)\n", rd_count); - struct ParallelLookup *parallel_lookup = cls; - struct ConsumeTicketHandle *handle = parallel_lookup->handle; - struct ConsumeTicketResultMessage *crm; - struct GNUNET_MQ_Envelope *env; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *attr_le; - struct GNUNET_TIME_Absolute decrypt_duration; - char *data; - char *data_tmp; - ssize_t attr_len; - size_t attrs_len; - - GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, - handle->parallel_lookups_tail, - parallel_lookup); - GNUNET_free (parallel_lookup->label); - - GNUNET_STATISTICS_update (stats, - "attribute_lookup_time_total", - GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us, - GNUNET_YES); - GNUNET_STATISTICS_update (stats, - "attribute_lookups_count", - 1, - GNUNET_YES); - - - GNUNET_free (parallel_lookup); - if (1 != rd_count) - GNUNET_break(0);//TODO - if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) - { - decrypt_duration = GNUNET_TIME_absolute_get (); - attr_len = GNUNET_ABE_cpabe_decrypt (rd->data + sizeof (uint32_t), - rd->data_size - sizeof (uint32_t), - handle->key, - (void**)&data); - if (GNUNET_SYSERR != attr_len) - { - GNUNET_STATISTICS_update (stats, - "abe_decrypt_time_total", - GNUNET_TIME_absolute_get_duration (decrypt_duration).rel_value_us, - GNUNET_YES); - GNUNET_STATISTICS_update (stats, - "abe_decrypt_count", - 1, - GNUNET_YES); - - attr_le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - attr_le->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize (data, - attr_len); - attr_le->claim->version = ntohl(*(uint32_t*)rd->data); - GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head, - handle->attrs->list_tail, - attr_le); - GNUNET_free (data); - } - } - if (NULL != handle->parallel_lookups_head) - return; //Wait for more - /* Else we are done */ - - /* Store ticket in DB */ - if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, - &handle->ticket, - handle->attrs)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to store ticket after consume\n"); - GNUNET_break (0); - } - - GNUNET_SCHEDULER_cancel (handle->kill_task); - attrs_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (handle->attrs); - env = GNUNET_MQ_msg_extra (crm, - attrs_len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT); - crm->id = htonl (handle->r_id); - crm->attrs_len = htons (attrs_len); - crm->identity = handle->ticket.identity; - data_tmp = (char *) &crm[1]; - GNUNET_IDENTITY_ATTRIBUTE_list_serialize (handle->attrs, - data_tmp); - GNUNET_MQ_send (handle->client->mq, env); - GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head, - handle->client->consume_op_tail, - handle); - cleanup_consume_ticket_handle (handle); -} - -void -abort_parallel_lookups2 (void *cls) -{ - struct ConsumeTicketHandle *handle = cls; - struct ParallelLookup *lu; - struct ParallelLookup *tmp; - struct AttributeResultMessage *arm; - struct GNUNET_MQ_Envelope *env; - - handle->kill_task = NULL; - for (lu = handle->parallel_lookups_head; - NULL != lu;) { - GNUNET_GNS_lookup_cancel (lu->lookup_request); - GNUNET_free (lu->label); - tmp = lu->next; - GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, - handle->parallel_lookups_tail, - lu); - GNUNET_free (lu); - lu = tmp; - } - env = GNUNET_MQ_msg (arm, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); - arm->id = htonl (handle->r_id); - arm->attr_len = htons (0); - GNUNET_MQ_send (handle->client->mq, env); - -} - - -static void -process_consume_abe_key (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct ConsumeTicketHandle *handle = cls; - struct GNUNET_HashCode new_key_hash; - struct GNUNET_CRYPTO_SymmetricSessionKey enc_key; - struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv; - struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key; - struct ParallelLookup *parallel_lookup; - size_t size; - char *buf; - char *scope; - - handle->lookup_request = NULL; - if (1 != rd_count) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Number of keys %d != 1.", - rd_count); - cleanup_consume_ticket_handle (handle); - GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head, - handle->client->consume_op_tail, - handle); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; - } - - //Decrypt - ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data; - - buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - - //Calculate symmetric key from ecdh parameters - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity, - ecdh_key, - &new_key_hash)); - create_sym_key_from_ecdh (&new_key_hash, - &enc_key, - &enc_iv); - size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), - rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), - &enc_key, - &enc_iv, - buf); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Decrypted bytes: %zd Expected bytes: %zd\n", - size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - GNUNET_STATISTICS_update (stats, - "abe_key_lookup_time_total", - GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us, - GNUNET_YES); - GNUNET_STATISTICS_update (stats, - "abe_key_lookups_count", - 1, - GNUNET_YES); - scopes = GNUNET_strdup (buf); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scopes %s\n", scopes); - handle->key = GNUNET_ABE_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1), - rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) - - strlen (scopes) - 1); - - for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ",")) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Looking up %s\n", scope); - parallel_lookup = GNUNET_new (struct ParallelLookup); - parallel_lookup->handle = handle; - parallel_lookup->label = GNUNET_strdup (scope); - parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get(); - parallel_lookup->lookup_request - = GNUNET_GNS_lookup (gns_handle, - scope, - &handle->ticket.identity, - GNUNET_GNSRECORD_TYPE_ID_ATTR, - GNUNET_GNS_LO_DEFAULT, - &process_parallel_lookup2, - parallel_lookup); - GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head, - handle->parallel_lookups_tail, - parallel_lookup); - } - GNUNET_free (scopes); - GNUNET_free (buf); - handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3), - &abort_parallel_lookups2, - handle); -} - - -static void -handle_consume_ticket_message (void *cls, - const struct ConsumeTicketMessage *cm) -{ - struct ConsumeTicketHandle *ch; - struct IdpClient *idp = cls; - char* rnd_label; - - ch = GNUNET_new (struct ConsumeTicketHandle); - ch->r_id = ntohl (cm->id); - ch->client = idp; - ch->identity = cm->identity; - ch->attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity, - &ch->identity_pub); - ch->ticket = *((struct GNUNET_IDENTITY_PROVIDER_Ticket*)&cm[1]); - rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd, - sizeof (uint64_t)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Looking for ABE key under %s\n", rnd_label); - ch->lookup_start_time = GNUNET_TIME_absolute_get (); - ch->lookup_request - = GNUNET_GNS_lookup (gns_handle, - rnd_label, - &ch->ticket.identity, - GNUNET_GNSRECORD_TYPE_ABE_KEY, - GNUNET_GNS_LO_DEFAULT, - &process_consume_abe_key, - ch); - GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, - idp->consume_op_tail, - ch); - GNUNET_free (rnd_label); - GNUNET_SERVICE_client_continue (idp->client); -} - -/** - * Cleanup attribute store handle - * - * @param handle handle to clean up - */ -static void -cleanup_as_handle (struct AttributeStoreHandle *handle) -{ - if (NULL != handle->ns_qe) - GNUNET_NAMESTORE_cancel (handle->ns_qe); - if (NULL != handle->claim) - GNUNET_free (handle->claim); - if (NULL != handle->abe_key) - GNUNET_ABE_cpabe_delete_master_key (handle->abe_key); - GNUNET_free (handle); -} - -static void -attr_store_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct AttributeStoreHandle *as_handle = cls; - struct GNUNET_MQ_Envelope *env; - struct AttributeStoreResultMessage *acr_msg; - - as_handle->ns_qe = NULL; - GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head, - as_handle->client->store_op_tail, - as_handle); - - if (GNUNET_SYSERR == success) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to store attribute %s\n", - emsg); - cleanup_as_handle (as_handle); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending ATTRIBUTE_STORE_RESPONSE message\n"); - env = GNUNET_MQ_msg (acr_msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE); - acr_msg->id = htonl (as_handle->r_id); - acr_msg->op_result = htonl (GNUNET_OK); - GNUNET_MQ_send (as_handle->client->mq, - env); - cleanup_as_handle (as_handle); -} - -static void -attr_store_task (void *cls) -{ - struct AttributeStoreHandle *as_handle = cls; - struct GNUNET_GNSRECORD_Data rd[1]; - char* buf; - char* policy; - char* enc_buf; - char* rd_buf; - size_t enc_size; - size_t buf_size; - uint32_t attr_ver; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Storing attribute\n"); - buf_size = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (as_handle->claim); - buf = GNUNET_malloc (buf_size); - - GNUNET_IDENTITY_ATTRIBUTE_serialize (as_handle->claim, - buf); - - GNUNET_asprintf (&policy, - "%s_%lu", - as_handle->claim->name, - as_handle->claim->version); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting with policy %s\n", policy); - /** - * Encrypt the attribute value and store in namestore - */ - enc_size = GNUNET_ABE_cpabe_encrypt (buf, - buf_size, - policy, //Policy - as_handle->abe_key, - (void**)&enc_buf); - if (GNUNET_SYSERR == enc_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to encrypt with policy %s\n", - policy); - GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head, - as_handle->client->store_op_tail, - as_handle); - - cleanup_as_handle (as_handle); - GNUNET_free (buf); - GNUNET_free (policy); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; - } - GNUNET_free (buf); - GNUNET_free (policy); - rd[0].data_size = enc_size + sizeof (uint32_t); - rd_buf = GNUNET_malloc (rd[0].data_size); - attr_ver = htonl (as_handle->claim->version); - GNUNET_memcpy (rd_buf, - &attr_ver, - sizeof (uint32_t)); - GNUNET_memcpy (rd_buf+sizeof (uint32_t), - enc_buf, - enc_size); - rd[0].data = rd_buf; - rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; - rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd[0].expiration_time = as_handle->exp.rel_value_us; - as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &as_handle->identity, - as_handle->claim->name, - 1, - rd, - &attr_store_cont, - as_handle); - GNUNET_free (enc_buf); - GNUNET_free (rd_buf); -} - - -static void -store_after_abe_bootstrap (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finished ABE bootstrap\n"); - struct AttributeStoreHandle *ash = cls; - ash->abe_key = abe_key; - GNUNET_SCHEDULER_add_now (&attr_store_task, ash); -} - -static int -check_attribute_store_message(void *cls, - const struct AttributeStoreMessage *sam) -{ - uint16_t size; - - size = ntohs (sam->header.size); - if (size <= sizeof (struct AttributeStoreMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -static void -handle_attribute_store_message (void *cls, - const struct AttributeStoreMessage *sam) -{ - struct AttributeStoreHandle *as_handle; - struct IdpClient *idp = cls; - size_t data_len; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received ATTRIBUTE_STORE message\n"); - - data_len = ntohs (sam->attr_len); - - as_handle = GNUNET_new (struct AttributeStoreHandle); - as_handle->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&sam[1], - data_len); - - as_handle->r_id = ntohl (sam->id); - as_handle->identity = sam->identity; - as_handle->exp.rel_value_us = GNUNET_ntohll (sam->exp); - GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, - &as_handle->identity_pkey); - - GNUNET_SERVICE_client_continue (idp->client); - as_handle->client = idp; - GNUNET_CONTAINER_DLL_insert (idp->store_op_head, - idp->store_op_tail, - as_handle); - bootstrap_abe (&as_handle->identity, &store_after_abe_bootstrap, as_handle, GNUNET_NO); -} - -static void -cleanup_attribute_iter_handle (struct AttributeIterator *ai) -{ - if (NULL != ai->abe_key) - GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); - GNUNET_free (ai); -} - -static void -attr_iter_error (void *cls) -{ - struct AttributeIterator *ai = cls; - //TODO - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to iterate over attributes\n"); - GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head, - ai->client->attr_iter_tail, - ai); - cleanup_attribute_iter_handle (ai); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); -} - -static void -attr_iter_finished (void *cls) -{ - struct AttributeIterator *ai = cls; - struct GNUNET_MQ_Envelope *env; - struct AttributeResultMessage *arm; - - env = GNUNET_MQ_msg (arm, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); - arm->id = htonl (ai->request_id); - arm->attr_len = htons (0); - GNUNET_MQ_send (ai->client->mq, env); - GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head, - ai->client->attr_iter_tail, - ai); - cleanup_attribute_iter_handle (ai); -} - -static void -attr_iter_cb (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct AttributeIterator *ai = cls; - struct AttributeResultMessage *arm; - struct GNUNET_ABE_AbeKey *key; - struct GNUNET_MQ_Envelope *env; - ssize_t msg_extra_len; - char* attr_ser; - char* attrs[2]; - char* data_tmp; - char* policy; - uint32_t attr_ver; - - if (rd_count != 1) - { - GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, - 1); - return; - } - - if (GNUNET_GNSRECORD_TYPE_ID_ATTR != rd->record_type) - { - GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, - 1); - return; - } - attr_ver = ntohl(*((uint32_t*)rd->data)); - GNUNET_asprintf (&policy, "%s_%lu", - label, attr_ver); - attrs[0] = policy; - attrs[1] = 0; - key = GNUNET_ABE_cpabe_create_key (ai->abe_key, - attrs); - msg_extra_len = GNUNET_ABE_cpabe_decrypt (rd->data+sizeof (uint32_t), - rd->data_size-sizeof (uint32_t), - key, - (void**)&attr_ser); - if (GNUNET_SYSERR == msg_extra_len) - { - GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, - 1); - return; - } - - GNUNET_ABE_cpabe_delete_key (key, - GNUNET_YES); - //GNUNET_free (policy); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found attribute: %s\n", label); - env = GNUNET_MQ_msg_extra (arm, - msg_extra_len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); - arm->id = htonl (ai->request_id); - arm->attr_len = htons (msg_extra_len); - GNUNET_CRYPTO_ecdsa_key_get_public (zone, - &arm->identity); - data_tmp = (char *) &arm[1]; - GNUNET_memcpy (data_tmp, - attr_ser, - msg_extra_len); - GNUNET_MQ_send (ai->client->mq, env); - GNUNET_free (attr_ser); - GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); - ai->abe_key = NULL; -} - - -void -iterate_after_abe_bootstrap (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key) -{ - struct AttributeIterator *ai = cls; - ai->abe_key = abe_key; - ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - &ai->identity, - &attr_iter_error, - ai, - &attr_iter_cb, - ai, - &attr_iter_finished, - ai); -} - - -static void -iterate_next_after_abe_bootstrap (void *cls, - struct GNUNET_ABE_AbeMasterKey *abe_key) -{ - struct AttributeIterator *ai = cls; - ai->abe_key = abe_key; - GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, - 1); -} - - - -static void -handle_iteration_start (void *cls, - const struct AttributeIterationStartMessage *ais_msg) -{ - struct IdpClient *idp = cls; - struct AttributeIterator *ai; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received ATTRIBUTE_ITERATION_START message\n"); - ai = GNUNET_new (struct AttributeIterator); - ai->request_id = ntohl (ais_msg->id); - ai->client = idp; - ai->identity = ais_msg->identity; - - GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, - idp->attr_iter_tail, - ai); - bootstrap_abe (&ai->identity, &iterate_after_abe_bootstrap, ai, GNUNET_NO); - GNUNET_SERVICE_client_continue (idp->client); -} - - -static void -handle_iteration_stop (void *cls, - const struct AttributeIterationStopMessage *ais_msg) -{ - struct IdpClient *idp = cls; - struct AttributeIterator *ai; - uint32_t rid; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' message\n", - "ATTRIBUTE_ITERATION_STOP"); - rid = ntohl (ais_msg->id); - for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next) - if (ai->request_id == rid) - break; - if (NULL == ai) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (idp->client); - return; - } - GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, - idp->attr_iter_tail, - ai); - GNUNET_free (ai); - GNUNET_SERVICE_client_continue (idp->client); -} - - -static void -handle_iteration_next (void *cls, - const struct AttributeIterationNextMessage *ais_msg) -{ - struct IdpClient *idp = cls; - struct AttributeIterator *ai; - uint32_t rid; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received ATTRIBUTE_ITERATION_NEXT message\n"); - rid = ntohl (ais_msg->id); - for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next) - if (ai->request_id == rid) - break; - if (NULL == ai) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (idp->client); - return; - } - bootstrap_abe (&ai->identity, - &iterate_next_after_abe_bootstrap, - ai, - GNUNET_NO); - GNUNET_SERVICE_client_continue (idp->client); -} - -/** - * Ticket iteration processor result - */ -enum ZoneIterationResult -{ - /** - * Iteration start. - */ - IT_START = 0, - - /** - * Found tickets, - * Continue to iterate with next iteration_next call - */ - IT_SUCCESS_MORE_AVAILABLE = 1, - - /** - * Iteration complete - */ - IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2 -}; - - -/** - * Context for ticket iteration - */ -struct TicketIterationProcResult -{ - /** - * The ticket iteration handle - */ - struct TicketIteration *ti; - - /** - * Iteration result: iteration done? - * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but - * we got one for now and have sent it to the client - * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results, - * #IT_START: if we are still trying to find a result. - */ - int res_iteration_finished; - -}; - -static void -cleanup_ticket_iter_handle (struct TicketIteration *ti) -{ - GNUNET_free (ti); -} - -/** - * Process ticket from database - * - * @param cls struct TicketIterationProcResult - * @param ticket the ticket - * @param attrs the attributes - */ -static void -ticket_iterate_proc (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct TicketIterationProcResult *proc = cls; - - if (NULL == ticket) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Iteration done\n"); - proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; - return; - } - proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE; - send_ticket_result (proc->ti->client, - proc->ti->r_id, - ticket, - attrs); - -} - -/** - * Perform ticket iteration step - * - * @param ti ticket iterator to process - */ -static void -run_ticket_iteration_round (struct TicketIteration *ti) -{ - struct TicketIterationProcResult proc; - struct GNUNET_MQ_Envelope *env; - struct TicketResultMessage *trm; - int ret; - - memset (&proc, 0, sizeof (proc)); - proc.ti = ti; - proc.res_iteration_finished = IT_START; - while (IT_START == proc.res_iteration_finished) - { - if (GNUNET_SYSERR == - (ret = TKT_database->iterate_tickets (TKT_database->cls, - &ti->identity, - ti->is_audience, - ti->offset, - &ticket_iterate_proc, - &proc))) - { - GNUNET_break (0); - break; - } - if (GNUNET_NO == ret) - proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; - ti->offset++; - } - if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "More results available\n"); - return; /* more later */ - } - /* send empty response to indicate end of list */ - env = GNUNET_MQ_msg (trm, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT); - trm->id = htonl (ti->r_id); - GNUNET_MQ_send (ti->client->mq, - env); - GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head, - ti->client->ticket_iter_tail, - ti); - cleanup_ticket_iter_handle (ti); -} - -static void -handle_ticket_iteration_start (void *cls, - const struct TicketIterationStartMessage *tis_msg) -{ - struct IdpClient *client = cls; - struct TicketIteration *ti; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received TICKET_ITERATION_START message\n"); - ti = GNUNET_new (struct TicketIteration); - ti->r_id = ntohl (tis_msg->id); - ti->offset = 0; - ti->client = client; - ti->identity = tis_msg->identity; - ti->is_audience = ntohl (tis_msg->is_audience); - - GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head, - client->ticket_iter_tail, - ti); - run_ticket_iteration_round (ti); - GNUNET_SERVICE_client_continue (client->client); -} - - -static void -handle_ticket_iteration_stop (void *cls, - const struct TicketIterationStopMessage *tis_msg) -{ - struct IdpClient *client = cls; - struct TicketIteration *ti; - uint32_t rid; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' message\n", - "TICKET_ITERATION_STOP"); - rid = ntohl (tis_msg->id); - for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) - if (ti->r_id == rid) - break; - if (NULL == ti) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client->client); - return; - } - GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head, - client->ticket_iter_tail, - ti); - cleanup_ticket_iter_handle (ti); - GNUNET_SERVICE_client_continue (client->client); -} - - -static void -handle_ticket_iteration_next (void *cls, - const struct TicketIterationNextMessage *tis_msg) -{ - struct IdpClient *client = cls; - struct TicketIteration *ti; - uint32_t rid; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received TICKET_ITERATION_NEXT message\n"); - rid = ntohl (tis_msg->id); - for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) - if (ti->r_id == rid) - break; - if (NULL == ti) - { - GNUNET_break (0); - GNUNET_SERVICE_client_drop (client->client); - return; - } - run_ticket_iteration_round (ti); - GNUNET_SERVICE_client_continue (client->client); -} - - - - -/** - * Main function that will be run - * - * @param cls closure - * @param c the configuration used - * @param server the service handle - */ -static void -run (void *cls, - const struct GNUNET_CONFIGURATION_Handle *c, - struct GNUNET_SERVICE_Handle *server) -{ - char *database; - cfg = c; - - stats = GNUNET_STATISTICS_create ("identity-provider", cfg); - - //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"); - } - - gns_handle = GNUNET_GNS_connect (cfg); - if (NULL == gns_handle) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns"); - } - credential_handle = GNUNET_CREDENTIAL_connect (cfg); - if (NULL == credential_handle) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential"); - } - identity_handle = GNUNET_IDENTITY_connect (cfg, - NULL, - NULL); - /* Loading DB plugin */ - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "identity-provider", - "database", - &database)) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No database backend configured\n"); - GNUNET_asprintf (&db_lib_name, - "libgnunet_plugin_identity_provider_%s", - database); - TKT_database = GNUNET_PLUGIN_load (db_lib_name, - (void *) cfg); - GNUNET_free (database); - if (NULL == TKT_database) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not load database backend `%s'\n", - db_lib_name); - GNUNET_SCHEDULER_shutdown (); - return; - } - - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_time (cfg, - "identity-provider", - "TOKEN_EXPIRATION_INTERVAL", - &token_expiration_interval)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Time window for zone iteration: %s\n", - GNUNET_STRINGS_relative_time_to_string (token_expiration_interval, - GNUNET_YES)); - } else { - token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL; - } - - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); -} - -/** - * Called whenever a client is disconnected. - * - * @param cls closure - * @param client identification of the client - * @param app_ctx @a client - */ -static void -client_disconnect_cb (void *cls, - struct GNUNET_SERVICE_Client *client, - void *app_ctx) -{ - struct IdpClient *idp = app_ctx; - struct AttributeIterator *ai; - struct TicketIteration *ti; - struct TicketRevocationHandle *rh; - struct TicketIssueHandle *iss; - struct ConsumeTicketHandle *ct; - struct AttributeStoreHandle *as; - - //TODO other operations - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client %p disconnected\n", - client); - - while (NULL != (iss = idp->issue_op_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, - idp->issue_op_tail, - iss); - cleanup_ticket_issue_handle (iss); - } - while (NULL != (ct = idp->consume_op_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->consume_op_head, - idp->consume_op_tail, - ct); - cleanup_consume_ticket_handle (ct); - } - while (NULL != (as = idp->store_op_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->store_op_head, - idp->store_op_tail, - as); - cleanup_as_handle (as); - } - - while (NULL != (ai = idp->attr_iter_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, - idp->attr_iter_tail, - ai); - cleanup_attribute_iter_handle (ai); - } - while (NULL != (rh = idp->revoke_op_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, - idp->revoke_op_tail, - rh); - cleanup_revoke_ticket_handle (rh); - } - while (NULL != (ti = idp->ticket_iter_head)) - { - GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head, - idp->ticket_iter_tail, - ti); - cleanup_ticket_iter_handle (ti); - } - GNUNET_free (idp); -} - - -/** - * Add a client to our list of active clients. - * - * @param cls NULL - * @param client client to add - * @param mq message queue for @a client - * @return internal namestore client structure for this client - */ -static void * -client_connect_cb (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - struct IdpClient *idp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Client %p connected\n", - client); - idp = GNUNET_new (struct IdpClient); - idp->client = client; - idp->mq = mq; - return idp; -} - - - -/** - * Define "main" method using service macro. - */ -GNUNET_SERVICE_MAIN -("identity-provider", - GNUNET_SERVICE_OPTION_NONE, - &run, - &client_connect_cb, - &client_disconnect_cb, - NULL, - GNUNET_MQ_hd_var_size (attribute_store_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE, - struct AttributeStoreMessage, - NULL), - GNUNET_MQ_hd_fixed_size (iteration_start, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START, - struct AttributeIterationStartMessage, - NULL), - GNUNET_MQ_hd_fixed_size (iteration_next, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT, - struct AttributeIterationNextMessage, - NULL), - GNUNET_MQ_hd_fixed_size (iteration_stop, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP, - struct AttributeIterationStopMessage, - NULL), - GNUNET_MQ_hd_var_size (issue_ticket_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET, - struct IssueTicketMessage, - NULL), - GNUNET_MQ_hd_var_size (consume_ticket_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET, - struct ConsumeTicketMessage, - NULL), - GNUNET_MQ_hd_fixed_size (ticket_iteration_start, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START, - struct TicketIterationStartMessage, - NULL), - GNUNET_MQ_hd_fixed_size (ticket_iteration_next, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT, - struct TicketIterationNextMessage, - NULL), - GNUNET_MQ_hd_fixed_size (ticket_iteration_stop, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP, - struct TicketIterationStopMessage, - NULL), - GNUNET_MQ_hd_var_size (revoke_ticket_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET, - struct RevokeTicketMessage, - NULL), - GNUNET_MQ_handler_end()); -/* end of gnunet-service-identity-provider.c */ diff --git a/src/identity-provider/identity-provider.conf b/src/identity-provider/identity-provider.conf deleted file mode 100644 index 99c0a50be..000000000 --- a/src/identity-provider/identity-provider.conf +++ /dev/null @@ -1,23 +0,0 @@ -[identity-provider] -START_ON_DEMAND = NO -RUN_PER_USER = YES -#PORT = 2108 -HOSTNAME = localhost -BINARY = gnunet-service-identity-provider -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; -UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-identity-provider.sock -UNIX_MATCH_UID = NO -UNIX_MATCH_GID = YES -TOKEN_EXPIRATION_INTERVAL = 30 m -DATABASE = sqlite - -[identity-rest-plugin] -#ADDRESS = https://identity.gnu:8000#/login -ADDRESS = https://reclaim.ui/#/login -PSW = secret -JWT_SECRET = secret -EXPIRATION_TIME = 3600 - -[identity-provider-sqlite] -FILENAME = $GNUNET_DATA_HOME/identity-provider/sqlite.db diff --git a/src/identity-provider/identity-token.conf b/src/identity-provider/identity-token.conf deleted file mode 100644 index f29f6cdf3..000000000 --- a/src/identity-provider/identity-token.conf +++ /dev/null @@ -1,2 +0,0 @@ -[identity-token] -BINARY=gnunet-service-identity-token diff --git a/src/identity-provider/identity_provider.h b/src/identity-provider/identity_provider.h deleted file mode 100644 index 6a4b7769f..000000000 --- a/src/identity-provider/identity_provider.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2016 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @author Martin Schanzenbach - * @file identity-provider/identity_provider.h - * - * @brief Common type definitions for the identity provider - * service and API. - */ -#ifndef IDENTITY_PROVIDER_H -#define IDENTITY_PROVIDER_H - -#include "gnunet_common.h" - - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Use to store an identity attribute - */ -struct AttributeStoreMessage -{ - /** - * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * The length of the attribute - */ - uint32_t attr_len GNUNET_PACKED; - - /** - * The expiration interval of the attribute - */ - uint64_t exp GNUNET_PACKED; - - /** - * Identity - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /* followed by the serialized attribute */ - -}; - -/** - * Attribute store response message - */ -struct AttributeStoreResultMessage -{ - /** - * Message header - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * #GNUNET_SYSERR on failure, #GNUNET_OK on success - */ - int32_t op_result GNUNET_PACKED; - -}; - -/** - * Attribute is returned from the idp. - */ -struct AttributeResultMessage -{ - /** - * Message header - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Length of serialized attribute data - */ - uint16_t attr_len GNUNET_PACKED; - - /** - * always zero (for alignment) - */ - uint16_t reserved GNUNET_PACKED; - - /** - * The public key of the identity. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity; - - /* followed by: - * serialized attribute data - */ -}; - - -/** - * Start a attribute iteration for the given identity - */ -struct AttributeIterationStartMessage -{ - /** - * Message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Identity. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - -}; - - -/** - * Ask for next result of attribute iteration for the given operation - */ -struct AttributeIterationNextMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - -}; - - -/** - * Stop attribute iteration for the given operation - */ -struct AttributeIterationStopMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - -}; - -/** - * Start a ticket iteration for the given identity - */ -struct TicketIterationStartMessage -{ - /** - * Message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Identity. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity; - - /** - * Identity is audience or issuer - */ - uint32_t is_audience GNUNET_PACKED; -}; - - -/** - * Ask for next result of ticket iteration for the given operation - */ -struct TicketIterationNextMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - -}; - - -/** - * Stop ticket iteration for the given operation - */ -struct TicketIterationStopMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - -}; - - - -/** - * Ticket issue message - */ -struct IssueTicketMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Identity. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * Requesting party. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey rp; - - /** - * length of serialized attribute list - */ - uint32_t attr_len GNUNET_PACKED; - - //Followed by a serialized attribute list -}; - -/** - * Ticket revoke message - */ -struct RevokeTicketMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Identity. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * length of serialized attribute list - */ - uint32_t attrs_len GNUNET_PACKED; - - //Followed by a ticket and serialized attribute list -}; - -/** - * Ticket revoke message - */ -struct RevokeTicketResultMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Revocation result - */ - uint32_t success GNUNET_PACKED; -}; - - -/** - * Ticket result message - */ -struct TicketResultMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - -}; - -/** - * Ticket consume message - */ -struct ConsumeTicketMessage -{ - /** - * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Identity. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - //Followed by a serialized ticket -}; - -/** - * Attribute list is returned from the idp. - */ -struct ConsumeTicketResultMessage -{ - /** - * Message header - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this request (for key collisions). - */ - uint32_t id GNUNET_PACKED; - - /** - * Length of serialized attribute data - */ - uint16_t attrs_len GNUNET_PACKED; - - /** - * always zero (for alignment) - */ - uint16_t reserved GNUNET_PACKED; - - /** - * The public key of the identity. - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity; - - /* followed by: - * serialized attributes data - */ -}; - - - -GNUNET_NETWORK_STRUCT_END - -#endif diff --git a/src/identity-provider/identity_provider_api.c b/src/identity-provider/identity_provider_api.c deleted file mode 100644 index 33efe726f..000000000 --- a/src/identity-provider/identity_provider_api.c +++ /dev/null @@ -1,1383 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2016 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @file identity-provider/identity_provider_api.c - * @brief api to interact with the identity provider service - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_mq_lib.h" -#include "gnunet_identity_provider_service.h" -#include "gnunet_identity_attribute_lib.h" -#include "identity_provider.h" - -#define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__) - - -/** - * Handle for an operation with the service. - */ -struct GNUNET_IDENTITY_PROVIDER_Operation -{ - - /** - * Main handle. - */ - struct GNUNET_IDENTITY_PROVIDER_Handle *h; - - /** - * We keep operations in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *next; - - /** - * We keep operations in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *prev; - - /** - * Message to send to the service. - * Allocated at the end of this struct. - */ - const struct GNUNET_MessageHeader *msg; - - /** - * Continuation to invoke after attribute store call - */ - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus as_cb; - - /** - * Attribute result callback - */ - GNUNET_IDENTITY_PROVIDER_AttributeResult ar_cb; - - /** - * Revocation result callback - */ - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus rvk_cb; - - /** - * Ticket result callback - */ - GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb; - - /** - * Envelope with the message for this queue entry. - */ - struct GNUNET_MQ_Envelope *env; - - /** - * request id - */ - uint32_t r_id; - - /** - * Closure for @e cont or @e cb. - */ - void *cls; - -}; - -/** - * Handle for a ticket iterator operation - */ -struct GNUNET_IDENTITY_PROVIDER_TicketIterator -{ - - /** - * Kept in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *next; - - /** - * Kept in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *prev; - - /** - * Main handle to access the idp. - */ - struct GNUNET_IDENTITY_PROVIDER_Handle *h; - - /** - * Function to call on completion. - */ - GNUNET_SCHEDULER_TaskCallback finish_cb; - - /** - * Closure for @e error_cb. - */ - void *finish_cb_cls; - - /** - * The continuation to call with the results - */ - GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb; - - /** - * Closure for @e tr_cb. - */ - void *cls; - - /** - * Function to call on errors. - */ - GNUNET_SCHEDULER_TaskCallback error_cb; - - /** - * Closure for @e error_cb. - */ - void *error_cb_cls; - - /** - * Envelope of the message to send to the service, if not yet - * sent. - */ - struct GNUNET_MQ_Envelope *env; - - /** - * The operation id this zone iteration operation has - */ - uint32_t r_id; - -}; - - -/** - * Handle for a attribute iterator operation - */ -struct GNUNET_IDENTITY_PROVIDER_AttributeIterator -{ - - /** - * Kept in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *next; - - /** - * Kept in a DLL. - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *prev; - - /** - * Main handle to access the idp. - */ - struct GNUNET_IDENTITY_PROVIDER_Handle *h; - - /** - * Function to call on completion. - */ - GNUNET_SCHEDULER_TaskCallback finish_cb; - - /** - * Closure for @e error_cb. - */ - void *finish_cb_cls; - - /** - * The continuation to call with the results - */ - GNUNET_IDENTITY_PROVIDER_AttributeResult proc; - - /** - * Closure for @e proc. - */ - void *proc_cls; - - /** - * Function to call on errors. - */ - GNUNET_SCHEDULER_TaskCallback error_cb; - - /** - * Closure for @e error_cb. - */ - void *error_cb_cls; - - /** - * Envelope of the message to send to the service, if not yet - * sent. - */ - struct GNUNET_MQ_Envelope *env; - - /** - * Private key of the zone. - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - - /** - * The operation id this zone iteration operation has - */ - uint32_t r_id; - -}; - - -/** - * Handle for the service. - */ -struct GNUNET_IDENTITY_PROVIDER_Handle -{ - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Socket (if available). - */ - struct GNUNET_CLIENT_Connection *client; - - /** - * Closure for 'cb'. - */ - void *cb_cls; - - /** - * Head of active operations. - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *op_head; - - /** - * Tail of active operations. - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *op_tail; - - /** - * Head of active iterations - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_head; - - /** - * Tail of active iterations - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_tail; - - /** - * Head of active iterations - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_head; - - /** - * Tail of active iterations - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_tail; - - - /** - * Currently pending transmission request, or NULL for none. - */ - struct GNUNET_CLIENT_TransmitHandle *th; - - /** - * Task doing exponential back-off trying to reconnect. - */ - struct GNUNET_SCHEDULER_Task * reconnect_task; - - /** - * Time for next connect retry. - */ - struct GNUNET_TIME_Relative reconnect_backoff; - - /** - * Connection to service (if available). - */ - struct GNUNET_MQ_Handle *mq; - - /** - * Request Id generator. Incremented by one for each request. - */ - uint32_t r_id_gen; - - /** - * Are we polling for incoming messages right now? - */ - int in_receive; - -}; - -/** - * Try again to connect to the service. - * - * @param h handle to the identity provider service. - */ -static void -reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h); - -/** - * Reconnect - * - * @param cls the handle - */ -static void -reconnect_task (void *cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls; - - handle->reconnect_task = NULL; - reconnect (handle); -} - - -/** - * Disconnect from service and then reconnect. - * - * @param handle our service - */ -static void -force_reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle) -{ - GNUNET_MQ_destroy (handle->mq); - handle->mq = NULL; - handle->reconnect_backoff - = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff); - handle->reconnect_task - = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff, - &reconnect_task, - handle); -} - -/** - * Free @a it. - * - * @param it entry to free - */ -static void -free_it (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; - - GNUNET_CONTAINER_DLL_remove (h->it_head, - h->it_tail, - it); - if (NULL != it->env) - GNUNET_MQ_discard (it->env); - GNUNET_free (it); -} - -static void -free_op (struct GNUNET_IDENTITY_PROVIDER_Operation* op) -{ - if (NULL == op) - return; - if (NULL != op->env) - GNUNET_MQ_discard (op->env); - GNUNET_free(op); -} - - -/** - * Generic error handler, called with the appropriate error code and - * the same closure specified at the creation of the message queue. - * Not every message queue implementation supports an error handler. - * - * @param cls closure with the `struct GNUNET_GNS_Handle *` - * @param error error code - */ -static void -mq_error_handler (void *cls, - enum GNUNET_MQ_Error error) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls; - force_reconnect (handle); -} - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE - * - * @param cls - * @param msg the message we received - */ -static void -handle_attribute_store_response (void *cls, - const struct AttributeStoreResultMessage *msg) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - uint32_t r_id = ntohl (msg->id); - int res; - const char *emsg; - - for (op = h->op_head; NULL != op; op = op->next) - if (op->r_id == r_id) - break; - if (NULL == op) - return; - - res = ntohl (msg->op_result); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received ATTRIBUTE_STORE_RESPONSE with result %d\n", - res); - - /* TODO: add actual error message to response... */ - if (GNUNET_SYSERR == res) - emsg = _("failed to store record\n"); - else - emsg = NULL; - if (NULL != op->as_cb) - op->as_cb (op->cls, - res, - emsg); - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - op); - free_op (op); - -} - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT - * - * @param cls - * @param msg the message we received - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -check_consume_ticket_result (void *cls, - const struct ConsumeTicketResultMessage *msg) -{ - size_t msg_len; - size_t attrs_len; - - msg_len = ntohs (msg->header.size); - attrs_len = ntohs (msg->attrs_len); - if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT - * - * @param cls - * @param msg the message we received - */ -static void -handle_consume_ticket_result (void *cls, - const struct ConsumeTicketResultMessage *msg) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - size_t attrs_len; - uint32_t r_id = ntohl (msg->id); - - attrs_len = ntohs (msg->attrs_len); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Processing attribute result.\n"); - - - for (op = h->op_head; NULL != op; op = op->next) - if (op->r_id == r_id) - break; - if (NULL == op) - return; - - { - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&msg[1], - attrs_len); - if (NULL != op->ar_cb) - { - if (NULL == attrs) - { - op->ar_cb (op->cls, - &msg->identity, - NULL); - } - else - { - for (le = attrs->list_head; NULL != le; le = le->next) - op->ar_cb (op->cls, - &msg->identity, - le->claim); - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs); - } - } - if (NULL != op) - { - op->ar_cb (op->cls, - NULL, - NULL); - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - op); - free_op (op); - } - return; - } - GNUNET_assert (0); -} - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT - * - * @param cls - * @param msg the message we received - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -check_attribute_result (void *cls, - const struct AttributeResultMessage *msg) -{ - size_t msg_len; - size_t attr_len; - - msg_len = ntohs (msg->header.size); - attr_len = ntohs (msg->attr_len); - if (msg_len != sizeof (struct AttributeResultMessage) + attr_len) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT - * - * @param cls - * @param msg the message we received - */ -static void -handle_attribute_result (void *cls, - const struct AttributeResultMessage *msg) -{ - static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy; - struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - size_t attr_len; - uint32_t r_id = ntohl (msg->id); - - attr_len = ntohs (msg->attr_len); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Processing attribute result.\n"); - - - for (it = h->it_head; NULL != it; it = it->next) - if (it->r_id == r_id) - break; - for (op = h->op_head; NULL != op; op = op->next) - if (op->r_id == r_id) - break; - if ((NULL == it) && (NULL == op)) - return; - - if ( (0 == (memcmp (&msg->identity, - &identity_dummy, - sizeof (identity_dummy)))) ) - { - if ((NULL == it) && (NULL == op)) - { - GNUNET_break (0); - force_reconnect (h); - return; - } - if (NULL != it) - { - if (NULL != it->finish_cb) - it->finish_cb (it->finish_cb_cls); - free_it (it); - } - if (NULL != op) - { - if (NULL != op->ar_cb) - op->ar_cb (op->cls, - NULL, - NULL); - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - op); - free_op (op); - - } - return; - } - - { - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; - attr = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&msg[1], - attr_len); - if (NULL != it) - { - if (NULL != it->proc) - it->proc (it->proc_cls, - &msg->identity, - attr); - } else if (NULL != op) - { - if (NULL != op->ar_cb) - op->ar_cb (op->cls, - &msg->identity, - attr); - - } - GNUNET_free (attr); - return; - } - GNUNET_assert (0); -} - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT - * - * @param cls - * @param msg the message we received - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - */ -static int -check_ticket_result (void *cls, - const struct TicketResultMessage *msg) -{ - size_t msg_len; - - msg_len = ntohs (msg->header.size); - if (msg_len < sizeof (struct TicketResultMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT - * - * @param cls - * @param msg the message we received - */ -static void -handle_ticket_result (void *cls, - const struct TicketResultMessage *msg) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; - uint32_t r_id = ntohl (msg->id); - size_t msg_len; - - for (op = handle->op_head; NULL != op; op = op->next) - if (op->r_id == r_id) - break; - for (it = handle->ticket_it_head; NULL != it; it = it->next) - if (it->r_id == r_id) - break; - if ((NULL == op) && (NULL == it)) - return; - msg_len = ntohs (msg->header.size); - if (NULL != op) - { - GNUNET_CONTAINER_DLL_remove (handle->op_head, - handle->op_tail, - op); - if (msg_len == sizeof (struct TicketResultMessage)) - { - if (NULL != op->tr_cb) - op->tr_cb (op->cls, NULL); - } else { - ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1]; - if (NULL != op->tr_cb) - op->tr_cb (op->cls, ticket); - } - free_op (op); - return; - } else if (NULL != it) { - if (msg_len == sizeof (struct TicketResultMessage)) - { - if (NULL != it->tr_cb) - GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head, - handle->ticket_it_tail, - it); - it->finish_cb (it->finish_cb_cls); - GNUNET_free (it); - } else { - ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1]; - if (NULL != it->tr_cb) - it->tr_cb (it->cls, ticket); - } - return; - } - GNUNET_break (0); -} - - -/** - * Handle an incoming message of type - * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT - * - * @param cls - * @param msg the message we received - */ -static void -handle_revoke_ticket_result (void *cls, - const struct RevokeTicketResultMessage *msg) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - uint32_t r_id = ntohl (msg->id); - int32_t success; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Processing revocation result.\n"); - - - for (op = h->op_head; NULL != op; op = op->next) - if (op->r_id == r_id) - break; - if (NULL == op) - return; - success = ntohl (msg->success); - { - if (NULL != op->rvk_cb) - { - op->rvk_cb (op->cls, - success, - NULL); - } - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - op); - free_op (op); - return; - } - GNUNET_assert (0); -} - - - -/** - * Try again to connect to the service. - * - * @param h handle to the identity provider service. - */ -static void -reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h) -{ - struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_fixed_size (attribute_store_response, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE, - struct AttributeStoreResultMessage, - h), - GNUNET_MQ_hd_var_size (attribute_result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT, - struct AttributeResultMessage, - h), - GNUNET_MQ_hd_var_size (ticket_result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT, - struct TicketResultMessage, - h), - GNUNET_MQ_hd_var_size (consume_ticket_result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT, - struct ConsumeTicketResultMessage, - h), - GNUNET_MQ_hd_fixed_size (revoke_ticket_result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT, - struct RevokeTicketResultMessage, - h), - GNUNET_MQ_handler_end () - }; - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - - GNUNET_assert (NULL == h->mq); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Connecting to identity provider service.\n"); - - h->mq = GNUNET_CLIENT_connect (h->cfg, - "identity-provider", - handlers, - &mq_error_handler, - h); - if (NULL == h->mq) - return; - for (op = h->op_head; NULL != op; op = op->next) - GNUNET_MQ_send_copy (h->mq, - op->env); -} - - -/** - * Connect to the identity provider service. - * - * @param cfg the configuration to use - * @return handle to use - */ -struct GNUNET_IDENTITY_PROVIDER_Handle * -GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h; - - h = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Handle); - h->cfg = cfg; - reconnect (h); - if (NULL == h->mq) - { - GNUNET_free (h); - return NULL; - } - return h; -} - - -/** - * Cancel an operation. Note that the operation MAY still - * be executed; this merely cancels the continuation; if the request - * was already transmitted, the service may still choose to complete - * the operation. - * - * @param op operation to cancel - */ -void -GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = op->h; - - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - op); - free_op (op); -} - - -/** - * Disconnect from service - * - * @param h handle to destroy - */ -void -GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h) -{ - GNUNET_assert (NULL != h); - if (NULL != h->mq) - { - GNUNET_MQ_destroy (h->mq); - h->mq = NULL; - } - if (NULL != h->reconnect_task) - { - GNUNET_SCHEDULER_cancel (h->reconnect_task); - h->reconnect_task = NULL; - } - GNUNET_assert (NULL == h->op_head); - GNUNET_free (h); -} - -/** - * Store an attribute. If the attribute is already present, - * it is replaced with the new attribute. - * - * @param h handle to the identity provider - * @param pkey private key of the identity - * @param attr the attribute value - * @param exp_interval the relative expiration interval for the attribute - * @param cont continuation to call when done - * @param cont_cls closure for @a cont - * @return handle to abort the request - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, - const struct GNUNET_TIME_Relative *exp_interval, - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont, - void *cont_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct AttributeStoreMessage *sam; - size_t attr_len; - - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = h; - op->as_cb = cont; - op->cls = cont_cls; - op->r_id = h->r_id_gen++; - GNUNET_CONTAINER_DLL_insert_tail (h->op_head, - h->op_tail, - op); - attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (attr); - op->env = GNUNET_MQ_msg_extra (sam, - attr_len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE); - sam->identity = *pkey; - sam->id = htonl (op->r_id); - sam->exp = GNUNET_htonll (exp_interval->rel_value_us); - - GNUNET_IDENTITY_ATTRIBUTE_serialize (attr, - (char*)&sam[1]); - - sam->attr_len = htons (attr_len); - if (NULL != h->mq) - GNUNET_MQ_send_copy (h->mq, - op->env); - return op; - -} - - -/** - * List all attributes for a local identity. - * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle` - * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and - * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once - * immediately, and then again after - * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked. - * - * On error (disconnect), @a error_cb will be invoked. - * On normal completion, @a finish_cb proc will be - * invoked. - * - * @param h handle to the idp - * @param identity identity to access - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each attribute; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_AttributeIterator * -GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_AttributeResult proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it; - struct GNUNET_MQ_Envelope *env; - struct AttributeIterationStartMessage *msg; - uint32_t rid; - - rid = h->r_id_gen++; - it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator); - it->h = h; - it->error_cb = error_cb; - it->error_cb_cls = error_cb_cls; - it->finish_cb = finish_cb; - it->finish_cb_cls = finish_cb_cls; - it->proc = proc; - it->proc_cls = proc_cls; - it->r_id = rid; - it->identity = *identity; - GNUNET_CONTAINER_DLL_insert_tail (h->it_head, - h->it_tail, - it); - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START); - msg->id = htonl (rid); - msg->identity = *identity; - if (NULL == h->mq) - it->env = env; - else - GNUNET_MQ_send (h->mq, - env); - return it; -} - - -/** - * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start - * for the next record. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; - struct AttributeIterationNextMessage *msg; - struct GNUNET_MQ_Envelope *env; - - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT); - msg->id = htonl (it->r_id); - GNUNET_MQ_send (h->mq, - env); -} - - -/** - * Stops iteration and releases the idp handle for further calls. Must - * be called on any iteration that has not yet completed prior to calling - * #GNUNET_IDENTITY_PROVIDER_disconnect. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; - struct GNUNET_MQ_Envelope *env; - struct AttributeIterationStopMessage *msg; - - if (NULL != h->mq) - { - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP); - msg->id = htonl (it->r_id); - GNUNET_MQ_send (h->mq, - env); - } - free_it (it); -} - - -/** TODO - * Issues a ticket to another identity. The identity may use - * @GNUNET_IDENTITY_PROVIDER_authorization_ticket_consume to consume the ticket - * and retrieve the attributes specified in the AttributeList. - * - * @param h the identity provider to use - * @param iss the issuing identity - * @param rp the subject of the ticket (the relying party) - * @param attrs the attributes that the relying party is given access to - * @param cb the callback - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, - const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - GNUNET_IDENTITY_PROVIDER_TicketCallback cb, - void *cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct IssueTicketMessage *tim; - size_t attr_len; - - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = h; - op->tr_cb = cb; - op->cls = cb_cls; - op->r_id = h->r_id_gen++; - GNUNET_CONTAINER_DLL_insert_tail (h->op_head, - h->op_tail, - op); - attr_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs); - op->env = GNUNET_MQ_msg_extra (tim, - attr_len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET); - tim->identity = *iss; - tim->rp = *rp; - tim->id = htonl (op->r_id); - - GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs, - (char*)&tim[1]); - - tim->attr_len = htons (attr_len); - if (NULL != h->mq) - GNUNET_MQ_send_copy (h->mq, - op->env); - return op; -} - -/** - * Consumes an issued ticket. The ticket is persisted - * and used to retrieve identity information from the issuer - * - * @param h the identity provider to use - * @param identity the identity that is the subject of the issued ticket (the relying party) - * @param ticket the issued ticket to consume - * @param cb the callback to call - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_AttributeResult cb, - void *cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct ConsumeTicketMessage *ctm; - - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = h; - op->ar_cb = cb; - op->cls = cb_cls; - op->r_id = h->r_id_gen++; - GNUNET_CONTAINER_DLL_insert_tail (h->op_head, - h->op_tail, - op); - op->env = GNUNET_MQ_msg_extra (ctm, - sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket), - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET); - ctm->identity = *identity; - ctm->id = htonl (op->r_id); - - GNUNET_memcpy ((char*)&ctm[1], - ticket, - sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket)); - - if (NULL != h->mq) - GNUNET_MQ_send_copy (h->mq, - op->env); - return op; - -} - - -/** - * Lists all tickets that have been issued to remote - * identites (relying parties) - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each ticket; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_TicketIterator * -GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_TicketCallback proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; - struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; - struct GNUNET_MQ_Envelope *env; - struct TicketIterationStartMessage *msg; - uint32_t rid; - - GNUNET_CRYPTO_ecdsa_key_get_public (identity, - &identity_pub); - rid = h->r_id_gen++; - it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator); - it->h = h; - it->error_cb = error_cb; - it->error_cb_cls = error_cb_cls; - it->finish_cb = finish_cb; - it->finish_cb_cls = finish_cb_cls; - it->tr_cb = proc; - it->cls = proc_cls; - it->r_id = rid; - GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, - h->ticket_it_tail, - it); - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START); - msg->id = htonl (rid); - msg->identity = identity_pub; - msg->is_audience = htonl (GNUNET_NO); - if (NULL == h->mq) - it->env = env; - else - GNUNET_MQ_send (h->mq, - env); - return it; - -} - - -/** - * Lists all tickets that have been issued to remote - * identites (relying parties) - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each ticket; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_TicketIterator * -GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_TicketCallback proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; - struct GNUNET_MQ_Envelope *env; - struct TicketIterationStartMessage *msg; - uint32_t rid; - - rid = h->r_id_gen++; - it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator); - it->h = h; - it->error_cb = error_cb; - it->error_cb_cls = error_cb_cls; - it->finish_cb = finish_cb; - it->finish_cb_cls = finish_cb_cls; - it->tr_cb = proc; - it->cls = proc_cls; - it->r_id = rid; - GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, - h->ticket_it_tail, - it); - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START); - msg->id = htonl (rid); - msg->identity = *identity; - msg->is_audience = htonl (GNUNET_YES); - if (NULL == h->mq) - it->env = env; - else - GNUNET_MQ_send (h->mq, - env); - return it; - - -} - -/** - * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start - * for the next record. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; - struct TicketIterationNextMessage *msg; - struct GNUNET_MQ_Envelope *env; - - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT); - msg->id = htonl (it->r_id); - GNUNET_MQ_send (h->mq, - env); -} - - -/** - * Stops iteration and releases the idp handle for further calls. Must - * be called on any iteration that has not yet completed prior to calling - * #GNUNET_IDENTITY_PROVIDER_disconnect. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it) -{ - struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; - struct GNUNET_MQ_Envelope *env; - struct TicketIterationStopMessage *msg; - - if (NULL != h->mq) - { - env = GNUNET_MQ_msg (msg, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP); - msg->id = htonl (it->r_id); - GNUNET_MQ_send (h->mq, - env); - } - GNUNET_free (it); -} - -/** - * Revoked an issued ticket. The relying party will be unable to retrieve - * updated attributes. - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param ticket the ticket to revoke - * @param cb the callback - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb, - void *cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct RevokeTicketMessage *msg; - uint32_t rid; - - rid = h->r_id_gen++; - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = h; - op->rvk_cb = cb; - op->cls = cb_cls; - op->r_id = rid; - GNUNET_CONTAINER_DLL_insert_tail (h->op_head, - h->op_tail, - op); - op->env = GNUNET_MQ_msg_extra (msg, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket), - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET); - msg->id = htonl (rid); - msg->identity = *identity; - GNUNET_memcpy (&msg[1], - ticket, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - if (NULL != h->mq) { - GNUNET_MQ_send (h->mq, - op->env); - op->env = NULL; - } - return op; -} - - - -/* end of identity_provider_api.c */ diff --git a/src/identity-provider/jwt.c b/src/identity-provider/jwt.c deleted file mode 100644 index 7ac4f0025..000000000 --- a/src/identity-provider/jwt.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -/** - * @file identity-provider/jwt.c - * @brief helper library for JSON-Web-Tokens - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" -#include "gnunet_identity_attribute_lib.h" -#include - - -#define JWT_ALG "alg" - -/* Use 512bit HMAC */ -#define JWT_ALG_VALUE "HS512" - -#define JWT_TYP "typ" - -#define JWT_TYP_VALUE "jwt" - -#define SERVER_ADDRESS "https://reclaim.id/api/openid/userinfo" - -static char* -create_jwt_header(void) -{ - json_t *root; - char *json_str; - - root = json_object (); - json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); - json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); - - json_str = json_dumps (root, JSON_INDENT(1)); - json_decref (root); - return json_str; -} - -/** - * Create a JWT from attributes - * - * @param aud_key the public of the subject - * @param attrs the attribute list - * @param priv_key the key used to sign the JWT - * @return a new base64-encoded JWT string. - */ -char* -jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - const struct GNUNET_CRYPTO_AuthKey *priv_key) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - struct GNUNET_HashCode signature; - char* audience; - char* subject; - char* header; - char* padding; - char* body_str; - char* result; - char* header_base64; - char* body_base64; - char* signature_target; - char* signature_base64; - char* attr_val_str; - json_t* body; - - //exp REQUIRED time expired from config - //iat REQUIRED time now - //auth_time only if max_age - //nonce only if nonce - // OPTIONAL acr,amr,azp - subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - header = create_jwt_header (); - body = json_object (); - - //iss REQUIRED case sensitive server uri with https - //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) - json_object_set_new (body, - "iss", json_string (SERVER_ADDRESS)); - //sub REQUIRED public key identity, not exceed 255 ASCII length - json_object_set_new (body, - "sub", json_string (subject)); - //aud REQUIRED public key client_id must be there - json_object_set_new (body, - "aud", json_string (audience)); - for (le = attrs->list_head; NULL != le; le = le->next) - { - attr_val_str = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (le->claim->type, - le->claim->data, - le->claim->data_size); - json_object_set_new (body, - le->claim->name, - json_string (attr_val_str)); - GNUNET_free (attr_val_str); - } - body_str = json_dumps (body, JSON_INDENT(0)); - json_decref (body); - - GNUNET_STRINGS_base64_encode (header, - strlen (header), - &header_base64); - //Remove GNUNET padding of base64 - padding = strtok(header_base64, "="); - while (NULL != padding) - padding = strtok(NULL, "="); - - GNUNET_STRINGS_base64_encode (body_str, - strlen (body_str), - &body_base64); - - //Remove GNUNET padding of base64 - padding = strtok(body_base64, "="); - while (NULL != padding) - padding = strtok(NULL, "="); - - GNUNET_free (subject); - GNUNET_free (audience); - - /** - * Creating the JWT signature. This might not be - * standards compliant, check. - */ - GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64); - GNUNET_CRYPTO_hmac (priv_key, signature_target, strlen (signature_target), &signature); - GNUNET_STRINGS_base64_encode ((const char*)&signature, - sizeof (struct GNUNET_HashCode), - &signature_base64); - GNUNET_asprintf (&result, "%s.%s.%s", - header_base64, body_base64, signature_base64); - - GNUNET_free (signature_target); - GNUNET_free (header); - GNUNET_free (body_str); - GNUNET_free (signature_base64); - GNUNET_free (body_base64); - GNUNET_free (header_base64); - return result; -} diff --git a/src/identity-provider/jwt.h b/src/identity-provider/jwt.h deleted file mode 100644 index 80b6caa33..000000000 --- a/src/identity-provider/jwt.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef JWT_H -#define JWT_H - -char* -jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - const struct GNUNET_CRYPTO_AuthKey *priv_key); - -#endif diff --git a/src/identity-provider/plugin_gnsrecord_identity_provider.c b/src/identity-provider/plugin_gnsrecord_identity_provider.c deleted file mode 100644 index f0dc563dc..000000000 --- a/src/identity-provider/plugin_gnsrecord_identity_provider.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2013, 2014 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @file identity-provider/plugin_gnsrecord_identity_provider.c - * @brief gnsrecord plugin to provide the API for identity records - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_gnsrecord_lib.h" -#include "gnunet_gnsrecord_plugin.h" - - -/** - * Convert the 'value' of a record to a string. - * - * @param cls closure, unused - * @param type type of the record - * @param data value in binary encoding - * @param data_size number of bytes in @a data - * @return NULL on error, otherwise human-readable representation of the value - */ -static char * -value_to_string (void *cls, - uint32_t type, - 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: - return GNUNET_STRINGS_data_to_string_alloc (data, data_size); - case GNUNET_GNSRECORD_TYPE_ID_TOKEN: //DEPRECATED - return GNUNET_strndup (data, data_size); - case GNUNET_GNSRECORD_TYPE_ABE_KEY: - case GNUNET_GNSRECORD_TYPE_ABE_MASTER: - return GNUNET_STRINGS_data_to_string_alloc (data, data_size); - case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: //DEPRECATED - 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); - GNUNET_free (aud_str); - GNUNET_free (ecdhe_str); - return result; - - default: - return NULL; - } -} - - -/** - * Convert human-readable version of a 'value' of a record to the binary - * representation. - * - * @param cls closure, unused - * @param type type of the record - * @param s human-readable string - * @param data set to value in binary encoding (will be allocated) - * @param data_size set to number of bytes in @a data - * @return #GNUNET_OK on success - */ -static int -string_to_value (void *cls, - uint32_t type, - const char *s, - 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) - { - case GNUNET_GNSRECORD_TYPE_ID_ATTR: - return GNUNET_STRINGS_string_to_data (s, - strlen (s), - *data, - *data_size); - case GNUNET_GNSRECORD_TYPE_ID_TOKEN: - *data = GNUNET_strdup (s); - *data_size = strlen (s); - return GNUNET_OK; - case GNUNET_GNSRECORD_TYPE_ABE_KEY: - case GNUNET_GNSRECORD_TYPE_ABE_MASTER: - return GNUNET_STRINGS_string_to_data (s, - strlen (s), - *data, - *data_size); - 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); - GNUNET_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 }, - { "ABE_KEY", GNUNET_GNSRECORD_TYPE_ABE_KEY }, - { "ABE_MASTER", GNUNET_GNSRECORD_TYPE_ABE_MASTER }, - { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA }, - { NULL, UINT32_MAX } -}; - - -/** - * Convert a type name (i.e. "AAAA") to the corresponding number. - * - * @param cls closure, unused - * @param dns_typename name to convert - * @return corresponding number, UINT32_MAX on error - */ -static uint32_t -typename_to_number (void *cls, - const char *dns_typename) -{ - unsigned int i; - - i=0; - while ( (NULL != name_map[i].name) && - (0 != strcasecmp (dns_typename, name_map[i].name)) ) - i++; - return name_map[i].number; -} - - -/** - * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") - * - * @param cls closure, unused - * @param type number of a type to convert - * @return corresponding typestring, NULL on error - */ -static const char * -number_to_typename (void *cls, - uint32_t type) -{ - unsigned int i; - - i=0; - while ( (NULL != name_map[i].name) && - (type != name_map[i].number) ) - i++; - return name_map[i].name; -} - - -/** - * Entry point for the plugin. - * - * @param cls NULL - * @return the exported block API - */ -void * -libgnunet_plugin_gnsrecord_identity_provider_init (void *cls) -{ - struct GNUNET_GNSRECORD_PluginFunctions *api; - - api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions); - api->value_to_string = &value_to_string; - api->string_to_value = &string_to_value; - api->typename_to_number = &typename_to_number; - api->number_to_typename = &number_to_typename; - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the return value from #libgnunet_plugin_block_test_init - * @return NULL - */ -void * -libgnunet_plugin_gnsrecord_identity_provider_done (void *cls) -{ - struct GNUNET_GNSRECORD_PluginFunctions *api = cls; - - GNUNET_free (api); - return NULL; -} - -/* end of plugin_gnsrecord_dns.c */ diff --git a/src/identity-provider/plugin_identity_provider_sqlite.c b/src/identity-provider/plugin_identity_provider_sqlite.c deleted file mode 100644 index f2a8b7b54..000000000 --- a/src/identity-provider/plugin_identity_provider_sqlite.c +++ /dev/null @@ -1,734 +0,0 @@ - /* - * This file is part of GNUnet - * Copyright (C) 2009-2017 GNUnet e.V. - * - * GNUnet is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, - * 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 - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -/** - * @file identity-provider/plugin_identity_provider_sqlite.c - * @brief sqlite-based idp backend - * @author Martin Schanzenbach - */ - -#include "platform.h" -#include "gnunet_identity_provider_service.h" -#include "gnunet_identity_provider_plugin.h" -#include "gnunet_identity_attribute_lib.h" -#include "gnunet_sq_lib.h" -#include - -/** - * After how many ms "busy" should a DB operation fail for good? A - * low value makes sure that we are more responsive to requests - * (especially PUTs). A high value guarantees a higher success rate - * (SELECTs in iterate can take several seconds despite LIMIT=1). - * - * The default value of 1s should ensure that users do not experience - * huge latencies while at the same time allowing operations to - * succeed with reasonable probability. - */ -#define BUSY_TIMEOUT_MS 1000 - - -/** - * Log an error message at log-level 'level' that indicates - * a failure of the command 'cmd' on file 'filename' - * with the message given by strerror(errno). - */ -#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "identity-provider", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) - -#define LOG(kind,...) GNUNET_log_from (kind, "identity-provider-sqlite", __VA_ARGS__) - - -/** - * Context for all functions in this plugin. - */ -struct Plugin -{ - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Database filename. - */ - char *fn; - - /** - * Native SQLite database handle. - */ - sqlite3 *dbh; - - /** - * Precompiled SQL to store ticket. - */ - sqlite3_stmt *store_ticket; - - /** - * Precompiled SQL to delete existing ticket. - */ - sqlite3_stmt *delete_ticket; - - /** - * Precompiled SQL to iterate tickets. - */ - sqlite3_stmt *iterate_tickets; - - /** - * Precompiled SQL to get ticket attributes. - */ - sqlite3_stmt *get_ticket_attrs; - - /** - * Precompiled SQL to iterate tickets by audience. - */ - sqlite3_stmt *iterate_tickets_by_audience; -}; - - -/** - * @brief Prepare a SQL statement - * - * @param dbh handle to the database - * @param zSql SQL statement, UTF-8 encoded - * @param ppStmt set to the prepared statement - * @return 0 on success - */ -static int -sq_prepare (sqlite3 *dbh, - const char *zSql, - sqlite3_stmt **ppStmt) -{ - char *dummy; - int result; - - result = - sqlite3_prepare_v2 (dbh, - zSql, - strlen (zSql), - ppStmt, - (const char **) &dummy); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Prepared `%s' / %p: %d\n", - zSql, - *ppStmt, - result); - return result; -} - -/** - * Create our database indices. - * - * @param dbh handle to the database - */ -static void -create_indices (sqlite3 * dbh) -{ - /* create indices */ - if ( (SQLITE_OK != - sqlite3_exec (dbh, - "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)", - NULL, NULL, NULL)) || - (SQLITE_OK != - sqlite3_exec (dbh, - "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)", - NULL, NULL, NULL)) ) - LOG (GNUNET_ERROR_TYPE_ERROR, - "Failed to create indices: %s\n", - sqlite3_errmsg (dbh)); -} - - - -#if 0 -#define CHECK(a) GNUNET_break(a) -#define ENULL NULL -#else -#define ENULL &e -#define ENULL_DEFINED 1 -#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } -#endif - - -/** - * Initialize the database connections and associated - * data structures (create tables and indices - * as needed as well). - * - * @param plugin the plugin context (state for this module) - * @return #GNUNET_OK on success - */ -static int -database_setup (struct Plugin *plugin) -{ - sqlite3_stmt *stmt; - char *afsdir; -#if ENULL_DEFINED - char *e; -#endif - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, - "identity-provider-sqlite", - "FILENAME", - &afsdir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "identity-provider-sqlite", - "FILENAME"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_DISK_file_test (afsdir)) - { - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (afsdir)) - { - GNUNET_break (0); - GNUNET_free (afsdir); - return GNUNET_SYSERR; - } - } - /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ - plugin->fn = afsdir; - - /* Open database and precompile statements */ - if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - _("Unable to initialize SQLite: %s.\n"), - sqlite3_errmsg (plugin->dbh)); - return GNUNET_SYSERR; - } - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA temp_store=MEMORY", NULL, NULL, - ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA synchronous=NORMAL", NULL, NULL, - ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA legacy_file_format=OFF", NULL, NULL, - ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA auto_vacuum=INCREMENTAL", NULL, - NULL, ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA encoding=\"UTF-8\"", NULL, - NULL, ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, - ENULL)); - CHECK (SQLITE_OK == - sqlite3_exec (plugin->dbh, - "PRAGMA page_size=4092", NULL, NULL, - ENULL)); - - CHECK (SQLITE_OK == - sqlite3_busy_timeout (plugin->dbh, - BUSY_TIMEOUT_MS)); - - - /* Create table */ - CHECK (SQLITE_OK == - sq_prepare (plugin->dbh, - "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'", - &stmt)); - if ((sqlite3_step (stmt) == SQLITE_DONE) && - (sqlite3_exec - (plugin->dbh, - "CREATE TABLE identity001tickets (" - " identity BLOB NOT NULL DEFAULT ''," - " audience BLOB NOT NULL DEFAULT ''," - " rnd INT8 NOT NULL DEFAULT ''," - " attributes BLOB NOT NULL DEFAULT ''" - ")", - NULL, NULL, NULL) != SQLITE_OK)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, - "sqlite3_exec"); - sqlite3_finalize (stmt); - return GNUNET_SYSERR; - } - sqlite3_finalize (stmt); - - create_indices (plugin->dbh); - - if ( (SQLITE_OK != - sq_prepare (plugin->dbh, - "INSERT INTO identity001tickets (identity, audience, rnd, attributes)" - " VALUES (?, ?, ?, ?)", - &plugin->store_ticket)) || - (SQLITE_OK != - sq_prepare (plugin->dbh, - "DELETE FROM identity001tickets WHERE identity=? AND rnd=?", - &plugin->delete_ticket)) || - (SQLITE_OK != - sq_prepare (plugin->dbh, - "SELECT identity,audience,rnd,attributes" - " FROM identity001tickets WHERE identity=? AND rnd=?", - &plugin->get_ticket_attrs)) || - (SQLITE_OK != - sq_prepare (plugin->dbh, - "SELECT identity,audience,rnd,attributes" - " FROM identity001tickets WHERE identity=?" - " ORDER BY rnd LIMIT 1 OFFSET ?", - &plugin->iterate_tickets)) || - (SQLITE_OK != - sq_prepare (plugin->dbh, - "SELECT identity,audience,rnd,attributes" - " FROM identity001tickets WHERE audience=?" - " ORDER BY rnd LIMIT 1 OFFSET ?", - &plugin->iterate_tickets_by_audience)) ) - { - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR, - "precompiling"); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Shutdown database connection and associate data - * structures. - * @param plugin the plugin context (state for this module) - */ -static void -database_shutdown (struct Plugin *plugin) -{ - int result; - sqlite3_stmt *stmt; - - if (NULL != plugin->store_ticket) - sqlite3_finalize (plugin->store_ticket); - if (NULL != plugin->delete_ticket) - sqlite3_finalize (plugin->delete_ticket); - if (NULL != plugin->iterate_tickets) - sqlite3_finalize (plugin->iterate_tickets); - if (NULL != plugin->iterate_tickets_by_audience) - sqlite3_finalize (plugin->iterate_tickets_by_audience); - if (NULL != plugin->get_ticket_attrs) - sqlite3_finalize (plugin->get_ticket_attrs); - result = sqlite3_close (plugin->dbh); - if (result == SQLITE_BUSY) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - _("Tried to close sqlite without finalizing all prepared statements.\n")); - stmt = sqlite3_next_stmt (plugin->dbh, - NULL); - while (NULL != stmt) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Closing statement %p\n", - stmt); - result = sqlite3_finalize (stmt); - if (result != SQLITE_OK) - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, - "sqlite", - "Failed to close statement %p: %d\n", - stmt, - result); - stmt = sqlite3_next_stmt (plugin->dbh, - NULL); - } - result = sqlite3_close (plugin->dbh); - } - if (SQLITE_OK != result) - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR, - "sqlite3_close"); - - GNUNET_free_non_null (plugin->fn); -} - - -/** - * Store a ticket in the database. - * - * @param cls closure (internal context for the plugin) - * @param ticket the ticket to persist - * @param attrs the attributes associated with the ticket - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -identity_provider_sqlite_store_ticket (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) -{ - struct Plugin *plugin = cls; - size_t attrs_len; - char *attrs_ser; - int n; - - { - /* First delete duplicates */ - struct GNUNET_SQ_QueryParam dparams[] = { - GNUNET_SQ_query_param_auto_from_type (&ticket->identity), - GNUNET_SQ_query_param_uint64 (&ticket->rnd), - GNUNET_SQ_query_param_end - }; - if (GNUNET_OK != - GNUNET_SQ_bind (plugin->delete_ticket, - dparams)) - { - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind_XXXX"); - GNUNET_SQ_reset (plugin->dbh, - plugin->delete_ticket); - return GNUNET_SYSERR; - } - n = sqlite3_step (plugin->delete_ticket); - GNUNET_SQ_reset (plugin->dbh, - plugin->delete_ticket); - - attrs_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs); - attrs_ser = GNUNET_malloc (attrs_len); - GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs, - attrs_ser); - struct GNUNET_SQ_QueryParam sparams[] = { - GNUNET_SQ_query_param_auto_from_type (&ticket->identity), - GNUNET_SQ_query_param_auto_from_type (&ticket->audience), - GNUNET_SQ_query_param_uint64 (&ticket->rnd), - GNUNET_SQ_query_param_fixed_size (attrs_ser, attrs_len), - GNUNET_SQ_query_param_end - }; - - if (GNUNET_OK != - GNUNET_SQ_bind (plugin->store_ticket, - sparams)) - { - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind_XXXX"); - GNUNET_SQ_reset (plugin->dbh, - plugin->store_ticket); - return GNUNET_SYSERR; - } - n = sqlite3_step (plugin->store_ticket); - GNUNET_SQ_reset (plugin->dbh, - plugin->store_ticket); - GNUNET_free (attrs_ser); - } - switch (n) - { - case SQLITE_DONE: - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Ticket stored\n"); - return GNUNET_OK; - case SQLITE_BUSY: - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - return GNUNET_NO; - default: - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - return GNUNET_SYSERR; - } -} - - -/** - * Store a ticket in the database. - * - * @param cls closure (internal context for the plugin) - * @param ticket the ticket to delete - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -identity_provider_sqlite_delete_ticket (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) -{ - struct Plugin *plugin = cls; - int n; - - { - struct GNUNET_SQ_QueryParam sparams[] = { - GNUNET_SQ_query_param_auto_from_type (&ticket->identity), - GNUNET_SQ_query_param_uint64 (&ticket->rnd), - GNUNET_SQ_query_param_end - }; - - if (GNUNET_OK != - GNUNET_SQ_bind (plugin->delete_ticket, - sparams)) - { - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind_XXXX"); - GNUNET_SQ_reset (plugin->dbh, - plugin->store_ticket); - return GNUNET_SYSERR; - } - n = sqlite3_step (plugin->delete_ticket); - GNUNET_SQ_reset (plugin->dbh, - plugin->delete_ticket); - } - switch (n) - { - case SQLITE_DONE: - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "sqlite", - "Ticket deleted\n"); - return GNUNET_OK; - case SQLITE_BUSY: - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - return GNUNET_NO; - default: - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_step"); - return GNUNET_SYSERR; - } -} - - -/** - * The given 'sqlite' statement has been prepared to be run. - * It will return a record which should be given to the iterator. - * Runs the statement and parses the returned record. - * - * @param plugin plugin context - * @param stmt to run (and then clean up) - * @param iter iterator to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error - */ -static int -get_ticket_and_call_iterator (struct Plugin *plugin, - sqlite3_stmt *stmt, - GNUNET_IDENTITY_PROVIDER_TicketIterator iter, - void *iter_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; - int ret; - int sret; - size_t attrs_len; - char *attrs_ser; - - ret = GNUNET_NO; - if (SQLITE_ROW == (sret = sqlite3_step (stmt))) - { - struct GNUNET_SQ_ResultSpec rs[] = { - GNUNET_SQ_result_spec_auto_from_type (&ticket.identity), - GNUNET_SQ_result_spec_auto_from_type (&ticket.audience), - GNUNET_SQ_result_spec_uint64 (&ticket.rnd), - GNUNET_SQ_result_spec_variable_size ((void**)&attrs_ser, - &attrs_len), - GNUNET_SQ_result_spec_end - - }; - ret = GNUNET_SQ_extract_result (stmt, - rs); - if (GNUNET_OK != ret) - { - GNUNET_break (0); - ret = GNUNET_SYSERR; - } - else - { - attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize (attrs_ser, - attrs_len); - if (NULL != iter) - iter (iter_cls, - &ticket, - attrs); - GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs); - ret = GNUNET_YES; - } - GNUNET_SQ_cleanup_result (rs); - } - else - { - if (SQLITE_DONE != sret) - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR, - "sqlite_step"); - } - GNUNET_SQ_reset (plugin->dbh, - stmt); - return ret; -} - - -/** - * Lookup tickets in the datastore. - * - * @param cls closure (internal context for the plugin) - * @param ticket the ticket to retrieve attributes for - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ -static int -identity_provider_sqlite_ticket_get_attrs (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_TicketIterator iter, - void *iter_cls) -{ - struct Plugin *plugin = cls; - struct GNUNET_SQ_QueryParam params[] = { - GNUNET_SQ_query_param_auto_from_type (&ticket->identity), - GNUNET_SQ_query_param_uint64 (&ticket->rnd), - GNUNET_SQ_query_param_end - }; - - if (GNUNET_OK != - GNUNET_SQ_bind (plugin->get_ticket_attrs, - params)) - { - LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind_XXXX"); - GNUNET_SQ_reset (plugin->dbh, - plugin->get_ticket_attrs); - return GNUNET_SYSERR; - } - return get_ticket_and_call_iterator (plugin, - plugin->get_ticket_attrs, - iter, - iter_cls); -} - - -/** - * Iterate over the results for a particular key and zone in the - * datastore. Will return at most one result to the iterator. - * - * @param cls closure (internal context for the plugin) - * @param identity the issuing identity or audience (depending on audience switch) - * @param audience GNUNET_YES if identity is audience - * @param offset offset in the list of all matching records - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error - */ -static int -identity_provider_sqlite_iterate_tickets (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - int audience, - uint64_t offset, - GNUNET_IDENTITY_PROVIDER_TicketIterator iter, - void *iter_cls) -{ - struct Plugin *plugin = cls; - sqlite3_stmt *stmt; - int err; - - if (NULL == identity) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - struct GNUNET_SQ_QueryParam params[] = { - GNUNET_SQ_query_param_auto_from_type (identity), - GNUNET_SQ_query_param_uint64 (&offset), - GNUNET_SQ_query_param_end - }; - if (GNUNET_YES == audience) - { - stmt = plugin->iterate_tickets_by_audience; - err = GNUNET_SQ_bind (stmt, - params); - } - else - { - stmt = plugin->iterate_tickets; - err = GNUNET_SQ_bind (stmt, - params); - } - if (GNUNET_OK != err) - { - LOG_SQLITE (plugin, - GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, - "sqlite3_bind_XXXX"); - GNUNET_SQ_reset (plugin->dbh, - stmt); - return GNUNET_SYSERR; - } - return get_ticket_and_call_iterator (plugin, - stmt, - iter, - iter_cls); -} - - -/** - * Entry point for the plugin. - * - * @param cls the "struct GNUNET_IDENTITY_PROVIDER_PluginEnvironment*" - * @return NULL on error, otherwise the plugin context - */ -void * -libgnunet_plugin_identity_provider_sqlite_init (void *cls) -{ - static struct Plugin plugin; - const struct GNUNET_CONFIGURATION_Handle *cfg = cls; - struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api; - - if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); - plugin.cfg = cfg; - if (GNUNET_OK != database_setup (&plugin)) - { - database_shutdown (&plugin); - return NULL; - } - api = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_PluginFunctions); - api->cls = &plugin; - api->store_ticket = &identity_provider_sqlite_store_ticket; - api->delete_ticket = &identity_provider_sqlite_delete_ticket; - api->iterate_tickets = &identity_provider_sqlite_iterate_tickets; - api->get_ticket_attributes = &identity_provider_sqlite_ticket_get_attrs; - LOG (GNUNET_ERROR_TYPE_INFO, - _("Sqlite database running\n")); - return api; -} - - -/** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ -void * -libgnunet_plugin_identity_provider_sqlite_done (void *cls) -{ - struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api = cls; - struct Plugin *plugin = api->cls; - - database_shutdown (plugin); - plugin->cfg = NULL; - GNUNET_free (api); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "sqlite plugin is finished\n"); - return NULL; -} - -/* end of plugin_identity_provider_sqlite.c */ diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c deleted file mode 100644 index f8176a101..000000000 --- a/src/identity-provider/plugin_rest_identity_provider.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @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 "gnunet_jsonapi_lib.h" -#include "gnunet_jsonapi_util.h" -#include "microhttpd.h" -#include -#include -#include "gnunet_signatures.h" -#include "gnunet_identity_attribute_lib.h" -#include "gnunet_identity_provider_service.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp" - -/** - * Attribute namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes" - -/** - * Ticket namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke" - -/** - * Revoke namespace - */ -#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" - -/** - * Attribute key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" - -/** - * Ticket key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" - - -/** - * Value key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * 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; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Handle to NAMESTORE - */ - struct GNUNET_NAMESTORE_Handle *namestore_handle; - - /** - * Iterator for NAMESTORE - */ - struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; - - /** - * Attribute claim list - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Identity Provider - */ - struct GNUNET_IDENTITY_PROVIDER_Handle *idp; - - /** - * Idp Operation - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op; - - /** - * Attribute iterator - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it; - - /** - * Ticket iterator - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - - /** - * 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; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * Error response message - */ - char *emsg; - - /** - * Reponse code - */ - int response_code; - - /** - * Response object - */ - struct GNUNET_JSONAPI_Document *resp_object; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->resp_object) - GNUNET_JSONAPI_document_delete (handle->resp_object); - 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->attr_it) - GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it); - if (NULL != handle->ticket_it) - GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->idp) - GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->namestore_handle) - GNUNET_NAMESTORE_disconnect (handle->namestore_handle); - if ( NULL != handle->attr_list ) - { - for (claim_entry = handle->attr_list->list_head; - NULL != claim_entry;) - { - claim_tmp = claim_entry; - claim_entry = claim_entry->next; - GNUNET_free(claim_tmp->claim); - GNUNET_free(claim_tmp); - } - GNUNET_free (handle->attr_list); - } - 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); - } - if (NULL != handle->attr_it) - { - GNUNET_free(handle->attr_it); - } - GNUNET_free (handle); -} - -static void -cleanup_handle_delayed (void *cls) -{ - cleanup_handle (cls); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", - handle->emsg); - if ( 0 == handle->response_code ) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (json_error); -} - - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - - -static void -collect_error_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - do_error (handle); -} - -static void -finished_cont (void *cls, - int32_t success, - const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - resp = GNUNET_REST_create_response (emsg); - if (GNUNET_OK != success) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); -} - - -/** - * Return attributes for identity - * - * @param cls the request handle - */ -static void -return_response (void *cls) -{ - char* result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - -static void -collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - //Done - handle->attr_it = NULL; - handle->ticket_it = NULL; - GNUNET_SCHEDULER_add_now (&return_response, handle); -} - - -/** - * Collect all attributes for an ego - * - */ -static void -ticket_collect (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) -{ - struct GNUNET_JSONAPI_Resource *json_resource; - struct RequestHandle *handle = cls; - json_t *value; - char* tmp; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, - sizeof (uint64_t)); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET, - tmp); - GNUNET_free (tmp); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "issuer", - value); - GNUNET_free (tmp); - json_decref (value); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "audience", - value); - GNUNET_free (tmp); - json_decref (value); - tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, - sizeof (uint64_t)); - value = json_string (tmp); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "rnd", - value); - GNUNET_free (tmp); - json_decref (value); - GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it); -} - - - -/** - * List tickets for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = GNUNET_JSONAPI_document_new (); - - if (NULL == ego_entry) - { - //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", - identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp, - priv_key, - &collect_error_cb, - handle, - &ticket_collect, - handle, - &collect_finished_cb, - handle); -} - - -static void -add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity; - const char* name_str; - const char* value_str; - const char* exp_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_TIME_Relative exp; - char term_data[handle->rest_handle->data_size+1]; - json_t *value_json; - json_t *data_json; - json_t *exp_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - name_str = GNUNET_JSONAPI_resource_get_id (json_res); - exp_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "exp"); - exp_str = json_string_value (exp_json); - if (NULL == exp_str) { - exp = GNUNET_TIME_UNIT_HOURS; - } else { - if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str, - &exp)) { - exp = GNUNET_TIME_UNIT_HOURS; - } - } - - value_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "value"); - value_str = json_string_value (value_json); - attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str, - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - value_str, - strlen (value_str) + 1); - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp, - identity_priv, - attribute, - &exp, - &finished_cont, - handle); - GNUNET_free (attribute); - GNUNET_JSONAPI_document_delete (json_obj); -} - - - -/** - * Collect all attributes for an ego - * - */ -static void -attr_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - struct GNUNET_JSONAPI_Resource *json_resource; - struct RequestHandle *handle = cls; - json_t *value; - char* tmp_value; - - if ((NULL == attr->name) || (NULL == attr->data)) - { - GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", - attr->name); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE, - attr->name); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - - value = json_string (tmp_value); - - GNUNET_JSONAPI_resource_add_attr (json_resource, - "value", - value); - json_decref (value); - GNUNET_free(tmp_value); - GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); -} - - - -/** - * List attributes for identity request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - char *identity; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", - handle->url); - if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >= - strlen (handle->url)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1; - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - if (0 == strcmp (identity, ego_entry->identifier)) - break; - handle->resp_object = GNUNET_JSONAPI_document_new (); - - - if (NULL == ego_entry) - { - //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", - identity); - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp, - priv_key, - &collect_error_cb, - handle, - &attr_collect, - handle, - &collect_finished_cb, - handle); -} - - -static void -revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity_str; - const char* audience_str; - const char* rnd_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; - char term_data[handle->rest_handle->data_size+1]; - json_t *rnd_json; - json_t *identity_json; - json_t *audience_json; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_IDENTITY_TICKET)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "rnd"); - identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "issuer"); - audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "audience"); - rnd_str = json_string_value (rnd_json); - identity_str = json_string_value (identity_json); - audience_str = json_string_value (audience_json); - - GNUNET_STRINGS_string_to_data (rnd_str, - strlen (rnd_str), - &ticket.rnd, - sizeof (uint64_t)); - GNUNET_STRINGS_string_to_data (identity_str, - strlen (identity_str), - &ticket.identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - GNUNET_STRINGS_string_to_data (audience_str, - strlen (audience_str), - &ticket.audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &tmp_pk); - if (0 == memcmp (&ticket.identity, - &tmp_pk, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity_str); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp, - identity_priv, - &ticket, - &finished_cont, - handle); - GNUNET_JSONAPI_document_delete (json_obj); -} - -static void -consume_cont (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - struct GNUNET_JSONAPI_Resource *json_resource; - json_t *value; - - if (NULL == identity) - { - GNUNET_SCHEDULER_add_now (&return_response, handle); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", - attr->name); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE, - attr->name); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - - value = json_string (attr->data); - GNUNET_JSONAPI_resource_add_attr (json_resource, - "value", - value); - json_decref (value); -} - -static void -consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; - const char* identity_str; - const char* audience_str; - const char* rnd_str; - - struct RequestHandle *handle = cls; - struct EgoEntry *ego_entry; - struct MHD_Response *resp; - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - struct GNUNET_JSONAPI_Document *json_obj; - struct GNUNET_JSONAPI_Resource *json_res; - struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; - char term_data[handle->rest_handle->data_size+1]; - json_t *rnd_json; - json_t *identity_json; - json_t *audience_json; - json_t *data_json; - json_error_t err; - struct GNUNET_JSON_Specification docspec[] = { - GNUNET_JSON_spec_jsonapi_document (&json_obj), - GNUNET_JSON_spec_end() - }; - - if (0 >= handle->rest_handle->data_size) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, - handle->rest_handle->data, - handle->rest_handle->data_size); - data_json = json_loads (term_data, - JSON_DECODE_ANY, - &err); - GNUNET_assert (GNUNET_OK == - GNUNET_JSON_parse (data_json, docspec, - NULL, NULL)); - json_decref (data_json); - if (NULL == json_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse JSONAPI Object from %s\n", - term_data); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot create more than 1 resource! (Got %d)\n", - GNUNET_JSONAPI_document_resource_count (json_obj)); - GNUNET_JSONAPI_document_delete (json_obj); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); - if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, - GNUNET_REST_JSONAPI_IDENTITY_TICKET)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unsupported JSON data type\n"); - GNUNET_JSONAPI_document_delete (json_obj); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); - cleanup_handle (handle); - return; - } - rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "rnd"); - identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "identity"); - audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, - "audience"); - rnd_str = json_string_value (rnd_json); - identity_str = json_string_value (identity_json); - audience_str = json_string_value (audience_json); - - GNUNET_STRINGS_string_to_data (rnd_str, - strlen (rnd_str), - &ticket.rnd, - sizeof (uint64_t)); - GNUNET_STRINGS_string_to_data (identity_str, - strlen (identity_str), - &ticket.identity, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - GNUNET_STRINGS_string_to_data (audience_str, - strlen (audience_str), - &ticket.audience, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - for (ego_entry = handle->ego_head; - NULL != ego_entry; - ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &tmp_pk); - if (0 == memcmp (&ticket.audience, - &tmp_pk, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - break; - } - if (NULL == ego_entry) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Identity unknown (%s)\n", identity_str); - GNUNET_JSONAPI_document_delete (json_obj); - return; - } - identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - handle->resp_object = GNUNET_JSONAPI_document_new (); - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp, - identity_priv, - &ticket, - &consume_cont, - handle); - GNUNET_JSONAPI_document_delete (json_obj); -} - - - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *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_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) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, - &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - 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; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - } - -} - -static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->state = ID_REST_STATE_INIT; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_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->namestore_handle = GNUNET_NAMESTORE_connect (cfg); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_timeout, - 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_provider_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_PROVIDER; - 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_DEBUG, - _("Identity Provider 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_provider_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 Provider REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_identity_provider.c */ diff --git a/src/identity-provider/plugin_rest_openid_connect.c b/src/identity-provider/plugin_rest_openid_connect.c deleted file mode 100644 index cc4b83dae..000000000 --- a/src/identity-provider/plugin_rest_openid_connect.c +++ /dev/null @@ -1,2227 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -/** - * @author Martin Schanzenbach - * @author Philippe Buschmann - * @file identity/plugin_rest_openid_connect.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 "gnunet_jsonapi_lib.h" -#include "gnunet_jsonapi_util.h" -#include "microhttpd.h" -#include -#include -#include "gnunet_signatures.h" -#include "gnunet_identity_attribute_lib.h" -#include "gnunet_identity_provider_service.h" -#include "jwt.h" - -/** - * REST root namespace - */ -#define GNUNET_REST_API_NS_OIDC "/openid" - -/** - * Authorize endpoint - */ -#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize" - -/** - * Token endpoint - */ -#define GNUNET_REST_API_NS_TOKEN "/openid/token" - -/** - * UserInfo endpoint - */ -#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo" - -/** - * Login namespace - */ -#define GNUNET_REST_API_NS_LOGIN "/openid/login" - -/** - * Attribute key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" - -/** - * Ticket key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" - - -/** - * Value key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value" - -/** - * State while collecting all egos - */ -#define ID_REST_STATE_INIT 0 - -/** - * Done collecting egos - */ -#define ID_REST_STATE_POST_INIT 1 - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_KEY "grant_type" - -/** - * OIDC grant_type key - */ -#define OIDC_GRANT_TYPE_VALUE "authorization_code" - -/** - * OIDC code key - */ -#define OIDC_CODE_KEY "code" - -/** - * OIDC response_type key - */ -#define OIDC_RESPONSE_TYPE_KEY "response_type" - -/** - * OIDC client_id key - */ -#define OIDC_CLIENT_ID_KEY "client_id" - -/** - * OIDC scope key - */ -#define OIDC_SCOPE_KEY "scope" - -/** - * OIDC redirect_uri key - */ -#define OIDC_REDIRECT_URI_KEY "redirect_uri" - -/** - * OIDC state key - */ -#define OIDC_STATE_KEY "state" - -/** - * OIDC nonce key - */ -#define OIDC_NONCE_KEY "nonce" - -/** - * OIDC cookie header key - */ -#define OIDC_COOKIE_HEADER_KEY "cookie" - -/** - * OIDC cookie header information key - */ -#define OIDC_AUTHORIZATION_HEADER_KEY "authorization" - -/** - * OIDC cookie header information key - */ -#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" - -/** - * OIDC expected response_type while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" - -/** - * OIDC expected scope part while authorizing - */ -#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" - -/** - * OIDC ignored parameter array - */ -static char* OIDC_ignored_parameter_array [] = -{ - "display", - "prompt", - "max_age", - "ui_locales", - "response_mode", - "id_token_hint", - "login_hint", - "acr_values" -}; - -/** - * OIDC authorized identities and times hashmap - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; - -/** - * OIDC authorized identities and times hashmap - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; - -/** - * OIDC ticket/code use only once - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; - -/** - * OIDC access_token to ticket and ego - */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; - -/** - * 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; -}; - -/** - * OIDC needed variables - */ -struct OIDC_Variables -{ - /** - * The RP client public key - */ - struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey; - - /** - * The OIDC client id of the RP - */ - char *client_id; - - /** - * GNUNET_YES if there is a delegation to - * this RP or if it is a local identity - */ - int is_client_trusted; - - /** - * The OIDC redirect uri - */ - char *redirect_uri; - - /** - * The list of oidc scopes - */ - char *scope; - - /** - * The OIDC state - */ - char *state; - - /** - * The OIDC nonce - */ - char *nonce; - - /** - * The OIDC response type - */ - char *response_type; - - /** - * The identity chosen by the user to login - */ - char *login_identity; - - /** - * The response JSON - */ - json_t *response; - -}; - -/** - * 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; - - /** - * Pointer to ego private key - */ - struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; - - /** - * OIDC variables - */ - struct OIDC_Variables *oidc; - - /** - * The processing state - */ - int state; - - /** - * Handle to Identity service. - */ - struct GNUNET_IDENTITY_Handle *identity_handle; - - /** - * Rest connection - */ - struct GNUNET_REST_RequestHandle *rest_handle; - - /** - * Handle to NAMESTORE - */ - struct GNUNET_NAMESTORE_Handle *namestore_handle; - - /** - * Iterator for NAMESTORE - */ - struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; - - /** - * Attribute claim list - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list; - - /** - * IDENTITY Operation - */ - struct GNUNET_IDENTITY_Operation *op; - - /** - * Identity Provider - */ - struct GNUNET_IDENTITY_PROVIDER_Handle *idp; - - /** - * Idp Operation - */ - struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op; - - /** - * Attribute iterator - */ - struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it; - - /** - * Ticket iterator - */ - struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it; - - /** - * A ticket - */ - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - - /** - * 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; - - /** - * The plugin result processor - */ - GNUNET_REST_ResultProcessor proc; - - /** - * The closure of the result processor - */ - void *proc_cls; - - /** - * The url - */ - char *url; - - /** - * The tld for redirect - */ - char *tld; - - /** - * Error response message - */ - char *emsg; - - /** - * Error response description - */ - char *edesc; - - /** - * Reponse code - */ - int response_code; - - /** - * Response object - */ - struct GNUNET_JSONAPI_Document *resp_object; - -}; - -/** - * Cleanup lookup handle - * @param handle Handle to clean up - */ -static void -cleanup_handle (struct RequestHandle *handle) -{ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp; - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->resp_object) - GNUNET_JSONAPI_document_delete (handle->resp_object); - 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->attr_it) - GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it); - if (NULL != handle->ticket_it) - GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it); - if (NULL != handle->idp) - GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->tld) - GNUNET_free (handle->tld); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->edesc) - GNUNET_free (handle->edesc); - if (NULL != handle->namestore_handle) - GNUNET_NAMESTORE_disconnect (handle->namestore_handle); - if (NULL != handle->oidc) - { - if (NULL != handle->oidc->client_id) - GNUNET_free(handle->oidc->client_id); - if (NULL != handle->oidc->login_identity) - GNUNET_free(handle->oidc->login_identity); - if (NULL != handle->oidc->nonce) - GNUNET_free(handle->oidc->nonce); - if (NULL != handle->oidc->redirect_uri) - GNUNET_free(handle->oidc->redirect_uri); - if (NULL != handle->oidc->response_type) - GNUNET_free(handle->oidc->response_type); - if (NULL != handle->oidc->scope) - GNUNET_free(handle->oidc->scope); - if (NULL != handle->oidc->state) - GNUNET_free(handle->oidc->state); - if (NULL != handle->oidc->response) - json_decref(handle->oidc->response); - GNUNET_free(handle->oidc); - } - if ( NULL != handle->attr_list ) - { - for (claim_entry = handle->attr_list->list_head; - NULL != claim_entry;) - { - claim_tmp = claim_entry; - claim_entry = claim_entry->next; - GNUNET_free(claim_tmp->claim); - GNUNET_free(claim_tmp); - } - GNUNET_free (handle->attr_list); - } - 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); - } - if (NULL != handle->attr_it) - { - GNUNET_free(handle->attr_it); - } - GNUNET_free (handle); -} - -static void -cleanup_handle_delayed (void *cls) -{ - cleanup_handle (cls); -} - - -/** - * Task run on error, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *json_error; - - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : "", - (NULL != handle->oidc->state) ? ", \"state\":\"" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : "", - (NULL != handle->oidc->state) ? "\"" : ""); - if ( 0 == handle->response_code ) - { - handle->response_code = MHD_HTTP_BAD_REQUEST; - } - resp = GNUNET_REST_create_response (json_error); - if (MHD_HTTP_UNAUTHORIZED == handle->response_code) - { - MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); - } - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (json_error); -} - - -/** - * Task run on error in userinfo endpoint, sends error header. Cleans up - * everything - * - * @param cls the `struct RequestHandle` - */ -static void -do_userinfo_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *error; - - GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", - handle->emsg, - (NULL != handle->edesc) ? handle->edesc : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header(resp, "WWW-Authenticate", error); - handle->proc (handle->proc_cls, resp, handle->response_code); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (error); -} - - -/** - * Task run on error, sends error message and redirects. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_redirect_error (void *cls) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char* redirect; - GNUNET_asprintf (&redirect, - "%s?error=%s&error_description=%s%s%s", - handle->oidc->redirect_uri, handle->emsg, handle->edesc, - (NULL != handle->oidc->state) ? "&state=" : "", - (NULL != handle->oidc->state) ? handle->oidc->state : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", redirect); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (redirect); -} - -/** - * Task run on timeout, sends error message. Cleans up everything. - * - * @param cls the `struct RequestHandle` - */ -static void -do_timeout (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->timeout_task = NULL; - do_error (handle); -} - -/** - * Return attributes for claim - * - * @param cls the request handle - */ -static void -return_userinfo_response (void *cls) -{ - char* result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - result_str = json_dumps (handle->oidc->response, 0); - - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); -} - -/** - * Returns base64 encoded string without padding - * - * @param string the string to encode - * @return base64 encoded string - */ -static char* -base_64_encode(const char *s) -{ - char *enc; - char *tmp; - - GNUNET_STRINGS_base64_encode(s, strlen(s), &enc); - tmp = strrchr (enc, '='); - *tmp = '\0'; - return enc; -} - -/** - * Respond to OPTIONS request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -options_cont (struct GNUNET_REST_RequestHandle *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_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; -} - -/** - * Interprets cookie header and pass its identity keystring to handle - */ -static void -cookie_identity_interpretation (struct RequestHandle *handle) -{ - struct GNUNET_HashCode cache_key; - char *cookies; - struct GNUNET_TIME_Absolute current_time, *relog_time; - char delimiter[] = "; "; - - //gets identity of login try with cookie - GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), - &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) - { - //splits cookies and find 'Identity' cookie - cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); - handle->oidc->login_identity = strtok(cookies, delimiter); - - while ( NULL != handle->oidc->login_identity ) - { - if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) - { - break; - } - handle->oidc->login_identity = strtok (NULL, delimiter); - } - GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), - &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) - { - handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); - handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); - } else { - handle->oidc->login_identity = NULL; - } - } - else - { - handle->oidc->login_identity = NULL; - } - } -} - -/** - * Redirects to login page stored in configuration file - */ -static void -login_redirection(void *cls) -{ - char *login_base_url; - char *new_redirect; - struct MHD_Response *resp; - struct RequestHandle *handle = cls; - - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", - "address", &login_base_url) ) - { - GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", - login_base_url, - OIDC_RESPONSE_TYPE_KEY, - handle->oidc->response_type, - OIDC_CLIENT_ID_KEY, - handle->oidc->client_id, - OIDC_REDIRECT_URI_KEY, - handle->oidc->redirect_uri, - OIDC_SCOPE_KEY, - handle->oidc->scope, - OIDC_STATE_KEY, - (NULL != handle->oidc->state) ? handle->oidc->state : "", - OIDC_NONCE_KEY, - (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", new_redirect); - GNUNET_free(login_base_url); - } - else - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_free(new_redirect); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); -} - -/** - * Does internal server error when iteration failed. - */ -static void -oidc_iteration_error (void *cls) -{ - struct RequestHandle *handle = cls; - handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); -} - -static void get_client_name_result (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - char *ticket_str; - char *redirect_uri; - char *code_json_string; - char *code_base64_final_string; - char *redirect_path; - char *tmp; - char *tmp_prefix; - char *prefix; - ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, - sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - //TODO change if more attributes are needed (see max_age) - GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}", - ticket_str, - (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "", - (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "", - (NULL != handle->oidc->nonce) ? "\"" : ""); - code_base64_final_string = base_64_encode(code_json_string); - tmp = GNUNET_strdup (handle->oidc->redirect_uri); - redirect_path = strtok (tmp, "/"); - redirect_path = strtok (NULL, "/"); - redirect_path = strtok (NULL, "/"); - tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri); - prefix = strrchr (tmp_prefix, - (unsigned char) '.'); - *prefix = '\0'; - GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", - tmp_prefix, - handle->tld, - redirect_path, - handle->oidc->response_type, - code_base64_final_string, handle->oidc->state); - resp = GNUNET_REST_create_response (""); - MHD_add_response_header (resp, "Location", redirect_uri); - handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - GNUNET_free (tmp); - GNUNET_free (tmp_prefix); - GNUNET_free (redirect_uri); - GNUNET_free (ticket_str); - GNUNET_free (code_json_string); - GNUNET_free (code_base64_final_string); - return; -} - -static void -get_client_name_error (void *cls) -{ - struct RequestHandle *handle = cls; - - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); -} - -/** - * Issues ticket and redirects to relying party with the authorization code as - * parameter. Otherwise redirects with error - */ -static void -oidc_ticket_issue_cb (void* cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) -{ - struct RequestHandle *handle = cls; - handle->idp_op = NULL; - handle->ticket = *ticket; - if (NULL != ticket) { - GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, - &handle->priv_key, - &handle->oidc->client_pkey, - &get_client_name_error, - handle, - &get_client_name_result, - handle); - return; - } - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); -} - -static void -oidc_collect_finished_cb (void *cls) -{ - struct RequestHandle *handle = cls; - handle->attr_it = NULL; - handle->ticket_it = NULL; - if (NULL == handle->attr_list->list_head) - { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc = GNUNET_strdup("The requested scope is not available."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp, - &handle->priv_key, - &handle->oidc->client_pkey, - handle->attr_list, - &oidc_ticket_issue_cb, - handle); -} - - -/** - * Collects all attributes for an ego if in scope parameter - */ -static void -oidc_attr_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; - char* scope_variables; - char* scope_variable; - char delimiter[]=" "; - - if ( (NULL == attr->name) || (NULL == attr->data) ) - { - GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); - return; - } - - scope_variables = GNUNET_strdup(handle->oidc->scope); - scope_variable = strtok (scope_variables, delimiter); - while (NULL != scope_variable) - { - if ( 0 == strcmp (attr->name, scope_variable) ) - { - break; - } - scope_variable = strtok (NULL, delimiter); - } - if ( NULL == scope_variable ) - { - GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); - GNUNET_free(scope_variables); - return; - } - GNUNET_free(scope_variables); - - le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type, - attr->data, attr->data_size); - GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, - handle->attr_list->list_tail, le); - GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); -} - - -/** - * Checks time and cookie and redirects accordingly - */ -static void -login_check (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_TIME_Absolute current_time, *relog_time; - struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; - struct GNUNET_HashCode cache_key; - char *identity_cookie; - - GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); - GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); - GNUNET_free(identity_cookie); - //No login time for identity -> redirect to login - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, - &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) - { - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string ( - handle->oidc->login_identity, - strlen (handle->oidc->login_identity), &pubkey) ) - { - handle->emsg = GNUNET_strdup("invalid_cookie"); - handle->edesc = GNUNET_strdup( - "The cookie of a login identity is not valid"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - // iterate over egos and compare their public key - for (handle->ego_entry = handle->ego_head; - NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); - if ( 0 - == memcmp (&ego_pkey, &pubkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( - handle->ego_entry->ego); - handle->resp_object = GNUNET_JSONAPI_document_new (); - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->attr_list = GNUNET_new( - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start ( - handle->idp, &handle->priv_key, &oidc_iteration_error, handle, - &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); - return; - } - } - //handle->emsg = GNUNET_strdup("invalid_cookie"); - //handle->edesc = GNUNET_strdup( - // "The cookie of the login identity is not valid"); - //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_SCHEDULER_add_now (&login_redirection,handle); - return; - } - } -} - -/** - * Searches for client_id in namestore. If found trust status stored in handle - * Else continues to search - * - * @param handle the RequestHandle - */ -static void -namestore_iteration_callback ( - void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, - const char *rname, unsigned int rd_len, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey; - struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey; - int i; - - for (i = 0; i < rd_len; i++) - { - if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type ) - continue; - - if ( NULL != handle->oidc->login_identity ) - { - GNUNET_CRYPTO_ecdsa_public_key_from_string ( - handle->oidc->login_identity, - strlen (handle->oidc->login_identity), - &login_identity_pkey); - GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, - ¤t_zone_pkey); - - if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->oidc->is_client_trusted = GNUNET_YES; - } - } - } - else - { - if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->oidc->is_client_trusted = GNUNET_YES; - } - } - } - - GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it, - 1); -} - - -/** - * Iteration over all results finished, build final - * response. - * - * @param cls the `struct RequestHandle` - */ -static void -namestore_iteration_finished (void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - - char *expected_scope; - char delimiter[]=" "; - int number_of_ignored_parameter, iterator; - - - handle->ego_entry = handle->ego_entry->next; - - if(NULL != handle->ego_entry) - { - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego); - handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key, - &oidc_iteration_error, handle, &namestore_iteration_callback, handle, - &namestore_iteration_finished, handle); - return; - } - if (GNUNET_NO == handle->oidc->is_client_trusted) - { - handle->emsg = GNUNET_strdup("unauthorized_client"); - handle->edesc = GNUNET_strdup("The client is not authorized to request an " - "authorization code using this method."); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - // REQUIRED value: redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); - - // REQUIRED value: response_type - GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter response_type"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); - - // REQUIRED value: scope - GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter scope"); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); - - //OPTIONAL value: nonce - GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); - } - - //TODO check other values if needed - number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); - for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) - { - GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], - strlen(OIDC_ignored_parameter_array[iterator]), - &cache_key); - if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("access_denied"); - GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", - OIDC_ignored_parameter_array[iterator]); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - } - - // Checks if response_type is 'code' - if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) - { - handle->emsg=GNUNET_strdup("unsupported_response_type"); - handle->edesc=GNUNET_strdup("The authorization server does not support " - "obtaining this authorization code."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - - // Checks if scope contains 'openid' - expected_scope = GNUNET_strdup(handle->oidc->scope); - char* test; - test = strtok (expected_scope, delimiter); - while (NULL != test) - { - if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) - { - break; - } - test = strtok (NULL, delimiter); - } - if (NULL == test) - { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " - "malformed."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_free(expected_scope); - return; - } - - GNUNET_free(expected_scope); - - if( NULL != handle->oidc->login_identity ) - { - GNUNET_SCHEDULER_add_now(&login_check,handle); - return; - } - - GNUNET_SCHEDULER_add_now(&login_redirection,handle); -} - -/** - * Responds to authorization GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct EgoEntry *tmp_ego; - struct GNUNET_CRYPTO_EcdsaPublicKey pkey; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - - cookie_identity_interpretation(handle); - - //RECOMMENDED value: state - REQUIRED for answers - GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->state = GNUNET_strdup (handle->oidc->state); - } - - // REQUIRED value: client_id - GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter client_id"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); - - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, - strlen (handle->oidc->client_id), - &handle->oidc->client_pkey) ) - { - handle->emsg = GNUNET_strdup("unauthorized_client"); - handle->edesc = GNUNET_strdup("The client is not authorized to request an " - "authorization code using this method."); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - - if ( NULL == handle->ego_head ) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("Egos are missing"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - handle->ego_entry = handle->ego_head; - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); - handle->oidc->is_client_trusted = GNUNET_NO; - - //First check if client_id is one of our egos; TODO: handle other TLD cases: Delegation, from config - for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) - { - priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); - GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, - &pkey); - if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) - { - handle->tld = GNUNET_strdup (tmp_ego->identifier); - handle->oidc->is_client_trusted = GNUNET_YES; - handle->ego_entry = handle->ego_tail; - } - } - - - // Checks if client_id is valid: - handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start ( - handle->namestore_handle, &handle->priv_key, &oidc_iteration_error, - handle, &namestore_iteration_callback, handle, - &namestore_iteration_finished, handle); -} - -/** - * Combines an identity with a login time and responds OK to login request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -login_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct MHD_Response *resp = GNUNET_REST_create_response (""); - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - struct GNUNET_TIME_Absolute *current_time; - struct GNUNET_TIME_Absolute *last_time; - char* cookie; - json_t *root; - json_error_t error; - json_t *identity; - char term_data[handle->rest_handle->data_size+1]; - term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); - root = json_loads (term_data, JSON_DECODE_ANY, &error); - identity = json_object_get (root, "identity"); - if ( json_is_string(identity) ) - { - GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); - MHD_add_response_header (resp, "Set-Cookie", cookie); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); - GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); - - current_time = GNUNET_new(struct GNUNET_TIME_Absolute); - *current_time = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), - 5)); - last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); - if (NULL != last_time) - { - GNUNET_free(last_time); - } - GNUNET_CONTAINER_multihashmap_put ( - OIDC_identity_login_time, &cache_key, current_time, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(cookie); - } - else - { - handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); - } - json_decref (root); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - return; -} - -/** - * Responds to token url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - //TODO static strings - struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; - char *authorization, *credentials; - char delimiter[]=" "; - char delimiter_user_psw[]=":"; - char *grant_type, *code; - char *user_psw = NULL, *client_id, *psw; - char *expected_psw; - int client_exists = GNUNET_NO; - struct MHD_Response *resp; - char* code_output; - json_t *root, *ticket_string, *nonce, *max_age; - json_error_t error; - char *json_response; - char *jwt_secret; - - /* - * Check Authorization - */ - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->edesc=GNUNET_strdup("missing authorization"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); - - //split header in "Basic" and [content] - credentials = strtok (authorization, delimiter); - if (0 != strcmp ("Basic",credentials)) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - credentials = strtok(NULL, delimiter); - if (NULL == credentials) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw); - - if ( NULL == user_psw ) - { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - client_id = strtok (user_psw, delimiter_user_psw); - if ( NULL == client_id ) - { - GNUNET_free_non_null(user_psw); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - psw = strtok (NULL, delimiter_user_psw); - if (NULL == psw) - { - GNUNET_free_non_null(user_psw); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //check client password - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", - "psw", &expected_psw) ) - { - if (0 != strcmp (expected_psw, psw)) - { - GNUNET_free_non_null(user_psw); - GNUNET_free(expected_psw); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_free(expected_psw); - } - else - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //check client_id - for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) - { - if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) - { - client_exists = GNUNET_YES; - break; - } - handle->ego_entry = handle->ego_entry->next; - } - if (GNUNET_NO == client_exists) - { - GNUNET_free_non_null(user_psw); - handle->emsg=GNUNET_strdup("invalid_client"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - /* - * Check parameter - */ - - //TODO Do not allow multiple equal parameter names - //REQUIRED grant_type - GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &cache_key) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter grant_type"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - grant_type = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->url_param_map, &cache_key); - - //REQUIRED code - GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &cache_key) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - - //REQUIRED redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->url_param_map, &cache_key) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //Check parameter grant_type == "authorization_code" - if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) - { - GNUNET_free_non_null(user_psw); - handle->emsg=GNUNET_strdup("unsupported_grant_type"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); - int i = 1; - if ( GNUNET_SYSERR - == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, - &cache_key, - &i, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - //decode code - GNUNET_STRINGS_base64_decode(code,strlen(code), (void**)&code_output); - root = json_loads (code_output, 0, &error); - GNUNET_free(code_output); - ticket_string = json_object_get (root, "ticket"); - nonce = json_object_get (root, "nonce"); - max_age = json_object_get (root, "max_age"); - - if(ticket_string == NULL && !json_is_string(ticket_string)) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - - struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket); - if ( GNUNET_OK - != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string), - strlen (json_string_value(ticket_string)), - ticket, - sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket))) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - // this is the current client (relying party) - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key); - if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - - //create jwt - unsigned long long int expiration_time; - if ( GNUNET_OK - != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin", - "expiration_time", &expiration_time) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("gnunet configuration failed"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); - //aud REQUIRED public key client_id must be there - GNUNET_IDENTITY_ATTRIBUTE_list_add(cl, - "aud", - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - client_id, - strlen(client_id)); - //exp REQUIRED time expired from config - struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), - expiration_time)); - const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time); - GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, - "exp", - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - exp_time_string, - strlen(exp_time_string)); - //iat REQUIRED time now - struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get(); - const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now); - GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, - "iat", - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - time_now_string, - strlen(time_now_string)); - //nonce only if nonce is provided - if ( NULL != nonce && json_is_string(nonce) ) - { - GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, - "nonce", - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - json_string_value(nonce), - strlen(json_string_value(nonce))); - } - //auth_time only if max_age is provided - if ( NULL != max_age && json_is_string(max_age) ) - { - GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, - "auth_time", - GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, - json_string_value(max_age), - strlen(json_string_value(max_age))); - } - //TODO OPTIONAL acr,amr,azp - - struct EgoEntry *ego_entry; - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) - { - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); - if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - break; - } - } - if ( NULL == ego_entry ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code..."); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - if ( GNUNET_OK - != GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", - "jwt_secret", &jwt_secret) ) - { - GNUNET_free_non_null(user_psw); - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("No signing secret configured!"); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - return; - } - struct GNUNET_CRYPTO_AuthKey jwt_sign_key; - struct GNUNET_CRYPTO_EcdsaPublicKey pk; - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pk); - GNUNET_CRYPTO_hash (jwt_secret, strlen (jwt_secret), (struct GNUNET_HashCode*)jwt_sign_key.key); - char *id_token = jwt_create_from_list(&ticket->audience, - &pk, - cl, - &jwt_sign_key); - - //Create random access_token - char* access_token_number; - char* access_token; - uint64_t random_number; - random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); - GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number); - GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); - - - - //TODO OPTIONAL add refresh_token and scope - GNUNET_asprintf (&json_response, - "{ \"access_token\" : \"%s\", " - "\"token_type\" : \"Bearer\", " - "\"expires_in\" : %d, " - "\"id_token\" : \"%s\"}", - access_token, - expiration_time, - id_token); - GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); - char *id_ticket_combination; - GNUNET_asprintf(&id_ticket_combination, - "%s;%s", - client_id, - json_string_value(ticket_string)); - GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, - &cache_key, - id_ticket_combination, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - resp = GNUNET_REST_create_response (json_response); - MHD_add_response_header (resp, "Cache-Control", "no-store"); - MHD_add_response_header (resp, "Pragma", "no-cache"); - MHD_add_response_header (resp, "Content-Type", "application/json"); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - - GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl); - GNUNET_free(access_token_number); - GNUNET_free(access_token); - GNUNET_free(user_psw); - GNUNET_free(json_response); - GNUNET_free(ticket); - GNUNET_free(id_token); - json_decref (root); - GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); -} - -/** - * Collects claims and stores them in handle - */ -static void -consume_ticket (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) -{ - struct RequestHandle *handle = cls; - char *tmp_value; - json_t *value; - - if (NULL == identity) - { - GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); - return; - } - - tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - - value = json_string (tmp_value); - - - json_object_set_new (handle->oidc->response, - attr->name, - value); - GNUNET_free (tmp_value); -} - -/** - * Responds to userinfo GET and url-encoded POST request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, void *cls) -{ - //TODO expiration time - struct RequestHandle *handle = cls; - char delimiter[] = " "; - char delimiter_db[] = ";"; - struct GNUNET_HashCode cache_key; - char *authorization, *authorization_type, *authorization_access_token; - char *client_ticket, *client, *ticket_str; - struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; - - GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, - strlen (OIDC_AUTHORIZATION_HEADER_KEY), - &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->header_param_map, &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - return; - } - authorization = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->header_param_map, &cache_key); - - //split header in "Bearer" and access_token - authorization = GNUNET_strdup(authorization); - authorization_type = strtok (authorization, delimiter); - if ( 0 != strcmp ("Bearer", authorization_type) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - authorization_access_token = strtok (NULL, delimiter); - if ( NULL == authorization_access_token ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - - GNUNET_CRYPTO_hash (authorization_access_token, - strlen (authorization_access_token), - &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, - &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - - client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, - &cache_key); - client_ticket = GNUNET_strdup(client_ticket); - client = strtok(client_ticket,delimiter_db); - if (NULL == client) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - handle->ego_entry = handle->ego_head; - for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) - { - if (0 == strcmp(handle->ego_entry->keystring,client)) - { - break; - } - } - if (NULL == handle->ego_entry) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - ticket_str = strtok(NULL, delimiter_db); - if (NULL == ticket_str) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket); - if ( GNUNET_OK - != GNUNET_STRINGS_string_to_data (ticket_str, - strlen (ticket_str), - ticket, - sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket))) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - - handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->oidc->response = json_object(); - json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume ( - handle->idp, - GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), - ticket, - consume_ticket, - handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - -} - - -/** - * Handle rest request - * - * @param handle the request handle - */ -static void -init_cont (struct RequestHandle *handle) -{ - struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, - &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) - { - handle->response_code = err.error_code; - 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; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - return; - } - /* Ego renamed or added */ - if (identifier != NULL) { - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) { - /* Rename */ - GNUNET_free (ego_entry->identifier); - ego_entry->identifier = GNUNET_strdup (identifier); - break; - } - } - if (NULL == ego_entry) { - /* Add */ - 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; - ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); - } - } else { - /* Delete */ - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) - break; - } - if (NULL != ego_entry) - GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry); - } - -} - -static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) -{ - struct RequestHandle *handle = GNUNET_new (struct RequestHandle); - handle->oidc = GNUNET_new (struct OIDC_Variables); - if ( NULL == OIDC_identity_login_time ) - OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_identity_grants ) - OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_ticket_once ) - OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_interpret_access_token ) - OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - handle->response_code = 0; - handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; - handle->proc_cls = proc_cls; - handle->proc = proc; - handle->state = ID_REST_STATE_INIT; - handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (rest_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->namestore_handle = GNUNET_NAMESTORE_connect (cfg); - handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_timeout, - 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_openid_connect_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_OIDC; - 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_DEBUG, - _("Identity Provider 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_openid_connect_done (void *cls) -{ - struct GNUNET_REST_Plugin *api = cls; - struct Plugin *plugin = api->cls; - plugin->cfg = NULL; - - struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; - void *value = NULL; - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( - OIDC_identity_login_time); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); - GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); - GNUNET_free_non_null (allow_methods); - GNUNET_free (api); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Provider REST plugin is finished\n"); - return NULL; -} - -/* end of plugin_rest_identity_provider.c */ diff --git a/src/identity-provider/test_idp.conf b/src/identity-provider/test_idp.conf deleted file mode 100644 index 3e4df561a..000000000 --- a/src/identity-provider/test_idp.conf +++ /dev/null @@ -1,33 +0,0 @@ -@INLINE@ test_idp_defaults.conf - -[PATHS] -GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-idp-peer-1/ - -[dht] -START_ON_DEMAND = YES - -[rest] -START_ON_DEMAND = YES -PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=$GNUNET_TMP/restlog - -[transport] -PLUGINS = - -[identity-provider] -START_ON_DEMAND = YES -#PREFIX = valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=$GNUNET_TMP/idplog - -[gns] -#PREFIX = valgrind --leak-check=full --track-origins=yes -START_ON_DEMAND = YES -AUTO_IMPORT_PKEY = YES -MAX_PARALLEL_BACKGROUND_QUERIES = 10 -DEFAULT_LOOKUP_TIMEOUT = 15 s -RECORD_PUT_INTERVAL = 1 h -ZONE_PUBLISH_TIME_WINDOW = 1 h -DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 - -[identity-rest-plugin] -address = http://localhost:8000/#/login -psw = mysupersecretpassword -expiration_time = 3600 diff --git a/src/identity-provider/test_idp.sh b/src/identity-provider/test_idp.sh deleted file mode 100755 index 598d1008c..000000000 --- a/src/identity-provider/test_idp.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -#trap "gnunet-arm -e -c test_idp_lookup.conf" SIGINT - -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` - -# (1) PKEY1.user -> PKEY2.resu.user -# (2) PKEY2.resu -> PKEY3 -# (3) PKEY3.user -> PKEY4 - - -which timeout &> /dev/null && DO_TIMEOUT="timeout 30" - -TEST_ATTR="test" -gnunet-arm -s -c test_idp.conf -gnunet-identity -C testego -c test_idp.conf -valgrind gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf -gnunet-idp -e testego -a name -V John -c test_idp.conf -gnunet-idp -e testego -D -c test_idp.conf -gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_attribute.sh b/src/identity-provider/test_idp_attribute.sh deleted file mode 100755 index 7f0f06dac..000000000 --- a/src/identity-provider/test_idp_attribute.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -trap "gnunet-arm -e -c test_idp.conf" SIGINT - -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` - -# (1) PKEY1.user -> PKEY2.resu.user -# (2) PKEY2.resu -> PKEY3 -# (3) PKEY3.user -> PKEY4 - - -which timeout &> /dev/null && DO_TIMEOUT="timeout 30" - -TEST_ATTR="test" -gnunet-arm -s -c test_idp.conf -#gnunet-arm -i rest -c test_idp.conf -gnunet-identity -C testego -c test_idp.conf -gnunet-identity -C rpego -c test_idp.conf -TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') -gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf -gnunet-idp -e testego -a name -V John -c test_idp.conf > /dev/null 2>&1 -if test $? != 0 -then - echo "Failed." - exit 1 -fi - -#curl localhost:7776/idp/attributes/testego -gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_consume.sh b/src/identity-provider/test_idp_consume.sh deleted file mode 100755 index 11f6865a4..000000000 --- a/src/identity-provider/test_idp_consume.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -trap "gnunet-arm -e -c test_idp.conf" SIGINT - -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` - -# (1) PKEY1.user -> PKEY2.resu.user -# (2) PKEY2.resu -> PKEY3 -# (3) PKEY3.user -> PKEY4 - - -which timeout &> /dev/null && DO_TIMEOUT="timeout 30" - -TEST_ATTR="test" -gnunet-arm -s -c test_idp.conf -#gnunet-arm -i rest -c test_idp.conf -gnunet-identity -C testego -c test_idp.conf -gnunet-identity -C rpego -c test_idp.conf -SUBJECT_KEY=$(gnunet-identity -d -c test_idp.conf | grep rpego | awk '{print $3}') -TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') -gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf -gnunet-idp -e testego -a name -V John -c test_idp.conf -TICKET=$(gnunet-idp -e testego -i "email,name" -r $SUBJECT_KEY -c test_idp.conf | awk '{print $1}') -gnunet-idp -e rpego -C $TICKET -c test_idp.conf > /dev/null 2>&1 - -if test $? != 0 -then - "Failed." - exit 1 -fi -#curl http://localhost:7776/idp/tickets/testego -gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_defaults.conf b/src/identity-provider/test_idp_defaults.conf deleted file mode 100644 index a9a197dea..000000000 --- a/src/identity-provider/test_idp_defaults.conf +++ /dev/null @@ -1,24 +0,0 @@ -@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf - -[PATHS] -GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-idp-testing/ - -[namestore-sqlite] -FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db - -[namecache-sqlite] -FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db - -[identity] -# Directory where we store information about our egos -EGODIR = $GNUNET_TEST_HOME/identity/egos/ - -[dhtcache] -DATABASE = heap - -[transport] -PLUGINS = tcp - -[transport-tcp] -BINDTO = 127.0.0.1 - diff --git a/src/identity-provider/test_idp_issue.sh b/src/identity-provider/test_idp_issue.sh deleted file mode 100755 index 90487ee73..000000000 --- a/src/identity-provider/test_idp_issue.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -trap "gnunet-arm -e -c test_idp.conf" SIGINT - -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` - -# (1) PKEY1.user -> PKEY2.resu.user -# (2) PKEY2.resu -> PKEY3 -# (3) PKEY3.user -> PKEY4 - - -which timeout &> /dev/null && DO_TIMEOUT="timeout 30" - -TEST_ATTR="test" -gnunet-arm -s -c test_idp.conf -#gnunet-arm -i rest -c test_idp.conf -gnunet-identity -C testego -c test_idp.conf -gnunet-identity -C rpego -c test_idp.conf -SUBJECT_KEY=$(gnunet-identity -d -c test_idp.conf | grep rpego | awk '{print $3}') -TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') -gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf > /dev/null 2>&1 -gnunet-idp -e testego -a name -V John -c test_idp.conf > /dev/null 2>&1 -#gnunet-idp -e testego -D -c test_idp.conf -gnunet-idp -e testego -i "email,name" -r $SUBJECT_KEY -c test_idp.conf > /dev/null 2>&1 -if test $? != 0 -then - echo "Failed." - exit 1 -fi -#curl http://localhost:7776/idp/attributes/testego -gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_revoke.sh b/src/identity-provider/test_idp_revoke.sh deleted file mode 100755 index 7a3f5d030..000000000 --- a/src/identity-provider/test_idp_revoke.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -trap "gnunet-arm -e -c test_idp.conf" SIGINT - -LOCATION=$(which gnunet-config) -if [ -z $LOCATION ] -then - LOCATION="gnunet-config" -fi -$LOCATION --version 1> /dev/null -if test $? != 0 -then - echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" - exit 77 -fi - -rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` - -# (1) PKEY1.user -> PKEY2.resu.user -# (2) PKEY2.resu -> PKEY3 -# (3) PKEY3.user -> PKEY4 - - -which timeout &> /dev/null && DO_TIMEOUT="timeout 30" - -TEST_ATTR="test" -gnunet-arm -s -c test_idp.conf 2&>1 > /dev/null -gnunet-identity -C alice -c test_idp.conf -gnunet-identity -C bob -c test_idp.conf -gnunet-identity -C eve -c test_idp.conf -ALICE_KEY=$(gnunet-identity -d -c test_idp.conf | grep alice | awk '{print $3}') -BOB_KEY=$(gnunet-identity -d -c test_idp.conf | grep bob | awk '{print $3}') -EVE_KEY=$(gnunet-identity -d -c test_idp.conf | grep eve | awk '{print $3}') - -gnunet-idp -e alice -E 15s -a email -V john@doe.gnu -c test_idp.conf -gnunet-idp -e alice -E 15s -a name -V John -c test_idp.conf -TICKET_BOB=$(gnunet-idp -e alice -i "email,name" -r $BOB_KEY -c test_idp.conf | awk '{print $1}') -#gnunet-idp -e bob -C $TICKET_BOB -c test_idp.conf -TICKET_EVE=$(gnunet-idp -e alice -i "email" -r $EVE_KEY -c test_idp.conf | awk '{print $1}') - -#echo "Consuming $TICKET" -#gnunet-idp -e eve -C $TICKET_EVE -c test_idp.conf -gnunet-idp -e alice -R $TICKET_EVE -c test_idp.conf - -#sleep 6 - -gnunet-idp -e eve -C $TICKET_EVE -c test_idp.conf 2&>1 >/dev/null -if test $? == 0 -then - echo "Eve can still resolve attributes..." - gnunet-arm -e -c test_idp.conf - exit 1 -fi - -gnunet-arm -e -c test_idp.conf -gnunet-arm -s -c test_idp.conf 2&>1 > /dev/null - -gnunet-idp -e bob -C $TICKET_BOB -c test_idp.conf 2&>1 >/dev/null -if test $? != 0 -then - echo "Bob cannot resolve attributes..." - gnunet-arm -e -c test_idp.conf - exit 1 -fi - -gnunet-arm -e -c test_idp.conf diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 08e9dd156..41b2b1382 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -66,7 +66,7 @@ gnunetinclude_HEADERS = \ gnunet_hello_lib.h \ gnunet_helper_lib.h \ gnunet_identity_service.h \ - gnunet_identity_provider_service.h \ + gnunet_reclaim_service.h \ gnunet_json_lib.h \ gnunet_jsonapi_lib.h \ gnunet_jsonapi_util.h \ diff --git a/src/include/gnunet_identity_attribute_lib.h b/src/include/gnunet_identity_attribute_lib.h deleted file mode 100644 index eb01f7ac2..000000000 --- a/src/include/gnunet_identity_attribute_lib.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2017 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @author Martin Schanzenbach - * - * @file - * Identity attribute definitions - * - * @defgroup identity-provider Identity Provider service - * @{ - */ -#ifndef GNUNET_IDENTITY_ATTRIBUTE_LIB_H -#define GNUNET_IDENTITY_ATTRIBUTE_LIB_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" - - -/** - * No value attribute. - */ -#define GNUNET_IDENTITY_ATTRIBUTE_TYPE_NONE 0 - -/** - * String attribute. - */ -#define GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING 1 - - - -/** - * An attribute. - */ -struct GNUNET_IDENTITY_ATTRIBUTE_Claim -{ - /** - * The name of the attribute. Note "name" must never be individually - * free'd - */ - const char* name; - - /** - * Type of Claim - */ - uint32_t type; - - /** - * Version - */ - uint32_t version; - - /** - * Number of bytes in @e data. - */ - size_t data_size; - - /** - * Binary value stored as attribute value. Note: "data" must never - * be individually 'malloc'ed, but instead always points into some - * existing data area. - */ - const void *data; - -}; - -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList -{ - /** - * List head - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *list_head; - - /** - * List tail - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *list_tail; -}; - -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry -{ - /** - * DLL - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *prev; - - /** - * DLL - */ - struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *next; - - /** - * The attribute claim - */ - struct GNUNET_IDENTITY_ATTRIBUTE_Claim *claim; -}; - -/** - * Create a new attribute claim. - * - * @param attr_name the attribute name - * @param type the attribute type - * @param data the attribute value - * @param data_size the attribute value size - * @return the new attribute - */ -struct GNUNET_IDENTITY_ATTRIBUTE_Claim * -GNUNET_IDENTITY_ATTRIBUTE_claim_new (const char* attr_name, - uint32_t type, - const void* data, - size_t data_size); - - -/** - * Get required size for serialization buffer - * - * @param attrs the attribute list to serialize - * - * @return the required buffer size - */ -size_t -GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - -void -GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - -void -GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - const char* attr_name, - uint32_t type, - const void* data, - size_t data_size); - -/** - * Serialize an attribute list - * - * @param attrs the attribute list to serialize - * @param result the serialized attribute - * - * @return length of serialized data - */ -size_t -GNUNET_IDENTITY_ATTRIBUTE_list_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - char *result); - -/** - * Deserialize an attribute list - * - * @param data the serialized attribute list - * @param data_size the length of the serialized data - * - * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller - */ -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList * -GNUNET_IDENTITY_ATTRIBUTE_list_deserialize (const char* data, - size_t data_size); - - -/** - * Get required size for serialization buffer - * - * @param attr the attribute to serialize - * - * @return the required buffer size - */ -size_t -GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr); - - - -/** - * Serialize an attribute - * - * @param attr the attribute to serialize - * @param result the serialized attribute - * - * @return length of serialized data - */ -size_t -GNUNET_IDENTITY_ATTRIBUTE_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, - char *result); - -/** - * Deserialize an attribute - * - * @param data the serialized attribute - * @param data_size the length of the serialized data - * - * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller - */ -struct GNUNET_IDENTITY_ATTRIBUTE_Claim * -GNUNET_IDENTITY_ATTRIBUTE_deserialize (const char* data, - size_t data_size); - -struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList* -GNUNET_IDENTITY_ATTRIBUTE_list_dup (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - -/** - * Convert a type name to the corresponding number - * - * @param typename name to convert - * @return corresponding number, UINT32_MAX on error - */ -uint32_t -GNUNET_IDENTITY_ATTRIBUTE_typename_to_number (const char *typename); - -/** - * Convert human-readable version of a 'claim' of an attribute to the binary - * representation - * - * @param type type of the claim - * @param s human-readable string - * @param data set to value in binary encoding (will be allocated) - * @param data_size set to number of bytes in @a data - * @return #GNUNET_OK on success - */ -int -GNUNET_IDENTITY_ATTRIBUTE_string_to_value (uint32_t type, - const char *s, - void **data, - size_t *data_size); - -/** - * Convert the 'claim' of an attribute to a string - * - * @param type the type of attribute - * @param data claim in binary encoding - * @param data_size number of bytes in @a data - * @return NULL on error, otherwise human-readable representation of the claim - */ -char * -GNUNET_IDENTITY_ATTRIBUTE_value_to_string (uint32_t type, - const void* data, - size_t data_size); - -/** - * Convert a type number to the corresponding type string - * - * @param type number of a type - * @return corresponding typestring, NULL on error - */ -const char* -GNUNET_IDENTITY_ATTRIBUTE_number_to_typename (uint32_t type); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - - -/* ifndef GNUNET_IDENTITY_ATTRIBUTE_LIB_H */ -#endif - -/** @} */ /* end of group identity */ - -/* end of gnunet_identity_attribute_lib.h */ diff --git a/src/include/gnunet_identity_attribute_plugin.h b/src/include/gnunet_identity_attribute_plugin.h deleted file mode 100644 index 7c399c616..000000000 --- a/src/include/gnunet_identity_attribute_plugin.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @author Martin Schanzenbach - * - * @file - * Plugin API for the idp database backend - * - * @defgroup identity-provider-plugin IdP service plugin API - * Plugin API for the idp database backend - * @{ - */ -#ifndef GNUNET_IDENTITY_ATTRIBUTE_PLUGIN_H -#define GNUNET_IDENTITY_ATTRIBUTE_PLUGIN_H - -#include "gnunet_util_lib.h" -#include "gnunet_identity_attribute_lib.h" - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -/** - * Function called to convert the binary value @a data of an attribute of - * type @a type to a human-readable string. - * - * @param cls closure - * @param type type of the attribute - * @param data value in binary encoding - * @param data_size number of bytes in @a data - * @return NULL on error, otherwise human-readable representation of the value - */ -typedef char * (*GNUNET_IDENTITY_ATTRIBUTE_ValueToStringFunction) (void *cls, - uint32_t type, - const void *data, - size_t data_size); - - -/** - * Function called to convert human-readable version of the value @a s - * of an attribute of type @a type to the respective binary - * representation. - * - * @param cls closure - * @param type type of the attribute - * @param s human-readable string - * @param data set to value in binary encoding (will be allocated) - * @param data_size set to number of bytes in @a data - * @return #GNUNET_OK on success - */ -typedef int (*GNUNET_IDENTITY_ATTRIBUTE_StringToValueFunction) (void *cls, - uint32_t type, - const char *s, - void **data, - size_t *data_size); - - -/** - * Function called to convert a type name to the - * corresponding number. - * - * @param cls closure - * @param typename name to convert - * @return corresponding number, UINT32_MAX on error - */ -typedef uint32_t (*GNUNET_IDENTITY_ATTRIBUTE_TypenameToNumberFunction) (void *cls, - const char *typename); - - -/** - * Function called to convert a type number (i.e. 1) to the - * corresponding type string - * - * @param cls closure - * @param type number of a type to convert - * @return corresponding typestring, NULL on error - */ -typedef const char * (*GNUNET_IDENTITY_ATTRIBUTE_NumberToTypenameFunction) (void *cls, - uint32_t type); - - -/** - * Each plugin is required to return a pointer to a struct of this - * type as the return value from its entry point. - */ -struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions -{ - - /** - * Closure for all of the callbacks. - */ - void *cls; - - /** - * Conversion to string. - */ - GNUNET_IDENTITY_ATTRIBUTE_ValueToStringFunction value_to_string; - - /** - * Conversion to binary. - */ - GNUNET_IDENTITY_ATTRIBUTE_StringToValueFunction string_to_value; - - /** - * Typename to number. - */ - GNUNET_IDENTITY_ATTRIBUTE_TypenameToNumberFunction typename_to_number; - - /** - * Number to typename. - */ - GNUNET_IDENTITY_ATTRIBUTE_NumberToTypenameFunction number_to_typename; - -}; - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_identity_provider_plugin.h b/src/include/gnunet_identity_provider_plugin.h deleted file mode 100644 index 2330066dd..000000000 --- a/src/include/gnunet_identity_provider_plugin.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @author Martin Schanzenbach - * - * @file - * Plugin API for the idp database backend - * - * @defgroup identity-provider-plugin IdP service plugin API - * Plugin API for the idp database backend - * @{ - */ -#ifndef GNUNET_IDENTITY_PROVIDER_PLUGIN_H -#define GNUNET_IDENTITY_PROVIDER_PLUGIN_H - -#include "gnunet_util_lib.h" -#include "gnunet_identity_provider_service.h" - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - - -/** - * Function called by for each matching ticket. - * - * @param cls closure - * @param ticket the ticket - */ -typedef void (*GNUNET_IDENTITY_PROVIDER_TicketIterator) (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - - -/** - * @brief struct returned by the initialization function of the plugin - */ -struct GNUNET_IDENTITY_PROVIDER_PluginFunctions -{ - - /** - * Closure to pass to all plugin functions. - */ - void *cls; - - /** - * Store a ticket in the database. - * - * @param cls closure (internal context for the plugin) - * @param ticket the ticket to store - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int (*store_ticket) (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); - - /** - * Delete a ticket from the database. - * - * @param cls closure (internal context for the plugin) - * @param ticket the ticket to store - * @return #GNUNET_OK on success, else #GNUNET_SYSERR - */ - int (*delete_ticket) (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket); - - - - /** - * Iterate over all tickets - * - * @param cls closure (internal context for the plugin) - * @param identity the identity - * @param audience GNUNET_YES if the identity is the audience of the ticket - * else it is considered the issuer - * @param iter function to call with the result - * @param iter_cls closure for @a iter - * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error - */ - int (*iterate_tickets) (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - int audience, - uint64_t offset, - GNUNET_IDENTITY_PROVIDER_TicketIterator iter, void *iter_cls); - - int (*get_ticket_attributes) (void* cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_TicketIterator iter, - void *iter_cls); -}; - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif - -/** @} */ /* end of group */ diff --git a/src/include/gnunet_identity_provider_service.h b/src/include/gnunet_identity_provider_service.h deleted file mode 100644 index 0c72556e8..000000000 --- a/src/include/gnunet_identity_provider_service.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2016 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @author Martin Schanzenbach - * - * @file - * Identity provider service; implements identity provider for GNUnet - * - * @defgroup identity-provider Identity Provider service - * @{ - */ -#ifndef GNUNET_IDENTITY_PROVIDER_SERVICE_H -#define GNUNET_IDENTITY_PROVIDER_SERVICE_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" -#include "gnunet_identity_attribute_lib.h" - -/** - * Version number of GNUnet Identity Provider API. - */ -#define GNUNET_IDENTITY_PROVIDER_VERSION 0x00000000 - -/** - * Handle to access the identity service. - */ -struct GNUNET_IDENTITY_PROVIDER_Handle; - -/** - * Handle for a token. - */ -struct GNUNET_IDENTITY_PROVIDER_Token; - -/** - * The ticket - */ -struct GNUNET_IDENTITY_PROVIDER_Ticket -{ - /** - * The ticket issuer - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity; - - /** - * The ticket audience - */ - struct GNUNET_CRYPTO_EcdsaPublicKey audience; - - /** - * The ticket random (NBO) - */ - uint64_t rnd; -}; - -/** - * Handle for an operation with the identity provider service. - */ -struct GNUNET_IDENTITY_PROVIDER_Operation; - - -/** - * Connect to the identity provider service. - * - * @param cfg Configuration to contact the identity provider service. - * @return handle to communicate with identity provider service - */ -struct GNUNET_IDENTITY_PROVIDER_Handle * -GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); - -/** - * Continuation called to notify client about result of the - * operation. - * - * @param cls closure - * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) - * #GNUNET_NO if content was already there or not found - * #GNUNET_YES (or other positive value) on success - * @param emsg NULL on success, otherwise an error message - */ -typedef void -(*GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus) (void *cls, - int32_t success, - const char *emsg); - - -/** - * Store an attribute. If the attribute is already present, - * it is replaced with the new attribute. - * - * @param h handle to the identity provider - * @param pkey private key of the identity - * @param attr the attribute - * @param exp_interval the relative expiration interval for the attribute - * @param cont continuation to call when done - * @param cont_cls closure for @a cont - * @return handle to abort the request - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, - const struct GNUNET_TIME_Relative *exp_interval, - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont, - void *cont_cls); - - -/** - * Process an attribute that was stored in the idp. - * - * @param cls closure - * @param identity the identity - * @param attr the attribute - */ -typedef void -(*GNUNET_IDENTITY_PROVIDER_AttributeResult) (void *cls, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr); - - - -/** - * List all attributes for a local identity. - * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle` - * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and - * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once - * immediately, and then again after - * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked. - * - * On error (disconnect), @a error_cb will be invoked. - * On normal completion, @a finish_cb proc will be - * invoked. - * - * @param h handle to the idp - * @param identity identity to access - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each attribute; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_AttributeIterator * -GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_AttributeResult proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls); - - -/** - * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start - * for the next record. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it); - - -/** - * Stops iteration and releases the idp handle for further calls. Must - * be called on any iteration that has not yet completed prior to calling - * #GNUNET_IDENTITY_PROVIDER_disconnect. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it); - - -/** - * Method called when a token has been issued. - * On success returns a ticket that can be given to the audience to retrive the - * token - * - * @param cls closure - * @param ticket the ticket - */ -typedef void -(*GNUNET_IDENTITY_PROVIDER_TicketCallback)(void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket); - -/** - * Issues a ticket to another identity. The identity may use - * GNUNET_IDENTITY_PROVIDER_ticket_consume to consume the ticket - * and retrieve the attributes specified in the AttributeList. - * - * @param h the identity provider to use - * @param iss the issuing identity - * @param rp the subject of the ticket (the relying party) - * @param attrs the attributes that the relying party is given access to - * @param cb the callback - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, - const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, - const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, - GNUNET_IDENTITY_PROVIDER_TicketCallback cb, - void *cb_cls); - -/** - * Revoked an issued ticket. The relying party will be unable to retrieve - * updated attributes. - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param ticket the ticket to revoke - * @param cb the callback - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb, - void *cb_cls); - - - -/** - * Consumes an issued ticket. The ticket is persisted - * and used to retrieve identity information from the issuer - * - * @param h the identity provider to use - * @param identity the identity that is the subject of the issued ticket (the audience) - * @param ticket the issued ticket to consume - * @param cb the callback to call - * @param cb_cls the callback closure - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - GNUNET_IDENTITY_PROVIDER_AttributeResult cb, - void *cb_cls); - -/** - * Lists all tickets that have been issued to remote - * identites (relying parties) - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each ticket; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_TicketIterator * -GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_TicketCallback proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls); - -/** - * Lists all tickets that have been issued to remote - * identites (relying parties) - * - * @param h the identity provider to use - * @param identity the issuing identity - * @param error_cb function to call on error (i.e. disconnect), - * the handle is afterwards invalid - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each ticket; it - * will be called repeatedly with a value (if available) - * @param proc_cls closure for @a proc - * @param finish_cb function to call on completion - * the handle is afterwards invalid - * @param finish_cb_cls closure for @a finish_cb - * @return an iterator handle to use for iteration - */ -struct GNUNET_IDENTITY_PROVIDER_TicketIterator * -GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h, - const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - GNUNET_SCHEDULER_TaskCallback error_cb, - void *error_cb_cls, - GNUNET_IDENTITY_PROVIDER_TicketCallback proc, - void *proc_cls, - GNUNET_SCHEDULER_TaskCallback finish_cb, - void *finish_cb_cls); - -/** - * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start - * for the next record. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it); - -/** - * Stops iteration and releases the idp handle for further calls. Must - * be called on any iteration that has not yet completed prior to calling - * #GNUNET_IDENTITY_PROVIDER_disconnect. - * - * @param it the iterator - */ -void -GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it); - -/** - * Disconnect from identity provider service. - * - * @param h identity provider service to disconnect - */ -void -GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h); - - -/** - * Cancel an identity provider operation. Note that the operation MAY still - * be executed; this merely cancels the continuation; if the request - * was already transmitted, the service may still choose to complete - * the operation. - * - * @param op operation to cancel - */ -void -GNUNET_IDENTITY_PROVIDER_cancel (struct GNUNET_IDENTITY_PROVIDER_Operation *op); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - - -/* ifndef GNUNET_IDENTITY_PROVIDER_SERVICE_H */ -#endif - -/** @} */ /* end of group identity */ - -/* end of gnunet_identity_provider_service.h */ diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 36aa424b4..4400db7e1 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2656,35 +2656,35 @@ extern "C" * * IDENTITY PROVIDER MESSAGE TYPES */ -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE 961 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE 961 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE 962 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE 962 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START 963 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START 963 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP 964 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP 964 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT 965 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT 965 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT 966 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT 966 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET 967 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET 967 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT 968 +#define GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT 968 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET 969 +#define GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET 969 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT 970 +#define GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT 970 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET 971 +#define GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET 971 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT 972 +#define GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT 972 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START 973 +#define GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START 973 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP 974 +#define GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP 974 -#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT 975 +#define GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT 975 /************************************************** * diff --git a/src/include/gnunet_reclaim_attribute_lib.h b/src/include/gnunet_reclaim_attribute_lib.h new file mode 100644 index 000000000..df5356d76 --- /dev/null +++ b/src/include/gnunet_reclaim_attribute_lib.h @@ -0,0 +1,281 @@ +/* + This file is part of GNUnet. + Copyright (C) 2017 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @author Martin Schanzenbach + * + * @file + * Identity attribute definitions + * + * @defgroup identity-provider Identity Provider service + * @{ + */ +#ifndef GNUNET_RECLAIM_ATTRIBUTE_LIB_H +#define GNUNET_RECLAIM_ATTRIBUTE_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" + + +/** + * No value attribute. + */ +#define GNUNET_RECLAIM_ATTRIBUTE_TYPE_NONE 0 + +/** + * String attribute. + */ +#define GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING 1 + + + +/** + * An attribute. + */ +struct GNUNET_RECLAIM_ATTRIBUTE_Claim +{ + /** + * The name of the attribute. Note "name" must never be individually + * free'd + */ + const char* name; + + /** + * Type of Claim + */ + uint32_t type; + + /** + * Version + */ + uint32_t version; + + /** + * Number of bytes in @e data. + */ + size_t data_size; + + /** + * Binary value stored as attribute value. Note: "data" must never + * be individually 'malloc'ed, but instead always points into some + * existing data area. + */ + const void *data; + +}; + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList +{ + /** + * List head + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *list_head; + + /** + * List tail + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *list_tail; +}; + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry +{ + /** + * DLL + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *prev; + + /** + * DLL + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *next; + + /** + * The attribute claim + */ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; +}; + +/** + * Create a new attribute claim. + * + * @param attr_name the attribute name + * @param type the attribute type + * @param data the attribute value + * @param data_size the attribute value size + * @return the new attribute + */ +struct GNUNET_RECLAIM_ATTRIBUTE_Claim * +GNUNET_RECLAIM_ATTRIBUTE_claim_new (const char* attr_name, + uint32_t type, + const void* data, + size_t data_size); + + +/** + * Get required size for serialization buffer + * + * @param attrs the attribute list to serialize + * + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + +void +GNUNET_RECLAIM_ATTRIBUTE_list_destroy (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + +void +GNUNET_RECLAIM_ATTRIBUTE_list_add (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const char* attr_name, + uint32_t type, + const void* data, + size_t data_size); + +/** + * Serialize an attribute list + * + * @param attrs the attribute list to serialize + * @param result the serialized attribute + * + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTRIBUTE_list_serialize (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + char *result); + +/** + * Deserialize an attribute list + * + * @param data the serialized attribute list + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_AttributeList, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList * +GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (const char* data, + size_t data_size); + + +/** + * Get required size for serialization buffer + * + * @param attr the attribute to serialize + * + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr); + + + +/** + * Serialize an attribute + * + * @param attr the attribute to serialize + * @param result the serialized attribute + * + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTRIBUTE_serialize (const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + char *result); + +/** + * Deserialize an attribute + * + * @param data the serialized attribute + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTRIBUTE_Claim * +GNUNET_RECLAIM_ATTRIBUTE_deserialize (const char* data, + size_t data_size); + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList* +GNUNET_RECLAIM_ATTRIBUTE_list_dup (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + +/** + * Convert a type name to the corresponding number + * + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +uint32_t +GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (const char *typename); + +/** + * Convert human-readable version of a 'claim' of an attribute to the binary + * representation + * + * @param type type of the claim + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +int +GNUNET_RECLAIM_ATTRIBUTE_string_to_value (uint32_t type, + const char *s, + void **data, + size_t *data_size); + +/** + * Convert the 'claim' of an attribute to a string + * + * @param type the type of attribute + * @param data claim in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the claim + */ +char * +GNUNET_RECLAIM_ATTRIBUTE_value_to_string (uint32_t type, + const void* data, + size_t data_size); + +/** + * Convert a type number to the corresponding type string + * + * @param type number of a type + * @return corresponding typestring, NULL on error + */ +const char* +GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (uint32_t type); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_RECLAIM_ATTRIBUTE_LIB_H */ +#endif + +/** @} */ /* end of group identity */ + +/* end of gnunet_reclaim_attribute_lib.h */ diff --git a/src/include/gnunet_reclaim_attribute_plugin.h b/src/include/gnunet_reclaim_attribute_plugin.h new file mode 100644 index 000000000..cf0bb141a --- /dev/null +++ b/src/include/gnunet_reclaim_attribute_plugin.h @@ -0,0 +1,147 @@ +/* + This file is part of GNUnet + Copyright (C) 2012, 2013 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @author Martin Schanzenbach + * + * @file + * Plugin API for the idp database backend + * + * @defgroup identity-provider-plugin IdP service plugin API + * Plugin API for the idp database backend + * @{ + */ +#ifndef GNUNET_RECLAIM_ATTRIBUTE_PLUGIN_H +#define GNUNET_RECLAIM_ATTRIBUTE_PLUGIN_H + +#include "gnunet_util_lib.h" +#include "gnunet_reclaim_attribute_lib.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Function called to convert the binary value @a data of an attribute of + * type @a type to a human-readable string. + * + * @param cls closure + * @param type type of the attribute + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +typedef char * (*GNUNET_RECLAIM_ATTRIBUTE_ValueToStringFunction) (void *cls, + uint32_t type, + const void *data, + size_t data_size); + + +/** + * Function called to convert human-readable version of the value @a s + * of an attribute of type @a type to the respective binary + * representation. + * + * @param cls closure + * @param type type of the attribute + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +typedef int (*GNUNET_RECLAIM_ATTRIBUTE_StringToValueFunction) (void *cls, + uint32_t type, + const char *s, + void **data, + size_t *data_size); + + +/** + * Function called to convert a type name to the + * corresponding number. + * + * @param cls closure + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +typedef uint32_t (*GNUNET_RECLAIM_ATTRIBUTE_TypenameToNumberFunction) (void *cls, + const char *typename); + + +/** + * Function called to convert a type number (i.e. 1) to the + * corresponding type string + * + * @param cls closure + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +typedef const char * (*GNUNET_RECLAIM_ATTRIBUTE_NumberToTypenameFunction) (void *cls, + uint32_t type); + + +/** + * Each plugin is required to return a pointer to a struct of this + * type as the return value from its entry point. + */ +struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions +{ + + /** + * Closure for all of the callbacks. + */ + void *cls; + + /** + * Conversion to string. + */ + GNUNET_RECLAIM_ATTRIBUTE_ValueToStringFunction value_to_string; + + /** + * Conversion to binary. + */ + GNUNET_RECLAIM_ATTRIBUTE_StringToValueFunction string_to_value; + + /** + * Typename to number. + */ + GNUNET_RECLAIM_ATTRIBUTE_TypenameToNumberFunction typename_to_number; + + /** + * Number to typename. + */ + GNUNET_RECLAIM_ATTRIBUTE_NumberToTypenameFunction number_to_typename; + +}; + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ /* end of group */ diff --git a/src/include/gnunet_reclaim_plugin.h b/src/include/gnunet_reclaim_plugin.h new file mode 100644 index 000000000..c400af64c --- /dev/null +++ b/src/include/gnunet_reclaim_plugin.h @@ -0,0 +1,121 @@ +/* + This file is part of GNUnet + Copyright (C) 2012, 2013 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @author Martin Schanzenbach + * + * @file + * Plugin API for the idp database backend + * + * @defgroup reclaim-plugin IdP service plugin API + * Plugin API for the idp database backend + * @{ + */ +#ifndef GNUNET_RECLAIM_PLUGIN_H +#define GNUNET_RECLAIM_PLUGIN_H + +#include "gnunet_util_lib.h" +#include "gnunet_reclaim_service.h" + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + + +/** + * Function called by for each matching ticket. + * + * @param cls closure + * @param ticket the ticket + */ +typedef void (*GNUNET_RECLAIM_TicketIterator) (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct GNUNET_RECLAIM_PluginFunctions +{ + + /** + * Closure to pass to all plugin functions. + */ + void *cls; + + /** + * Store a ticket in the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to store + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ + int (*store_ticket) (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + + /** + * Delete a ticket from the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to store + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ + int (*delete_ticket) (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket); + + + + /** + * Iterate over all tickets + * + * @param cls closure (internal context for the plugin) + * @param identity the identity + * @param audience GNUNET_YES if the identity is the audience of the ticket + * else it is considered the issuer + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ + int (*iterate_tickets) (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + int audience, + uint64_t offset, + GNUNET_RECLAIM_TicketIterator iter, void *iter_cls); + + int (*get_ticket_attributes) (void* cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_TicketIterator iter, + void *iter_cls); +}; + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ /* end of group */ diff --git a/src/include/gnunet_reclaim_service.h b/src/include/gnunet_reclaim_service.h new file mode 100644 index 000000000..7e668cd62 --- /dev/null +++ b/src/include/gnunet_reclaim_service.h @@ -0,0 +1,378 @@ +/* + This file is part of GNUnet. + Copyright (C) 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @author Martin Schanzenbach + * + * @file + * Identity provider service; implements identity provider for GNUnet + * + * @defgroup reclaim Identity Provider service + * @{ + */ +#ifndef GNUNET_RECLAIM_SERVICE_H +#define GNUNET_RECLAIM_SERVICE_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_util_lib.h" +#include "gnunet_reclaim_attribute_lib.h" + +/** + * Version number of GNUnet Identity Provider API. + */ +#define GNUNET_RECLAIM_VERSION 0x00000000 + +/** + * Handle to access the identity service. + */ +struct GNUNET_RECLAIM_Handle; + +/** + * Handle for a token. + */ +struct GNUNET_RECLAIM_Token; + +/** + * The ticket + */ +struct GNUNET_RECLAIM_Ticket +{ + /** + * The ticket issuer + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /** + * The ticket audience + */ + struct GNUNET_CRYPTO_EcdsaPublicKey audience; + + /** + * The ticket random (NBO) + */ + uint64_t rnd; +}; + +/** + * Handle for an operation with the identity provider service. + */ +struct GNUNET_RECLAIM_Operation; + + +/** + * Connect to the identity provider service. + * + * @param cfg Configuration to contact the identity provider service. + * @return handle to communicate with identity provider service + */ +struct GNUNET_RECLAIM_Handle * +GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) + * #GNUNET_NO if content was already there or not found + * #GNUNET_YES (or other positive value) on success + * @param emsg NULL on success, otherwise an error message + */ +typedef void +(*GNUNET_RECLAIM_ContinuationWithStatus) (void *cls, + int32_t success, + const char *emsg); + + +/** + * Store an attribute. If the attribute is already present, + * it is replaced with the new attribute. + * + * @param h handle to the identity provider + * @param pkey private key of the identity + * @param attr the attribute + * @param exp_interval the relative expiration interval for the attribute + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attribute_store (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls); + + +/** + * Process an attribute that was stored in the idp. + * + * @param cls closure + * @param identity the identity + * @param attr the attribute + */ +typedef void +(*GNUNET_RECLAIM_AttributeResult) (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr); + + + +/** + * List all attributes for a local identity. + * This MUST lock the `struct GNUNET_RECLAIM_Handle` + * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and + * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once + * immediately, and then again after + * #GNUNET_RECLAIM_get_attributes_next() is invoked. + * + * On error (disconnect), @a error_cb will be invoked. + * On normal completion, @a finish_cb proc will be + * invoked. + * + * @param h handle to the idp + * @param identity identity to access + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each attribute; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_AttributeIterator * +GNUNET_RECLAIM_get_attributes_start (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_AttributeResult proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls); + + +/** + * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it); + + +/** + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_RECLAIM_disconnect. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it); + + +/** + * Method called when a token has been issued. + * On success returns a ticket that can be given to the audience to retrive the + * token + * + * @param cls closure + * @param ticket the ticket + */ +typedef void +(*GNUNET_RECLAIM_TicketCallback)(void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket); + +/** + * Issues a ticket to another identity. The identity may use + * GNUNET_RECLAIM_ticket_consume to consume the ticket + * and retrieve the attributes specified in the AttributeList. + * + * @param h the identity provider to use + * @param iss the issuing identity + * @param rp the subject of the ticket (the relying party) + * @param attrs the attributes that the relying party is given access to + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_issue (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, + const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + GNUNET_RECLAIM_TicketCallback cb, + void *cb_cls); + +/** + * Revoked an issued ticket. The relying party will be unable to retrieve + * updated attributes. + * + * @param h the identity provider to use + * @param identity the issuing identity + * @param ticket the ticket to revoke + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_revoke (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_ContinuationWithStatus cb, + void *cb_cls); + + + +/** + * Consumes an issued ticket. The ticket is persisted + * and used to retrieve identity information from the issuer + * + * @param h the identity provider to use + * @param identity the identity that is the subject of the issued ticket (the audience) + * @param ticket the issued ticket to consume + * @param cb the callback to call + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_consume (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_AttributeResult cb, + void *cb_cls); + +/** + * Lists all tickets that have been issued to remote + * identites (relying parties) + * + * @param h the identity provider to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_TicketIterator * +GNUNET_RECLAIM_ticket_iteration_start (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls); + +/** + * Lists all tickets that have been issued to remote + * identites (relying parties) + * + * @param h the identity provider to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_TicketIterator * +GNUNET_RECLAIM_ticket_iteration_start_rp (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls); + +/** + * Calls the record processor specified in #GNUNET_RECLAIM_ticket_iteration_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it); + +/** + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_RECLAIM_disconnect. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it); + +/** + * Disconnect from identity provider service. + * + * @param h identity provider service to disconnect + */ +void +GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h); + + +/** + * Cancel an identity provider operation. Note that the operation MAY still + * be executed; this merely cancels the continuation; if the request + * was already transmitted, the service may still choose to complete + * the operation. + * + * @param op operation to cancel + */ +void +GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op); + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_RECLAIM_SERVICE_H */ +#endif + +/** @} */ /* end of group identity */ + +/* end of gnunet_reclaim_service.h */ diff --git a/src/reclaim-attribute/Makefile.am b/src/reclaim-attribute/Makefile.am new file mode 100644 index 000000000..7db2925b1 --- /dev/null +++ b/src/reclaim-attribute/Makefile.am @@ -0,0 +1,44 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + +lib_LTLIBRARIES = \ + libgnunetreclaimattribute.la + +libgnunetreclaimattribute_la_SOURCES = \ + reclaim_attribute.c +libgnunetreclaimattribute_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunetreclaimattribute_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +plugin_LTLIBRARIES = \ + libgnunet_plugin_reclaim_attribute_gnuid.la + + +libgnunet_plugin_reclaim_attribute_gnuid_la_SOURCES = \ + plugin_reclaim_attribute_gnuid.c +libgnunet_plugin_reclaim_attribute_gnuid_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_reclaim_attribute_gnuid_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + diff --git a/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c b/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c new file mode 100644 index 000000000..48afc0732 --- /dev/null +++ b/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c @@ -0,0 +1,182 @@ +/* + This file is part of GNUnet + Copyright (C) 2013, 2014, 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @file reclaim-attribute/plugin_reclaim_attribute_gnuid.c + * @brief identity attribute plugin to provide the API for fundamental + * attribute types. + * + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_reclaim_attribute_plugin.h" +#include + + +/** + * Convert the 'value' of an attribute to a string. + * + * @param cls closure, unused + * @param type type of the attribute + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +static char * +gnuid_value_to_string (void *cls, + uint32_t type, + const void *data, + size_t data_size) +{ + + switch (type) + { + case GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING: + return GNUNET_strndup (data, data_size); + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of an attribute to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the attribute + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +static int +gnuid_string_to_value (void *cls, + uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + if (NULL == s) + return GNUNET_SYSERR; + switch (type) + { + + case GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING: + *data = GNUNET_strdup (s); + *data_size = strlen (s); + return GNUNET_OK; + default: + return GNUNET_SYSERR; + } +} + + +/** + * Mapping of attribute type numbers to human-readable + * attribute type names. + */ +static struct { + const char *name; + uint32_t number; +} gnuid_name_map[] = { + { "STRING", GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING }, + { NULL, UINT32_MAX } +}; + + +/** + * Convert a type name to the corresponding number. + * + * @param cls closure, unused + * @param gnuid_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +gnuid_typename_to_number (void *cls, + const char *gnuid_typename) +{ + unsigned int i; + + i=0; + while ( (NULL != gnuid_name_map[i].name) && + (0 != strcasecmp (gnuid_typename, + gnuid_name_map[i].name)) ) + i++; + return gnuid_name_map[i].number; +} + + +/** + * Convert a type number (i.e. 1) to the corresponding type string + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +gnuid_number_to_typename (void *cls, + uint32_t type) +{ + unsigned int i; + + i=0; + while ( (NULL != gnuid_name_map[i].name) && + (type != gnuid_name_map[i].number) ) + i++; + return gnuid_name_map[i].name; +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_reclaim_attribute_gnuid_init (void *cls) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions *api; + + api = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions); + api->value_to_string = &gnuid_value_to_string; + api->string_to_value = &gnuid_string_to_value; + api->typename_to_number = &gnuid_typename_to_number; + api->number_to_typename = &gnuid_number_to_typename; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init() + * @return NULL + */ +void * +libgnunet_plugin_reclaim_attribute_gnuid_done (void *cls) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_reclaim_attribute_type_gnuid.c */ diff --git a/src/reclaim-attribute/reclaim_attribute.c b/src/reclaim-attribute/reclaim_attribute.c new file mode 100644 index 000000000..74d668ea8 --- /dev/null +++ b/src/reclaim-attribute/reclaim_attribute.c @@ -0,0 +1,444 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +/** + * @file reclaim-attribute/reclaim_attribute.c + * @brief helper library to manage identity attributes + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "reclaim_attribute.h" +#include "gnunet_reclaim_attribute_plugin.h" + +/** + * Handle for a plugin + */ +struct Plugin +{ + /** + * Name of the plugin + */ + char *library_name; + + /** + * Plugin API + */ + struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions *api; +}; + +/** + * Plugins + */ +static struct Plugin **attr_plugins; + +/** + * Number of plugins + */ +static unsigned int num_plugins; + +/** + * Init canary + */ +static int initialized; + +/** + * Add a plugin + */ +static void +add_plugin (void* cls, + const char *library_name, + void *lib_ret) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions *api = lib_ret; + struct Plugin *plugin; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Loading attribute plugin `%s'\n", + library_name); + plugin = GNUNET_new (struct Plugin); + plugin->api = api; + plugin->library_name = GNUNET_strdup (library_name); + GNUNET_array_append (attr_plugins, num_plugins, plugin); +} + +/** + * Load plugins + */ +static void +init() +{ + if (GNUNET_YES == initialized) + return; + initialized = GNUNET_YES; + GNUNET_PLUGIN_load_all ("libgnunet_plugin_reclaim_attribute_", NULL, + &add_plugin, NULL); +} + +/** + * Convert a type name to the corresponding number + * + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +uint32_t +GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (const char *typename) +{ + unsigned int i; + struct Plugin *plugin; + uint32_t ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (UINT32_MAX != (ret = plugin->api->typename_to_number (plugin->api->cls, + typename))) + return ret; + } + return UINT32_MAX; +} + +/** + * Convert a type number to the corresponding type string + * + * @param type number of a type + * @return corresponding typestring, NULL on error + */ +const char* +GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (uint32_t type) +{ + unsigned int i; + struct Plugin *plugin; + const char *ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != (ret = plugin->api->number_to_typename (plugin->api->cls, + type))) + return ret; + } + return NULL; +} + +/** + * Convert human-readable version of a 'claim' of an attribute to the binary + * representation + * + * @param type type of the claim + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +int +GNUNET_RECLAIM_ATTRIBUTE_string_to_value (uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + unsigned int i; + struct Plugin *plugin; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls, + type, + s, + data, + data_size)) + return GNUNET_OK; + } + return GNUNET_SYSERR; +} + +/** + * Convert the 'claim' of an attribute to a string + * + * @param type the type of attribute + * @param data claim in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the claim + */ +char * +GNUNET_RECLAIM_ATTRIBUTE_value_to_string (uint32_t type, + const void* data, + size_t data_size) +{ + unsigned int i; + struct Plugin *plugin; + char *ret; + + init(); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls, + type, + data, + data_size))) + return ret; + } + return NULL; +} + +/** + * Create a new attribute. + * + * @param attr_name the attribute name + * @param type the attribute type + * @param data the attribute value + * @param data_size the attribute value size + * @return the new attribute + */ +struct GNUNET_RECLAIM_ATTRIBUTE_Claim * +GNUNET_RECLAIM_ATTRIBUTE_claim_new (const char* attr_name, + uint32_t type, + const void* data, + size_t data_size) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr; + char *write_ptr; + + attr = GNUNET_malloc (sizeof (struct GNUNET_RECLAIM_ATTRIBUTE_Claim) + + strlen (attr_name) + 1 + + data_size); + attr->type = type; + attr->data_size = data_size; + attr->version = 0; + write_ptr = (char*)&attr[1]; + GNUNET_memcpy (write_ptr, + attr_name, + strlen (attr_name) + 1); + attr->name = write_ptr; + write_ptr += strlen (attr->name) + 1; + GNUNET_memcpy (write_ptr, + data, + data_size); + attr->data = write_ptr; + return attr; +} + +/** + * Add a new claim list entry. + * + * @param claim_list the attribute name + * @param attr_name the attribute name + * @param type the attribute type + * @param data the attribute value + * @param data_size the attribute value size + * @return + */ +void +GNUNET_RECLAIM_ATTRIBUTE_list_add (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *claim_list, + const char* attr_name, + uint32_t type, + const void* data, + size_t data_size) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name, + type, + data, + data_size); + GNUNET_CONTAINER_DLL_insert (claim_list->list_head, + claim_list->list_tail, + le); +} + +size_t +GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + size_t len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) + len += GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); + return len; +} + +size_t +GNUNET_RECLAIM_ATTRIBUTE_list_serialize (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + char *result) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + size_t len; + size_t total_len; + char* write_ptr; + + write_ptr = result; + total_len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) + { + len = GNUNET_RECLAIM_ATTRIBUTE_serialize (le->claim, + write_ptr); + total_len += len; + write_ptr += len; + } + return total_len; +} + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList * +GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (const char* data, + size_t data_size) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + size_t attr_len; + const char* read_ptr; + + if (data_size < sizeof (struct Attribute)) + return NULL; + + attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + read_ptr = data; + while (((data + data_size) - read_ptr) >= sizeof (struct Attribute)) + { + + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (read_ptr, + data_size - (read_ptr - data)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deserialized attribute %s\n", le->claim->name); + GNUNET_CONTAINER_DLL_insert (attrs->list_head, + attrs->list_tail, + le); + attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); + read_ptr += attr_len; + } + return attrs; +} + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList* +GNUNET_RECLAIM_ATTRIBUTE_list_dup (const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *result_le; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *result; + + result = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + for (le = attrs->list_head; NULL != le; le = le->next) + { + result_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + result_le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (le->claim->name, + le->claim->type, + le->claim->data, + le->claim->data_size); + GNUNET_CONTAINER_DLL_insert (result->list_head, + result->list_tail, + result_le); + } + return result; +} + + +void +GNUNET_RECLAIM_ATTRIBUTE_list_destroy (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *tmp_le; + + for (le = attrs->list_head; NULL != le;) + { + GNUNET_free (le->claim); + tmp_le = le; + le = le->next; + GNUNET_free (tmp_le); + } + GNUNET_free (attrs); + +} + +size_t +GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + return sizeof (struct Attribute) + + strlen (attr->name) + + attr->data_size; +} + +size_t +GNUNET_RECLAIM_ATTRIBUTE_serialize (const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + char *result) +{ + size_t data_len_ser; + size_t name_len; + struct Attribute *attr_ser; + char* write_ptr; + + attr_ser = (struct Attribute*)result; + attr_ser->attribute_type = htons (attr->type); + attr_ser->attribute_version = htonl (attr->version); + name_len = strlen (attr->name); + attr_ser->name_len = htons (name_len); + write_ptr = (char*)&attr_ser[1]; + GNUNET_memcpy (write_ptr, attr->name, name_len); + write_ptr += name_len; + //TODO plugin-ize + //data_len_ser = plugin->serialize_attribute_value (attr, + // &attr_ser[1]); + data_len_ser = attr->data_size; + GNUNET_memcpy (write_ptr, attr->data, attr->data_size); + attr_ser->data_size = htons (data_len_ser); + + return sizeof (struct Attribute) + strlen (attr->name) + attr->data_size; +} + +struct GNUNET_RECLAIM_ATTRIBUTE_Claim * +GNUNET_RECLAIM_ATTRIBUTE_deserialize (const char* data, + size_t data_size) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr; + struct Attribute *attr_ser; + size_t data_len; + size_t name_len; + char* write_ptr; + + if (data_size < sizeof (struct Attribute)) + return NULL; + + attr_ser = (struct Attribute*)data; + data_len = ntohs (attr_ser->data_size); + name_len = ntohs (attr_ser->name_len); + attr = GNUNET_malloc (sizeof (struct GNUNET_RECLAIM_ATTRIBUTE_Claim) + + data_len + name_len + 1); + attr->type = ntohs (attr_ser->attribute_type); + attr->version = ntohl (attr_ser->attribute_version); + attr->data_size = ntohs (attr_ser->data_size); + + write_ptr = (char*)&attr[1]; + GNUNET_memcpy (write_ptr, + &attr_ser[1], + name_len); + write_ptr[name_len] = '\0'; + attr->name = write_ptr; + + write_ptr += name_len + 1; + GNUNET_memcpy (write_ptr, + (char*)&attr_ser[1] + name_len, + attr->data_size); + attr->data = write_ptr; + return attr; + +} + +/* end of reclaim_attribute.c */ diff --git a/src/reclaim-attribute/reclaim_attribute.h b/src/reclaim-attribute/reclaim_attribute.h new file mode 100644 index 000000000..746d32980 --- /dev/null +++ b/src/reclaim-attribute/reclaim_attribute.h @@ -0,0 +1,54 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @file reclaim-attribute/reclaim_attribute.h + * @brief GNUnet reclaim identity attributes + * + */ +#ifndef RECLAIM_ATTRIBUTE_H +#define RECLAIM_ATTRIBUTE_H + +#include "gnunet_reclaim_service.h" + +struct Attribute +{ + /** + * Attribute type + */ + uint32_t attribute_type; + + /** + * Attribute version + */ + uint32_t attribute_version; + + /** + * Name length + */ + uint32_t name_len; + + /** + * Data size + */ + uint32_t data_size; + + //followed by data_size Attribute value data +}; + +#endif diff --git a/src/reclaim/.gitignore b/src/reclaim/.gitignore new file mode 100644 index 000000000..ef77fccdc --- /dev/null +++ b/src/reclaim/.gitignore @@ -0,0 +1,2 @@ +gnunet-service-identity-provider +gnunet-identity-token diff --git a/src/reclaim/Makefile.am b/src/reclaim/Makefile.am new file mode 100644 index 000000000..c13c68763 --- /dev/null +++ b/src/reclaim/Makefile.am @@ -0,0 +1,140 @@ +# 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 + +if HAVE_SQLITE +SQLITE_PLUGIN = libgnunet_plugin_reclaim_sqlite.la +endif + +EXTRA_DIST = \ + test_reclaim_defaults.conf \ + test_reclaim.conf \ + $(check_SCRIPTS) + +pkgcfgdir= $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + +pkgcfg_DATA = \ + reclaim.conf + +lib_LTLIBRARIES = \ + libgnunetidentityprovider.la +plugin_LTLIBRARIES = \ + libgnunet_plugin_rest_reclaim.la \ + libgnunet_plugin_rest_openid_connect.la \ + libgnunet_plugin_gnsrecord_reclaim.la \ + $(SQLITE_PLUGIN) + +bin_PROGRAMS = \ + gnunet-reclaim + +libexec_PROGRAMS = \ + gnunet-service-reclaim + +libgnunet_plugin_gnsrecord_reclaim_la_SOURCES = \ + plugin_gnsrecord_reclaim.c +libgnunet_plugin_gnsrecord_reclaim_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_gnsrecord_reclaim_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_reclaim_sqlite_la_SOURCES = \ + plugin_reclaim_sqlite.c +libgnunet_plugin_reclaim_sqlite_la_LIBADD = \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/sq/libgnunetsq.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ + $(LTLIBINTL) +libgnunet_plugin_reclaim_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + + +gnunet_service_reclaim_SOURCES = \ + gnunet-service-reclaim.c +gnunet_service_reclaim_LDADD = \ + $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/abe/libgnunetabe.la \ + $(top_builddir)/src/credential/libgnunetcredential.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(GN_LIBINTL) + +libgnunetidentityprovider_la_SOURCES = \ + reclaim_api.c \ + reclaim.h +libgnunetidentityprovider_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetidentityprovider_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + +libgnunet_plugin_rest_reclaim_la_SOURCES = \ + plugin_rest_reclaim.c \ + jwt.c +libgnunet_plugin_rest_reclaim_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_reclaim_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_rest_openid_connect_la_SOURCES = \ + plugin_rest_openid_connect.c \ + jwt.c +libgnunet_plugin_rest_openid_connect_la_LIBADD = \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_openid_connect_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +gnunet_reclaim_SOURCES = \ + gnunet-reclaim.c +gnunet_reclaim_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/reclaim-attribute/libgnunetreclaimattribute.la \ + $(GN_LIBINTL) + +check_SCRIPTS = \ + test_reclaim_attribute.sh \ + test_reclaim_issue.sh \ + test_reclaim_consume.sh \ + test_reclaim_revoke.sh + +if ENABLE_TEST_RUN + AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; + TESTS = $(check_SCRIPTS) +endif diff --git a/src/reclaim/gnunet-reclaim.c b/src/reclaim/gnunet-reclaim.c new file mode 100644 index 000000000..9947eac6d --- /dev/null +++ b/src/reclaim/gnunet-reclaim.c @@ -0,0 +1,517 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @file src/reclaim/gnunet-reclaim.c + * @brief Identity Provider utility + * + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_identity_service.h" +#include "gnunet_signatures.h" + +/** + * return value + */ +static int ret; + +/** + * List attribute flag + */ +static int list; + +/** + * Relying party + */ +static char* rp; + +/** + * The attribute + */ +static char* attr_name; + +/** + * Attribute value + */ +static char* attr_value; + +/** + * Attributes to issue + */ +static char* issue_attrs; + +/** + * Ticket to consume + */ +static char* consume_ticket; + +/** + * Attribute type + */ +static char* type_str; + +/** + * Ticket to revoke + */ +static char* revoke_ticket; + +/** + * Ego name + */ +static char* ego_name; + +/** + * Identity handle + */ +static struct GNUNET_IDENTITY_Handle *identity_handle; + +/** + * reclaim handle + */ +static struct GNUNET_RECLAIM_Handle *reclaim_handle; + +/** + * reclaim operation + */ +static struct GNUNET_RECLAIM_Operation *reclaim_op; + +/** + * Attribute iterator + */ +static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator; + +/** + * Master ABE key + */ +static struct GNUNET_CRYPTO_AbeMasterKey *abe_key; + +/** + * ego private key + */ +static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey; + +/** + * rp public key + */ +static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key; + +/** + * Ticket to consume + */ +static struct GNUNET_RECLAIM_Ticket ticket; + +/** + * Attribute list + */ +static struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + +/** + * Attribute expiration interval + */ +static struct GNUNET_TIME_Relative exp_interval; + +/** + * Timeout task + */ +static struct GNUNET_SCHEDULER_Task *timeout; + +static void +do_cleanup(void *cls) +{ + if (NULL != timeout) + GNUNET_SCHEDULER_cancel (timeout); + if (NULL != reclaim_op) + GNUNET_RECLAIM_cancel (reclaim_op); + if (NULL != attr_iterator) + GNUNET_RECLAIM_get_attributes_stop (attr_iterator); + if (NULL != reclaim_handle) + GNUNET_RECLAIM_disconnect (reclaim_handle); + if (NULL != identity_handle) + GNUNET_IDENTITY_disconnect (identity_handle); + if (NULL != abe_key) + GNUNET_free (abe_key); + if (NULL != attr_list) + GNUNET_free (attr_list); +} + +static void +ticket_issue_cb (void* cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + char* ticket_str; + reclaim_op = NULL; + if (NULL != ticket) { + ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + printf("%s\n", + ticket_str); + GNUNET_free (ticket_str); + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +store_attr_cont (void *cls, + int32_t success, + const char*emsg) +{ + reclaim_op = NULL; + if (GNUNET_SYSERR == success) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s\n", emsg); + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +process_attrs (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + char *value_str; + if (NULL == identity) + { + reclaim_op = NULL; + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); + return; + } + if (NULL == attr) + { + ret = 1; + return; + } + value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "%s: %s\n", attr->name, value_str); +} + + +static void +iter_error (void *cls) +{ + attr_iterator = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to iterate over attributes\n"); + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +timeout_task (void *cls) +{ + timeout = NULL; + ret = 1; + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Timeout\n"); + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +process_rvk (void *cls, int success, const char* msg) +{ + reclaim_op = NULL; + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Revocation failed.\n"); + ret = 1; + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +iter_finished (void *cls) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; + char *data; + size_t data_size; + int type; + + attr_iterator = NULL; + if (list) + { + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); + return; + } + + if (issue_attrs) + { + reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle, + pkey, + &rp_key, + attr_list, + &ticket_issue_cb, + NULL); + return; + } + if (consume_ticket) + { + reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle, + pkey, + &ticket, + &process_attrs, + NULL); + timeout = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), + &timeout_task, + NULL); + return; + } + if (revoke_ticket) + { + reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle, + pkey, + &ticket, + &process_rvk, + NULL); + return; + } + if (attr_name) + { + if (NULL == type_str) + type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING; + else + type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str); + + GNUNET_assert (GNUNET_SYSERR != GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type, + attr_value, + (void**)&data, + &data_size)); + claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name, + type, + data, + data_size); + reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle, + pkey, + claim, + &exp_interval, + &store_attr_cont, + NULL); + return; + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +iter_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + char *attrs_tmp; + char *attr_str; + + if (issue_attrs) + { + attrs_tmp = GNUNET_strdup (issue_attrs); + attr_str = strtok (attrs_tmp, ","); + while (NULL != attr_str) { + if (0 != strcmp (attr_str, attr->name)) { + attr_str = strtok (NULL, ","); + continue; + } + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, + attr->type, + attr->data, + attr->data_size); + GNUNET_CONTAINER_DLL_insert (attr_list->list_head, + attr_list->list_tail, + le); + break; + } + GNUNET_free (attrs_tmp); + } else if (list) { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "%s: %s\n", attr->name, (char*)attr->data); + } + GNUNET_RECLAIM_get_attributes_next (attr_iterator); +} + +static void +ego_iter_finished (void *cls) +{ + if (NULL == pkey) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Ego %s not found\n", ego_name); + return; + } + + if (NULL != rp) + GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, + strlen (rp), + &rp_key); + if (NULL != consume_ticket) + GNUNET_STRINGS_string_to_data (consume_ticket, + strlen (consume_ticket), + &ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + if (NULL != revoke_ticket) + GNUNET_STRINGS_string_to_data (revoke_ticket, + strlen (revoke_ticket), + &ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + + + attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + + attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle, + pkey, + &iter_error, + NULL, + &iter_cb, + NULL, + &iter_finished, + NULL); + + +} + +static int init = GNUNET_YES; + +static void +ego_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + if (NULL == name) { + if (GNUNET_YES == init) { + init = GNUNET_NO; + GNUNET_SCHEDULER_add_now (&ego_iter_finished, NULL); + } + return; + } + if (0 != strcmp (name, ego_name)) + return; + pkey = GNUNET_IDENTITY_ego_get_private_key (ego); +} + + +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + ret = 0; + if (NULL == ego_name) + { + ret = 1; + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + _("Ego is required\n")); + return; + } + + if ( (NULL == attr_value) && (NULL != attr_name) ) + { + ret = 1; + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + _("Attribute value missing!\n")); + return; + } + + if ( (NULL == rp) && (NULL != issue_attrs) ) + { + ret = 1; + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + _("Requesting party key is required!\n")); + return; + } + + reclaim_handle = GNUNET_RECLAIM_connect (c); + //Get Ego + identity_handle = GNUNET_IDENTITY_connect (c, + &ego_cb, + NULL); + + +} + + +int +main(int argc, char *const argv[]) +{ + exp_interval = GNUNET_TIME_UNIT_HOURS; + struct GNUNET_GETOPT_CommandLineOption options[] = { + + GNUNET_GETOPT_option_string ('a', + "add", + NULL, + gettext_noop ("Add attribute"), + &attr_name), + + GNUNET_GETOPT_option_string ('V', + "value", + NULL, + gettext_noop ("Attribute value"), + &attr_value), + GNUNET_GETOPT_option_string ('e', + "ego", + NULL, + gettext_noop ("Ego"), + &ego_name), + GNUNET_GETOPT_option_string ('r', + "rp", + NULL, + gettext_noop ("Audience (relying party)"), + &rp), + GNUNET_GETOPT_option_flag ('D', + "dump", + gettext_noop ("List attributes for Ego"), + &list), + GNUNET_GETOPT_option_string ('i', + "issue", + NULL, + gettext_noop ("Issue a ticket"), + &issue_attrs), + GNUNET_GETOPT_option_string ('C', + "consume", + NULL, + gettext_noop ("Consume a ticket"), + &consume_ticket), + GNUNET_GETOPT_option_string ('R', + "revoke", + NULL, + gettext_noop ("Revoke a ticket"), + &revoke_ticket), + GNUNET_GETOPT_option_string ('t', + "type", + NULL, + gettext_noop ("Type of attribute"), + &type_str), + GNUNET_GETOPT_option_relative_time ('E', + "expiration", + NULL, + gettext_noop ("Expiration interval of the attribute"), + &exp_interval), + + GNUNET_GETOPT_OPTION_END + }; + if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "ct", + "ct", options, + &run, NULL)) + return 1; + else + return ret; +} diff --git a/src/reclaim/gnunet-service-reclaim.c b/src/reclaim/gnunet-service-reclaim.c new file mode 100644 index 000000000..bf8780a92 --- /dev/null +++ b/src/reclaim/gnunet-service-reclaim.c @@ -0,0 +1,2786 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @file src/reclaim/gnunet-service-reclaim.c + * @brief reclaim Service + * + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_identity_service.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_abe_lib.h" +#include "gnunet_credential_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_gns_service.h" +#include "gnunet_reclaim_plugin.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_signatures.h" +#include "reclaim.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 + +/** + * Standard token expiration time + */ +#define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS + +/** + * Identity handle + */ +static struct GNUNET_IDENTITY_Handle *identity_handle; + +/** + * Database handle + */ +static struct GNUNET_RECLAIM_PluginFunctions *TKT_database; + +/** + * Name of DB plugin + */ +static char *db_lib_name; + +/** + * Token expiration interval + */ +static struct GNUNET_TIME_Relative token_expiration_interval; + +/** + * Namestore handle + */ +static struct GNUNET_NAMESTORE_Handle *ns_handle; + +/** + * GNS handle + */ +static struct GNUNET_GNS_Handle *gns_handle; + +/** + * Credential handle + */ +static struct GNUNET_CREDENTIAL_Handle *credential_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; + + +/** + * Currently processed token + */ +static struct IdentityToken *token; + +/** + * Label for currently processed token + */ +static char* label; + +/** + * Scopes for processed token + */ +static char* scopes; + +/** + * Handle to the statistics service. + */ +static struct GNUNET_STATISTICS_Handle *stats; + +/** + * Our configuration. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * An idp client + */ +struct IdpClient; + +/** + * A ticket iteration operation. + */ +struct TicketIteration +{ + /** + * DLL + */ + struct TicketIteration *next; + + /** + * DLL + */ + struct TicketIteration *prev; + + /** + * Client which intiated this zone iteration + */ + struct IdpClient *client; + + /** + * Key of the identity we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /** + * Identity is audience + */ + uint32_t is_audience; + + /** + * The operation id fot the iteration in the response for the client + */ + uint32_t r_id; + + /** + * Offset of the iteration used to address next result of the + * iteration in the store + * + * Initialy set to 0 in handle_iteration_start + * Incremented with by every call to handle_iteration_next + */ + uint32_t offset; + +}; + + + +/** + * Callback after an ABE bootstrap + * + * @param cls closure + * @param abe_key the ABE key that exists or was created + */ +typedef void +(*AbeBootstrapResult) (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key); + + +struct AbeBootstrapHandle +{ + /** + * Function to call when finished + */ + AbeBootstrapResult proc; + + /** + * Callback closure + */ + char *proc_cls; + + /** + * Key of the zone we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Namestore Queue Entry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; +}; + +/** + * An attribute iteration operation. + */ +struct AttributeIterator +{ + /** + * Next element in the DLL + */ + struct AttributeIterator *next; + + /** + * Previous element in the DLL + */ + struct AttributeIterator *prev; + + /** + * IDP client which intiated this zone iteration + */ + struct IdpClient *client; + + /** + * Key of the zone we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; + + /** + * Namestore iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *ns_it; + + /** + * The operation id fot the zone iteration in the response for the client + */ + uint32_t request_id; + +}; + + + +/** + * An idp client + */ +struct IdpClient +{ + + /** + * The client + */ + struct GNUNET_SERVICE_Client *client; + + /** + * Message queue for transmission to @e client + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Head of the DLL of + * Attribute iteration operations in + * progress initiated by this client + */ + struct AttributeIterator *attr_iter_head; + + /** + * Tail of the DLL of + * Attribute iteration operations + * in progress initiated by this client + */ + struct AttributeIterator *attr_iter_tail; + + /** + * Head of DLL of ticket iteration ops + */ + struct TicketIteration *ticket_iter_head; + + /** + * Tail of DLL of ticket iteration ops + */ + struct TicketIteration *ticket_iter_tail; + + /** + * Head of DLL of ticket revocation ops + */ + struct TicketRevocationHandle *revoke_op_head; + + /** + * Tail of DLL of ticket revocation ops + */ + struct TicketRevocationHandle *revoke_op_tail; + + /** + * Head of DLL of ticket issue ops + */ + struct TicketIssueHandle *issue_op_head; + + /** + * Tail of DLL of ticket issue ops + */ + struct TicketIssueHandle *issue_op_tail; + + /** + * Head of DLL of ticket consume ops + */ + struct ConsumeTicketHandle *consume_op_head; + + /** + * Tail of DLL of ticket consume ops + */ + struct ConsumeTicketHandle *consume_op_tail; + + /** + * Head of DLL of attribute store ops + */ + struct AttributeStoreHandle *store_op_head; + + /** + * Tail of DLL of attribute store ops + */ + struct AttributeStoreHandle *store_op_tail; + +}; + +struct AttributeStoreHandle +{ + /** + * DLL + */ + struct AttributeStoreHandle *next; + + /** + * DLL + */ + struct AttributeStoreHandle *prev; + + /** + * Client connection + */ + struct IdpClient *client; + + /** + * Identity + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Identity pubkey + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; + + /** + * QueueEntry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * The attribute to store + */ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; + + /** + * The attribute expiration interval + */ + struct GNUNET_TIME_Relative exp; + + /** + * request id + */ + uint32_t r_id; +}; + + +/* Prototype */ +struct ParallelLookup; + +struct ConsumeTicketHandle +{ + /** + * DLL + */ + struct ConsumeTicketHandle *next; + + /** + * DLL + */ + struct ConsumeTicketHandle *prev; + + /** + * Client connection + */ + struct IdpClient *client; + + /** + * Ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * LookupRequest + */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /** + * Audience Key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Audience Key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; + + /** + * Lookup DLL + */ + struct ParallelLookup *parallel_lookups_head; + + /** + * Lookup DLL + */ + struct ParallelLookup *parallel_lookups_tail; + + /** + * Kill task + */ + struct GNUNET_SCHEDULER_Task *kill_task; + + /** + * The ABE key + */ + struct GNUNET_ABE_AbeKey *key; + + /** + * Attributes + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + + /** + * Lookup time + */ + struct GNUNET_TIME_Absolute lookup_start_time; + + /** + * request id + */ + uint32_t r_id; +}; + +/** + * Handle for a parallel GNS lookup job + */ +struct ParallelLookup +{ + /* DLL */ + struct ParallelLookup *next; + + /* DLL */ + struct ParallelLookup *prev; + + /* The GNS request */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /* The handle the return to */ + struct ConsumeTicketHandle *handle; + + /** + * Lookup time + */ + struct GNUNET_TIME_Absolute lookup_start_time; + + /* The label to look up */ + char *label; +}; + +/** + * Ticket revocation request handle + */ +struct TicketRevocationHandle +{ + /** + * DLL + */ + struct TicketRevocationHandle *prev; + + /** + * DLL + */ + struct TicketRevocationHandle *next; + + /** + * Client connection + */ + struct IdpClient *client; + + /** + * Attributes to reissue + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + + /** + * Attributes to revoke + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *rvk_attrs; + + /** + * Issuer Key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Ticket to issue + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * QueueEntry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * Namestore iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *ns_it; + + /** + * The ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; + + /** + * Offset + */ + uint32_t offset; + + /** + * request id + */ + uint32_t r_id; +}; + + + +/** + * Ticket issue request handle + */ +struct TicketIssueHandle +{ + /** + * DLL + */ + struct TicketIssueHandle *prev; + + /** + * DLL + */ + struct TicketIssueHandle *next; + + /** + * Client connection + */ + struct IdpClient *client; + + /** + * Attributes to issue + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + + /** + * Issuer Key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Ticket to issue + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * QueueEntry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * request id + */ + uint32_t r_id; +}; + + +/** + * 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; + +}; + +/** + * Cleanup task + */ +static void +cleanup() +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + + if (NULL != stats) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, + TKT_database)); + GNUNET_free (db_lib_name); + db_lib_name = NULL; + 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 != gns_handle) + GNUNET_GNS_disconnect (gns_handle); + if (NULL != credential_handle) + GNUNET_CREDENTIAL_disconnect (credential_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); + GNUNET_free_non_null (token); + GNUNET_free_non_null (label); + +} + +/** + * Shutdown task + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutting down...\n"); + cleanup(); +} + +/** + * Finished storing newly bootstrapped ABE key + */ +static void +bootstrap_store_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct AbeBootstrapHandle *abh = cls; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to bootstrap ABE master %s\n", + emsg); + abh->proc (abh->proc_cls, NULL); + GNUNET_free (abh->abe_key); + GNUNET_free (abh); + return; + } + abh->proc (abh->proc_cls, abh->abe_key); + GNUNET_free (abh); +} + +/** + * Generates and stores a new ABE key + */ +static void +bootstrap_store_task (void *cls) +{ + struct AbeBootstrapHandle *abh = cls; + struct GNUNET_GNSRECORD_Data rd[1]; + char *key; + + rd[0].data_size = GNUNET_ABE_cpabe_serialize_master_key (abh->abe_key, + (void**)&key); + rd[0].data = key; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE; + rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane? + abh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &abh->identity, + "+", + 1, + rd, + &bootstrap_store_cont, + abh); + GNUNET_free (key); +} + +/** + * Error checking for ABE master + */ +static void +bootstrap_abe_error (void *cls) +{ + struct AbeBootstrapHandle *abh = cls; + abh->proc (abh->proc_cls, NULL); + GNUNET_free (abh); +} + + +/** + * Handle ABE lookup in namestore + */ +static void +bootstrap_abe_result (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct AbeBootstrapHandle *abh = cls; + struct GNUNET_ABE_AbeMasterKey *abe_key; + + for (uint32_t i=0;iproc (abh->proc_cls, abe_key); + GNUNET_free (abh); + return; + } + + //No ABE master found, bootstrapping... + abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); + GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); +} + +/** + * Bootstrap ABE master if it does not yet exists. + * Will call the AbeBootstrapResult processor when done. + * will always recreate the ABE key of GNUNET_YES == recreate + */ +static void +bootstrap_abe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + AbeBootstrapResult proc, + void* cls, + int recreate) +{ + struct AbeBootstrapHandle *abh; + + abh = GNUNET_new (struct AbeBootstrapHandle); + abh->proc = proc; + abh->proc_cls = cls; + abh->identity = *identity; + if (GNUNET_YES == recreate) + { + abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); + GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); + } else { + abh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, + identity, + "+", + &bootstrap_abe_error, + abh, + &bootstrap_abe_result, + abh); + } +} + + + +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_DEBUG, "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; +} + +/** + * Cleanup ticket consume handle + * @param handle the handle to clean up + */ +static void +cleanup_ticket_issue_handle (struct TicketIssueHandle *handle) +{ + if (NULL != handle->attrs) + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs); + if (NULL != handle->ns_qe) + GNUNET_NAMESTORE_cancel (handle->ns_qe); + GNUNET_free (handle); +} + + +static void +send_ticket_result (struct IdpClient *client, + uint32_t r_id, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketResultMessage *irm; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_RECLAIM_Ticket *ticket_buf; + + /* store ticket in DB */ + if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, + ticket, + attrs)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to store ticket after issue\n"); + GNUNET_break (0); + } + + env = GNUNET_MQ_msg_extra (irm, + sizeof (struct GNUNET_RECLAIM_Ticket), + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT); + ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1]; + *ticket_buf = *ticket; + irm->id = htonl (r_id); + GNUNET_MQ_send (client->mq, + env); +} + +static void +store_ticket_issue_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct TicketIssueHandle *handle = cls; + + handle->ns_qe = NULL; + GNUNET_CONTAINER_DLL_remove (handle->client->issue_op_head, + handle->client->issue_op_tail, + handle); + if (GNUNET_SYSERR == success) + { + cleanup_ticket_issue_handle (handle); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", + "Unknown Error\n"); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + send_ticket_result (handle->client, + handle->r_id, + &handle->ticket, + handle->attrs); + cleanup_ticket_issue_handle (handle); +} + + + +int +serialize_abe_keyinfo2 (const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_ABE_AbeKey *rp_key, + struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, + char **result) +{ + struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + char *enc_keyinfo; + char *serialized_key; + char *buf; + char *write_ptr; + char attrs_str_len; + ssize_t size; + + struct GNUNET_CRYPTO_SymmetricSessionKey skey; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + struct GNUNET_HashCode new_key_hash; + ssize_t enc_size; + + size = GNUNET_ABE_cpabe_serialize_key (rp_key, + (void**)&serialized_key); + attrs_str_len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) { + attrs_str_len += strlen (le->claim->name) + 1; + } + buf = GNUNET_malloc (attrs_str_len + size); + write_ptr = buf; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Writing attributes\n"); + for (le = attrs->list_head; NULL != le; le = le->next) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s\n", le->claim->name); + + + GNUNET_memcpy (write_ptr, + le->claim->name, + strlen (le->claim->name)); + write_ptr[strlen (le->claim->name)] = ','; + write_ptr += strlen (le->claim->name) + 1; + } + write_ptr--; + write_ptr[0] = '\0'; //replace last , with a 0-terminator + write_ptr++; + GNUNET_memcpy (write_ptr, + serialized_key, + size); + GNUNET_free (serialized_key); + // ECDH keypair E = eG + *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create(); + GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey, + &ecdh_pubkey); + enc_keyinfo = GNUNET_malloc (size + attrs_str_len); + // Derived key K = H(eB) + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey, + &ticket->audience, + &new_key_hash)); + create_sym_key_from_ecdh(&new_key_hash, &skey, &iv); + enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf, + size + attrs_str_len, + &skey, &iv, + enc_keyinfo); + *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+ + enc_size); + GNUNET_memcpy (*result, + &ecdh_pubkey, + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + enc_keyinfo, + enc_size); + GNUNET_free (enc_keyinfo); + GNUNET_free (buf); + return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size; +} + + + +static void +issue_ticket_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct TicketIssueHandle *ih = cls; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; + struct GNUNET_GNSRECORD_Data code_record[1]; + struct GNUNET_ABE_AbeKey *rp_key; + char *code_record_data; + char **attrs; + char *label; + char *policy; + int attrs_len; + uint32_t i; + size_t code_record_len; + + //Create new ABE key for RP + attrs_len = 0; + for (le = ih->attrs->list_head; NULL != le; le = le->next) + attrs_len++; + attrs = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); + i = 0; + for (le = ih->attrs->list_head; NULL != le; le = le->next) { + GNUNET_asprintf (&policy, "%s_%lu", + le->claim->name, + le->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding attribute to key: %s\n", + policy); + attrs[i] = policy; + i++; + } + attrs[i] = NULL; + rp_key = GNUNET_ABE_cpabe_create_key (abe_key, + attrs); + + //TODO review this wireformat + code_record_len = serialize_abe_keyinfo2 (&ih->ticket, + ih->attrs, + rp_key, + &ecdhe_privkey, + &code_record_data); + code_record[0].data = code_record_data; + code_record[0].data_size = code_record_len; + code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; + code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; + code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + + label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, + sizeof (uint64_t)); + //Publish record + ih->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &ih->identity, + label, + 1, + code_record, + &store_ticket_issue_cont, + ih); + //for (; i > 0; i--) + // GNUNET_free (attrs[i-1]); + GNUNET_free (ecdhe_privkey); + GNUNET_free (label); + GNUNET_free (attrs); + GNUNET_free (code_record_data); + GNUNET_ABE_cpabe_delete_key (rp_key, + GNUNET_YES); + GNUNET_ABE_cpabe_delete_master_key (abe_key); +} + + +static int +check_issue_ticket_message(void *cls, + const struct IssueTicketMessage *im) +{ + uint16_t size; + + size = ntohs (im->header.size); + if (size <= sizeof (struct IssueTicketMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +static void +handle_issue_ticket_message (void *cls, + const struct IssueTicketMessage *im) +{ + struct TicketIssueHandle *ih; + struct IdpClient *idp = cls; + size_t attrs_len; + + ih = GNUNET_new (struct TicketIssueHandle); + attrs_len = ntohs (im->attr_len); + ih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len); + ih->r_id = ntohl (im->id); + ih->client = idp; + ih->identity = im->identity; + GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity, + &ih->ticket.identity); + ih->ticket.audience = im->rp; + ih->ticket.rnd = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, + UINT64_MAX); + GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, + idp->issue_op_tail, + ih); + bootstrap_abe (&ih->identity, &issue_ticket_after_abe_bootstrap, ih, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); + +} + +/********************************************************** + * Revocation + **********************************************************/ + +/** + * Cleanup revoke handle + * + * @param rh the ticket revocation handle + */ +static void +cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh) +{ + if (NULL != rh->attrs) + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->attrs); + if (NULL != rh->rvk_attrs) + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->rvk_attrs); + if (NULL != rh->abe_key) + GNUNET_ABE_cpabe_delete_master_key (rh->abe_key); + if (NULL != rh->ns_qe) + GNUNET_NAMESTORE_cancel (rh->ns_qe); + if (NULL != rh->ns_it) + GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it); + GNUNET_free (rh); +} + + +/** + * Send revocation result + * + * @param rh ticket revocation handle + * @param success GNUNET_OK if successful result + */ +static void +send_revocation_finished (struct TicketRevocationHandle *rh, + uint32_t success) +{ + struct GNUNET_MQ_Envelope *env; + struct RevokeTicketResultMessage *trm; + + GNUNET_break(TKT_database->delete_ticket (TKT_database->cls, + &rh->ticket)); + + env = GNUNET_MQ_msg (trm, + GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT); + trm->id = htonl (rh->r_id); + trm->success = htonl (success); + GNUNET_MQ_send (rh->client->mq, + env); + GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head, + rh->client->revoke_op_tail, + rh); +} + + +/** + * Process ticket from database + * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes + */ +static void +ticket_reissue_proc (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); + +static void +revocation_reissue_tickets (struct TicketRevocationHandle *rh); + + +static void reissue_next (void *cls) +{ + struct TicketRevocationHandle *rh = cls; + revocation_reissue_tickets (rh); +} + + +static void +reissue_ticket_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct TicketRevocationHandle *rh = cls; + + rh->ns_qe = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", + "Unknown Error\n"); + send_revocation_finished (rh, GNUNET_SYSERR); + cleanup_revoke_ticket_handle (rh); + return; + } + rh->offset++; + GNUNET_SCHEDULER_add_now (&reissue_next, rh); +} + + +/** + * Process ticket from database + * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes + */ +static void +ticket_reissue_proc (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketRevocationHandle *rh = cls; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le_rollover; + struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; + struct GNUNET_GNSRECORD_Data code_record[1]; + struct GNUNET_ABE_AbeKey *rp_key; + char *code_record_data; + char **attr_arr; + char *label; + char *policy; + int attrs_len; + uint32_t i; + int reissue_ticket; + size_t code_record_len; + + + if (NULL == ticket) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Iteration done\n"); + return; + } + + if (0 == memcmp (&ticket->audience, + &rh->ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Do not reissue for this identity.!\n"); + label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd, + sizeof (uint64_t)); + //Delete record + rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &rh->identity, + label, + 0, + NULL, + &reissue_ticket_cont, + rh); + + GNUNET_free (label); + return; + } + + /* + * Check if any attribute of this ticket intersects with a rollover attribute + */ + reissue_ticket = GNUNET_NO; + for (le = attrs->list_head; NULL != le; le = le->next) + { + for (le_rollover = rh->rvk_attrs->list_head; + NULL != le_rollover; + le_rollover = le_rollover->next) + { + if (0 == strcmp (le_rollover->claim->name, + le->claim->name)) + { + reissue_ticket = GNUNET_YES; + le->claim->version = le_rollover->claim->version; + } + } + } + + if (GNUNET_NO == reissue_ticket) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Skipping ticket.\n"); + + rh->offset++; + GNUNET_SCHEDULER_add_now (&reissue_next, rh); + + + return; + } + + //Create new ABE key for RP + attrs_len = 0; + + /* If this is the RP we want to revoke attributes of, the do so */ + + for (le = attrs->list_head; NULL != le; le = le->next) + attrs_len++; + attr_arr = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); + i = 0; + for (le = attrs->list_head; NULL != le; le = le->next) { + GNUNET_asprintf (&policy, "%s_%lu", + le->claim->name, + le->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Recreating key with %s\n", policy); + attr_arr[i] = policy; + i++; + } + attr_arr[i] = NULL; + rp_key = GNUNET_ABE_cpabe_create_key (rh->abe_key, + attr_arr); + + //TODO review this wireformat + code_record_len = serialize_abe_keyinfo2 (ticket, + attrs, + rp_key, + &ecdhe_privkey, + &code_record_data); + code_record[0].data = code_record_data; + code_record[0].data_size = code_record_len; + code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; + code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; + code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + + label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + //Publish record + rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &rh->identity, + label, + 1, + code_record, + &reissue_ticket_cont, + rh); + //for (; i > 0; i--) + // GNUNET_free (attr_arr[i-1]); + GNUNET_free (ecdhe_privkey); + GNUNET_free (label); + GNUNET_free (attr_arr); + GNUNET_free (code_record_data); + GNUNET_ABE_cpabe_delete_key (rp_key, GNUNET_YES); +} + + +/* Prototype for below function */ +static void +attr_reenc_cont (void *cls, + int32_t success, + const char *emsg); + +static void +revocation_reissue_tickets (struct TicketRevocationHandle *rh) +{ + int ret; + /* Done, issue new keys */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Revocation Phase III: Reissuing Tickets\n"); + if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls, + &rh->ticket.identity, + GNUNET_NO, + rh->offset, + &ticket_reissue_proc, + rh))) + { + GNUNET_break (0); + } + if (GNUNET_NO == ret) + { + send_revocation_finished (rh, GNUNET_OK); + cleanup_revoke_ticket_handle (rh); + return; + } +} + +/** + * Failed to check for attribute + */ +static void +check_attr_error (void *cls) +{ + struct TicketRevocationHandle *rh = cls; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to check for existing attribute\n"); + rh->ns_qe = NULL; + send_revocation_finished (rh, GNUNET_SYSERR); + cleanup_revoke_ticket_handle (rh); +} + + +/** + * Revoke next attribte by reencryption with + * new ABE master + */ +static void +reenc_next_attribute (void *cls); + +/** + * Check for existing attribute and overwrite + */ +static void +check_attr_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd_old) +{ + struct TicketRevocationHandle *rh = cls; + struct GNUNET_GNSRECORD_Data rd[1]; + char* buf; + char* enc_buf; + size_t enc_size; + char* rd_buf; + size_t buf_size; + char* policy; + uint32_t attr_ver; + + rh->ns_qe = NULL; + if (1 != rd_count) { + GNUNET_SCHEDULER_add_now (&reenc_next_attribute, + rh); + return; + } + + buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim); + buf = GNUNET_malloc (buf_size); + GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim, + buf); + rh->attrs->list_head->claim->version++; + GNUNET_asprintf (&policy, "%s_%lu", + rh->attrs->list_head->claim->name, + rh->attrs->list_head->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypting with policy %s\n", policy); + /** + * Encrypt the attribute value and store in namestore + */ + enc_size = GNUNET_ABE_cpabe_encrypt (buf, + buf_size, + policy, //Policy + rh->abe_key, + (void**)&enc_buf); + GNUNET_free (buf); + if (GNUNET_SYSERR == enc_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to re-encrypt with policy %s\n", + policy); + GNUNET_free (policy); + send_revocation_finished (rh, GNUNET_SYSERR); + cleanup_revoke_ticket_handle (rh); + return; + } + GNUNET_free (policy); + + rd[0].data_size = enc_size + sizeof (uint32_t); + rd_buf = GNUNET_malloc (rd[0].data_size); + attr_ver = htonl (rh->attrs->list_head->claim->version); + GNUNET_memcpy (rd_buf, + &attr_ver, + sizeof (uint32_t)); + GNUNET_memcpy (rd_buf+sizeof (uint32_t), + enc_buf, + enc_size); + rd[0].data = rd_buf; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd[0].expiration_time = rd_old[0].expiration_time; + rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &rh->identity, + rh->attrs->list_head->claim->name, + 1, + rd, + &attr_reenc_cont, + rh); + GNUNET_free (enc_buf); + GNUNET_free (rd_buf); +} + + +/** + * Revoke next attribte by reencryption with + * new ABE master + */ +static void +reenc_next_attribute (void *cls) +{ + struct TicketRevocationHandle *rh = cls; + if (NULL == rh->attrs->list_head) + { + revocation_reissue_tickets (rh); + return; + } + /* First check if attribute still exists */ + rh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, + &rh->identity, + rh->attrs->list_head->claim->name, + &check_attr_error, + rh, + &check_attr_cb, + rh); +} + + +/** + * Namestore callback after revoked attribute + * is stored + */ +static void +attr_reenc_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct TicketRevocationHandle *rh = cls; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + + rh->ns_qe = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to reencrypt attribute %s\n", + emsg); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + if (NULL == rh->attrs->list_head) + { + revocation_reissue_tickets (rh); + return; + } + le = rh->attrs->list_head; + GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head, + rh->attrs->list_tail, + le); + GNUNET_assert (NULL != rh->rvk_attrs); + GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head, + rh->rvk_attrs->list_tail, + le); + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Re-encrypting next attribute\n"); + reenc_next_attribute (rh); +} + + +static void +process_attributes_to_update (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketRevocationHandle *rh = cls; + + rh->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Revocation Phase I: Collecting attributes\n"); + /* Reencrypt all attributes with new key */ + if (NULL == rh->attrs->list_head) + { + /* No attributes to reencrypt */ + send_revocation_finished (rh, GNUNET_OK); + cleanup_revoke_ticket_handle (rh); + return; + } else { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Revocation Phase II: Re-encrypting attributes\n"); + reenc_next_attribute (rh); + } + +} + + + +static void +get_ticket_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished ABE bootstrap\n"); + struct TicketRevocationHandle *rh = cls; + rh->abe_key = abe_key; + TKT_database->get_ticket_attributes (TKT_database->cls, + &rh->ticket, + &process_attributes_to_update, + rh); +} + +static int +check_revoke_ticket_message(void *cls, + const struct RevokeTicketMessage *im) +{ + uint16_t size; + + size = ntohs (im->header.size); + if (size <= sizeof (struct RevokeTicketMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +static void +handle_revoke_ticket_message (void *cls, + const struct RevokeTicketMessage *rm) +{ + struct TicketRevocationHandle *rh; + struct IdpClient *idp = cls; + struct GNUNET_RECLAIM_Ticket *ticket; + + rh = GNUNET_new (struct TicketRevocationHandle); + ticket = (struct GNUNET_RECLAIM_Ticket*)&rm[1]; + rh->rvk_attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + rh->ticket = *ticket; + rh->r_id = ntohl (rm->id); + rh->client = idp; + rh->identity = rm->identity; + GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity, + &rh->ticket.identity); + GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, + idp->revoke_op_tail, + rh); + bootstrap_abe (&rh->identity, &get_ticket_after_abe_bootstrap, rh, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); + +} + +/** + * Cleanup ticket consume handle + * @param handle the handle to clean up + */ +static void +cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle) +{ + struct ParallelLookup *lu; + struct ParallelLookup *tmp; + if (NULL != handle->lookup_request) + GNUNET_GNS_lookup_cancel (handle->lookup_request); + for (lu = handle->parallel_lookups_head; + NULL != lu;) { + GNUNET_GNS_lookup_cancel (lu->lookup_request); + GNUNET_free (lu->label); + tmp = lu->next; + GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + lu); + GNUNET_free (lu); + lu = tmp; + } + + if (NULL != handle->key) + GNUNET_ABE_cpabe_delete_key (handle->key, + GNUNET_YES); + if (NULL != handle->attrs) + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs); + GNUNET_free (handle); +} + + + +static int +check_consume_ticket_message(void *cls, + const struct ConsumeTicketMessage *cm) +{ + uint16_t size; + + size = ntohs (cm->header.size); + if (size <= sizeof (struct ConsumeTicketMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +static void +process_parallel_lookup2 (void *cls, uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Parallel lookup finished (count=%u)\n", rd_count); + struct ParallelLookup *parallel_lookup = cls; + struct ConsumeTicketHandle *handle = parallel_lookup->handle; + struct ConsumeTicketResultMessage *crm; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le; + struct GNUNET_TIME_Absolute decrypt_duration; + char *data; + char *data_tmp; + ssize_t attr_len; + size_t attrs_len; + + GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + parallel_lookup); + GNUNET_free (parallel_lookup->label); + + GNUNET_STATISTICS_update (stats, + "attribute_lookup_time_total", + GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats, + "attribute_lookups_count", + 1, + GNUNET_YES); + + + GNUNET_free (parallel_lookup); + if (1 != rd_count) + GNUNET_break(0);//TODO + if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) + { + decrypt_duration = GNUNET_TIME_absolute_get (); + attr_len = GNUNET_ABE_cpabe_decrypt (rd->data + sizeof (uint32_t), + rd->data_size - sizeof (uint32_t), + handle->key, + (void**)&data); + if (GNUNET_SYSERR != attr_len) + { + GNUNET_STATISTICS_update (stats, + "abe_decrypt_time_total", + GNUNET_TIME_absolute_get_duration (decrypt_duration).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats, + "abe_decrypt_count", + 1, + GNUNET_YES); + + attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + attr_le->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (data, + attr_len); + attr_le->claim->version = ntohl(*(uint32_t*)rd->data); + GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head, + handle->attrs->list_tail, + attr_le); + GNUNET_free (data); + } + } + if (NULL != handle->parallel_lookups_head) + return; //Wait for more + /* Else we are done */ + + /* Store ticket in DB */ + if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, + &handle->ticket, + handle->attrs)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to store ticket after consume\n"); + GNUNET_break (0); + } + + GNUNET_SCHEDULER_cancel (handle->kill_task); + attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (handle->attrs); + env = GNUNET_MQ_msg_extra (crm, + attrs_len, + GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT); + crm->id = htonl (handle->r_id); + crm->attrs_len = htons (attrs_len); + crm->identity = handle->ticket.identity; + data_tmp = (char *) &crm[1]; + GNUNET_RECLAIM_ATTRIBUTE_list_serialize (handle->attrs, + data_tmp); + GNUNET_MQ_send (handle->client->mq, env); + GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head, + handle->client->consume_op_tail, + handle); + cleanup_consume_ticket_handle (handle); +} + +void +abort_parallel_lookups2 (void *cls) +{ + struct ConsumeTicketHandle *handle = cls; + struct ParallelLookup *lu; + struct ParallelLookup *tmp; + struct AttributeResultMessage *arm; + struct GNUNET_MQ_Envelope *env; + + handle->kill_task = NULL; + for (lu = handle->parallel_lookups_head; + NULL != lu;) { + GNUNET_GNS_lookup_cancel (lu->lookup_request); + GNUNET_free (lu->label); + tmp = lu->next; + GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + lu); + GNUNET_free (lu); + lu = tmp; + } + env = GNUNET_MQ_msg (arm, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT); + arm->id = htonl (handle->r_id); + arm->attr_len = htons (0); + GNUNET_MQ_send (handle->client->mq, env); + +} + + +static void +process_consume_abe_key (void *cls, uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct ConsumeTicketHandle *handle = cls; + struct GNUNET_HashCode new_key_hash; + struct GNUNET_CRYPTO_SymmetricSessionKey enc_key; + struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv; + struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key; + struct ParallelLookup *parallel_lookup; + size_t size; + char *buf; + char *scope; + + handle->lookup_request = NULL; + if (1 != rd_count) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Number of keys %d != 1.", + rd_count); + cleanup_consume_ticket_handle (handle); + GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head, + handle->client->consume_op_tail, + handle); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + + //Decrypt + ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data; + + buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + + //Calculate symmetric key from ecdh parameters + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity, + ecdh_key, + &new_key_hash)); + create_sym_key_from_ecdh (&new_key_hash, + &enc_key, + &enc_iv); + size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + &enc_key, + &enc_iv, + buf); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Decrypted bytes: %zd Expected bytes: %zd\n", + size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + GNUNET_STATISTICS_update (stats, + "abe_key_lookup_time_total", + GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats, + "abe_key_lookups_count", + 1, + GNUNET_YES); + scopes = GNUNET_strdup (buf); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scopes %s\n", scopes); + handle->key = GNUNET_ABE_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1), + rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + - strlen (scopes) - 1); + + for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ",")) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up %s\n", scope); + parallel_lookup = GNUNET_new (struct ParallelLookup); + parallel_lookup->handle = handle; + parallel_lookup->label = GNUNET_strdup (scope); + parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get(); + parallel_lookup->lookup_request + = GNUNET_GNS_lookup (gns_handle, + scope, + &handle->ticket.identity, + GNUNET_GNSRECORD_TYPE_ID_ATTR, + GNUNET_GNS_LO_DEFAULT, + &process_parallel_lookup2, + parallel_lookup); + GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + parallel_lookup); + } + GNUNET_free (scopes); + GNUNET_free (buf); + handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3), + &abort_parallel_lookups2, + handle); +} + + +static void +handle_consume_ticket_message (void *cls, + const struct ConsumeTicketMessage *cm) +{ + struct ConsumeTicketHandle *ch; + struct IdpClient *idp = cls; + char* rnd_label; + + ch = GNUNET_new (struct ConsumeTicketHandle); + ch->r_id = ntohl (cm->id); + ch->client = idp; + ch->identity = cm->identity; + ch->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity, + &ch->identity_pub); + ch->ticket = *((struct GNUNET_RECLAIM_Ticket*)&cm[1]); + rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd, + sizeof (uint64_t)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking for ABE key under %s\n", rnd_label); + ch->lookup_start_time = GNUNET_TIME_absolute_get (); + ch->lookup_request + = GNUNET_GNS_lookup (gns_handle, + rnd_label, + &ch->ticket.identity, + GNUNET_GNSRECORD_TYPE_ABE_KEY, + GNUNET_GNS_LO_DEFAULT, + &process_consume_abe_key, + ch); + GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, + idp->consume_op_tail, + ch); + GNUNET_free (rnd_label); + GNUNET_SERVICE_client_continue (idp->client); +} + +/** + * Cleanup attribute store handle + * + * @param handle handle to clean up + */ +static void +cleanup_as_handle (struct AttributeStoreHandle *handle) +{ + if (NULL != handle->ns_qe) + GNUNET_NAMESTORE_cancel (handle->ns_qe); + if (NULL != handle->claim) + GNUNET_free (handle->claim); + if (NULL != handle->abe_key) + GNUNET_ABE_cpabe_delete_master_key (handle->abe_key); + GNUNET_free (handle); +} + +static void +attr_store_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct AttributeStoreHandle *as_handle = cls; + struct GNUNET_MQ_Envelope *env; + struct AttributeStoreResultMessage *acr_msg; + + as_handle->ns_qe = NULL; + GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head, + as_handle->client->store_op_tail, + as_handle); + + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to store attribute %s\n", + emsg); + cleanup_as_handle (as_handle); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ATTRIBUTE_STORE_RESPONSE message\n"); + env = GNUNET_MQ_msg (acr_msg, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE); + acr_msg->id = htonl (as_handle->r_id); + acr_msg->op_result = htonl (GNUNET_OK); + GNUNET_MQ_send (as_handle->client->mq, + env); + cleanup_as_handle (as_handle); +} + +static void +attr_store_task (void *cls) +{ + struct AttributeStoreHandle *as_handle = cls; + struct GNUNET_GNSRECORD_Data rd[1]; + char* buf; + char* policy; + char* enc_buf; + char* rd_buf; + size_t enc_size; + size_t buf_size; + uint32_t attr_ver; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Storing attribute\n"); + buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (as_handle->claim); + buf = GNUNET_malloc (buf_size); + + GNUNET_RECLAIM_ATTRIBUTE_serialize (as_handle->claim, + buf); + + GNUNET_asprintf (&policy, + "%s_%lu", + as_handle->claim->name, + as_handle->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypting with policy %s\n", policy); + /** + * Encrypt the attribute value and store in namestore + */ + enc_size = GNUNET_ABE_cpabe_encrypt (buf, + buf_size, + policy, //Policy + as_handle->abe_key, + (void**)&enc_buf); + if (GNUNET_SYSERR == enc_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to encrypt with policy %s\n", + policy); + GNUNET_CONTAINER_DLL_remove (as_handle->client->store_op_head, + as_handle->client->store_op_tail, + as_handle); + + cleanup_as_handle (as_handle); + GNUNET_free (buf); + GNUNET_free (policy); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + GNUNET_free (buf); + GNUNET_free (policy); + rd[0].data_size = enc_size + sizeof (uint32_t); + rd_buf = GNUNET_malloc (rd[0].data_size); + attr_ver = htonl (as_handle->claim->version); + GNUNET_memcpy (rd_buf, + &attr_ver, + sizeof (uint32_t)); + GNUNET_memcpy (rd_buf+sizeof (uint32_t), + enc_buf, + enc_size); + rd[0].data = rd_buf; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd[0].expiration_time = as_handle->exp.rel_value_us; + as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &as_handle->identity, + as_handle->claim->name, + 1, + rd, + &attr_store_cont, + as_handle); + GNUNET_free (enc_buf); + GNUNET_free (rd_buf); +} + + +static void +store_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished ABE bootstrap\n"); + struct AttributeStoreHandle *ash = cls; + ash->abe_key = abe_key; + GNUNET_SCHEDULER_add_now (&attr_store_task, ash); +} + +static int +check_attribute_store_message(void *cls, + const struct AttributeStoreMessage *sam) +{ + uint16_t size; + + size = ntohs (sam->header.size); + if (size <= sizeof (struct AttributeStoreMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +static void +handle_attribute_store_message (void *cls, + const struct AttributeStoreMessage *sam) +{ + struct AttributeStoreHandle *as_handle; + struct IdpClient *idp = cls; + size_t data_len; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_STORE message\n"); + + data_len = ntohs (sam->attr_len); + + as_handle = GNUNET_new (struct AttributeStoreHandle); + as_handle->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&sam[1], + data_len); + + as_handle->r_id = ntohl (sam->id); + as_handle->identity = sam->identity; + as_handle->exp.rel_value_us = GNUNET_ntohll (sam->exp); + GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, + &as_handle->identity_pkey); + + GNUNET_SERVICE_client_continue (idp->client); + as_handle->client = idp; + GNUNET_CONTAINER_DLL_insert (idp->store_op_head, + idp->store_op_tail, + as_handle); + bootstrap_abe (&as_handle->identity, &store_after_abe_bootstrap, as_handle, GNUNET_NO); +} + +static void +cleanup_attribute_iter_handle (struct AttributeIterator *ai) +{ + if (NULL != ai->abe_key) + GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); + GNUNET_free (ai); +} + +static void +attr_iter_error (void *cls) +{ + struct AttributeIterator *ai = cls; + //TODO + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to iterate over attributes\n"); + GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head, + ai->client->attr_iter_tail, + ai); + cleanup_attribute_iter_handle (ai); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +static void +attr_iter_finished (void *cls) +{ + struct AttributeIterator *ai = cls; + struct GNUNET_MQ_Envelope *env; + struct AttributeResultMessage *arm; + + env = GNUNET_MQ_msg (arm, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (0); + GNUNET_MQ_send (ai->client->mq, env); + GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head, + ai->client->attr_iter_tail, + ai); + cleanup_attribute_iter_handle (ai); +} + +static void +attr_iter_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct AttributeIterator *ai = cls; + struct AttributeResultMessage *arm; + struct GNUNET_ABE_AbeKey *key; + struct GNUNET_MQ_Envelope *env; + ssize_t msg_extra_len; + char* attr_ser; + char* attrs[2]; + char* data_tmp; + char* policy; + uint32_t attr_ver; + + if (rd_count != 1) + { + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, + 1); + return; + } + + if (GNUNET_GNSRECORD_TYPE_ID_ATTR != rd->record_type) + { + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, + 1); + return; + } + attr_ver = ntohl(*((uint32_t*)rd->data)); + GNUNET_asprintf (&policy, "%s_%lu", + label, attr_ver); + attrs[0] = policy; + attrs[1] = 0; + key = GNUNET_ABE_cpabe_create_key (ai->abe_key, + attrs); + msg_extra_len = GNUNET_ABE_cpabe_decrypt (rd->data+sizeof (uint32_t), + rd->data_size-sizeof (uint32_t), + key, + (void**)&attr_ser); + if (GNUNET_SYSERR == msg_extra_len) + { + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, + 1); + return; + } + + GNUNET_ABE_cpabe_delete_key (key, + GNUNET_YES); + //GNUNET_free (policy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found attribute: %s\n", label); + env = GNUNET_MQ_msg_extra (arm, + msg_extra_len, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (msg_extra_len); + GNUNET_CRYPTO_ecdsa_key_get_public (zone, + &arm->identity); + data_tmp = (char *) &arm[1]; + GNUNET_memcpy (data_tmp, + attr_ser, + msg_extra_len); + GNUNET_MQ_send (ai->client->mq, env); + GNUNET_free (attr_ser); + GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); + ai->abe_key = NULL; +} + + +void +iterate_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct AttributeIterator *ai = cls; + ai->abe_key = abe_key; + ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, + &ai->identity, + &attr_iter_error, + ai, + &attr_iter_cb, + ai, + &attr_iter_finished, + ai); +} + + +static void +iterate_next_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct AttributeIterator *ai = cls; + ai->abe_key = abe_key; + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, + 1); +} + + + +static void +handle_iteration_start (void *cls, + const struct AttributeIterationStartMessage *ais_msg) +{ + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_ITERATION_START message\n"); + ai = GNUNET_new (struct AttributeIterator); + ai->request_id = ntohl (ais_msg->id); + ai->client = idp; + ai->identity = ais_msg->identity; + + GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, + idp->attr_iter_tail, + ai); + bootstrap_abe (&ai->identity, &iterate_after_abe_bootstrap, ai, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); +} + + +static void +handle_iteration_stop (void *cls, + const struct AttributeIterationStopMessage *ais_msg) +{ + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + uint32_t rid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' message\n", + "ATTRIBUTE_ITERATION_STOP"); + rid = ntohl (ais_msg->id); + for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next) + if (ai->request_id == rid) + break; + if (NULL == ai) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (idp->client); + return; + } + GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, + idp->attr_iter_tail, + ai); + GNUNET_free (ai); + GNUNET_SERVICE_client_continue (idp->client); +} + + +static void +handle_iteration_next (void *cls, + const struct AttributeIterationNextMessage *ais_msg) +{ + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + uint32_t rid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_ITERATION_NEXT message\n"); + rid = ntohl (ais_msg->id); + for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next) + if (ai->request_id == rid) + break; + if (NULL == ai) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (idp->client); + return; + } + bootstrap_abe (&ai->identity, + &iterate_next_after_abe_bootstrap, + ai, + GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); +} + +/** + * Ticket iteration processor result + */ +enum ZoneIterationResult +{ + /** + * Iteration start. + */ + IT_START = 0, + + /** + * Found tickets, + * Continue to iterate with next iteration_next call + */ + IT_SUCCESS_MORE_AVAILABLE = 1, + + /** + * Iteration complete + */ + IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2 +}; + + +/** + * Context for ticket iteration + */ +struct TicketIterationProcResult +{ + /** + * The ticket iteration handle + */ + struct TicketIteration *ti; + + /** + * Iteration result: iteration done? + * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but + * we got one for now and have sent it to the client + * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results, + * #IT_START: if we are still trying to find a result. + */ + int res_iteration_finished; + +}; + +static void +cleanup_ticket_iter_handle (struct TicketIteration *ti) +{ + GNUNET_free (ti); +} + +/** + * Process ticket from database + * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes + */ +static void +ticket_iterate_proc (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketIterationProcResult *proc = cls; + + if (NULL == ticket) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Iteration done\n"); + proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; + return; + } + proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE; + send_ticket_result (proc->ti->client, + proc->ti->r_id, + ticket, + attrs); + +} + +/** + * Perform ticket iteration step + * + * @param ti ticket iterator to process + */ +static void +run_ticket_iteration_round (struct TicketIteration *ti) +{ + struct TicketIterationProcResult proc; + struct GNUNET_MQ_Envelope *env; + struct TicketResultMessage *trm; + int ret; + + memset (&proc, 0, sizeof (proc)); + proc.ti = ti; + proc.res_iteration_finished = IT_START; + while (IT_START == proc.res_iteration_finished) + { + if (GNUNET_SYSERR == + (ret = TKT_database->iterate_tickets (TKT_database->cls, + &ti->identity, + ti->is_audience, + ti->offset, + &ticket_iterate_proc, + &proc))) + { + GNUNET_break (0); + break; + } + if (GNUNET_NO == ret) + proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; + ti->offset++; + } + if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "More results available\n"); + return; /* more later */ + } + /* send empty response to indicate end of list */ + env = GNUNET_MQ_msg (trm, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT); + trm->id = htonl (ti->r_id); + GNUNET_MQ_send (ti->client->mq, + env); + GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head, + ti->client->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); +} + +static void +handle_ticket_iteration_start (void *cls, + const struct TicketIterationStartMessage *tis_msg) +{ + struct IdpClient *client = cls; + struct TicketIteration *ti; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TICKET_ITERATION_START message\n"); + ti = GNUNET_new (struct TicketIteration); + ti->r_id = ntohl (tis_msg->id); + ti->offset = 0; + ti->client = client; + ti->identity = tis_msg->identity; + ti->is_audience = ntohl (tis_msg->is_audience); + + GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head, + client->ticket_iter_tail, + ti); + run_ticket_iteration_round (ti); + GNUNET_SERVICE_client_continue (client->client); +} + + +static void +handle_ticket_iteration_stop (void *cls, + const struct TicketIterationStopMessage *tis_msg) +{ + struct IdpClient *client = cls; + struct TicketIteration *ti; + uint32_t rid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' message\n", + "TICKET_ITERATION_STOP"); + rid = ntohl (tis_msg->id); + for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) + if (ti->r_id == rid) + break; + if (NULL == ti) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (client->client); + return; + } + GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head, + client->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); + GNUNET_SERVICE_client_continue (client->client); +} + + +static void +handle_ticket_iteration_next (void *cls, + const struct TicketIterationNextMessage *tis_msg) +{ + struct IdpClient *client = cls; + struct TicketIteration *ti; + uint32_t rid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TICKET_ITERATION_NEXT message\n"); + rid = ntohl (tis_msg->id); + for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) + if (ti->r_id == rid) + break; + if (NULL == ti) + { + GNUNET_break (0); + GNUNET_SERVICE_client_drop (client->client); + return; + } + run_ticket_iteration_round (ti); + GNUNET_SERVICE_client_continue (client->client); +} + + + + +/** + * Main function that will be run + * + * @param cls closure + * @param c the configuration used + * @param server the service handle + */ +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_SERVICE_Handle *server) +{ + char *database; + cfg = c; + + stats = GNUNET_STATISTICS_create ("reclaim", cfg); + + //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"); + } + + gns_handle = GNUNET_GNS_connect (cfg); + if (NULL == gns_handle) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns"); + } + credential_handle = GNUNET_CREDENTIAL_connect (cfg); + if (NULL == credential_handle) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential"); + } + identity_handle = GNUNET_IDENTITY_connect (cfg, + NULL, + NULL); + /* Loading DB plugin */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "reclaim", + "database", + &database)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No database backend configured\n"); + GNUNET_asprintf (&db_lib_name, + "libgnunet_plugin_reclaim_%s", + database); + TKT_database = GNUNET_PLUGIN_load (db_lib_name, + (void *) cfg); + GNUNET_free (database); + if (NULL == TKT_database) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not load database backend `%s'\n", + db_lib_name); + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_time (cfg, + "reclaim", + "TOKEN_EXPIRATION_INTERVAL", + &token_expiration_interval)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Time window for zone iteration: %s\n", + GNUNET_STRINGS_relative_time_to_string (token_expiration_interval, + GNUNET_YES)); + } else { + token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL; + } + + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); +} + +/** + * Called whenever a client is disconnected. + * + * @param cls closure + * @param client identification of the client + * @param app_ctx @a client + */ +static void +client_disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + void *app_ctx) +{ + struct IdpClient *idp = app_ctx; + struct AttributeIterator *ai; + struct TicketIteration *ti; + struct TicketRevocationHandle *rh; + struct TicketIssueHandle *iss; + struct ConsumeTicketHandle *ct; + struct AttributeStoreHandle *as; + + //TODO other operations + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p disconnected\n", + client); + + while (NULL != (iss = idp->issue_op_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, + idp->issue_op_tail, + iss); + cleanup_ticket_issue_handle (iss); + } + while (NULL != (ct = idp->consume_op_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->consume_op_head, + idp->consume_op_tail, + ct); + cleanup_consume_ticket_handle (ct); + } + while (NULL != (as = idp->store_op_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->store_op_head, + idp->store_op_tail, + as); + cleanup_as_handle (as); + } + + while (NULL != (ai = idp->attr_iter_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, + idp->attr_iter_tail, + ai); + cleanup_attribute_iter_handle (ai); + } + while (NULL != (rh = idp->revoke_op_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, + idp->revoke_op_tail, + rh); + cleanup_revoke_ticket_handle (rh); + } + while (NULL != (ti = idp->ticket_iter_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head, + idp->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); + } + GNUNET_free (idp); +} + + +/** + * Add a client to our list of active clients. + * + * @param cls NULL + * @param client client to add + * @param mq message queue for @a client + * @return internal namestore client structure for this client + */ +static void * +client_connect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + struct GNUNET_MQ_Handle *mq) +{ + struct IdpClient *idp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p connected\n", + client); + idp = GNUNET_new (struct IdpClient); + idp->client = client; + idp->mq = mq; + return idp; +} + + + +/** + * Define "main" method using service macro. + */ +GNUNET_SERVICE_MAIN +("reclaim", + GNUNET_SERVICE_OPTION_NONE, + &run, + &client_connect_cb, + &client_disconnect_cb, + NULL, + GNUNET_MQ_hd_var_size (attribute_store_message, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE, + struct AttributeStoreMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_start, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START, + struct AttributeIterationStartMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_next, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT, + struct AttributeIterationNextMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_stop, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP, + struct AttributeIterationStopMessage, + NULL), + GNUNET_MQ_hd_var_size (issue_ticket_message, + GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET, + struct IssueTicketMessage, + NULL), + GNUNET_MQ_hd_var_size (consume_ticket_message, + GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET, + struct ConsumeTicketMessage, + NULL), + GNUNET_MQ_hd_fixed_size (ticket_iteration_start, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START, + struct TicketIterationStartMessage, + NULL), + GNUNET_MQ_hd_fixed_size (ticket_iteration_next, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT, + struct TicketIterationNextMessage, + NULL), + GNUNET_MQ_hd_fixed_size (ticket_iteration_stop, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP, + struct TicketIterationStopMessage, + NULL), + GNUNET_MQ_hd_var_size (revoke_ticket_message, + GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET, + struct RevokeTicketMessage, + NULL), + GNUNET_MQ_handler_end()); +/* end of gnunet-service-reclaim.c */ diff --git a/src/reclaim/jwt.c b/src/reclaim/jwt.c new file mode 100644 index 000000000..45b5d73f6 --- /dev/null +++ b/src/reclaim/jwt.c @@ -0,0 +1,160 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +/** + * @file reclaim/jwt.c + * @brief helper library for JSON-Web-Tokens + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include + + +#define JWT_ALG "alg" + +/* Use 512bit HMAC */ +#define JWT_ALG_VALUE "HS512" + +#define JWT_TYP "typ" + +#define JWT_TYP_VALUE "jwt" + +#define SERVER_ADDRESS "https://reclaim.id/api/openid/userinfo" + +static char* +create_jwt_header(void) +{ + json_t *root; + char *json_str; + + root = json_object (); + json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); + json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); + + json_str = json_dumps (root, JSON_INDENT(1)); + json_decref (root); + return json_str; +} + +/** + * Create a JWT from attributes + * + * @param aud_key the public of the subject + * @param attrs the attribute list + * @param priv_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ +char* +jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, + const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_CRYPTO_AuthKey *priv_key) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_HashCode signature; + char* audience; + char* subject; + char* header; + char* padding; + char* body_str; + char* result; + char* header_base64; + char* body_base64; + char* signature_target; + char* signature_base64; + char* attr_val_str; + json_t* body; + + //exp REQUIRED time expired from config + //iat REQUIRED time now + //auth_time only if max_age + //nonce only if nonce + // OPTIONAL acr,amr,azp + subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + audience = GNUNET_STRINGS_data_to_string_alloc (aud_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + header = create_jwt_header (); + body = json_object (); + + //iss REQUIRED case sensitive server uri with https + //The issuer is the local reclaim instance (e.g. https://reclaim.id/api/openid) + json_object_set_new (body, + "iss", json_string (SERVER_ADDRESS)); + //sub REQUIRED public key identity, not exceed 255 ASCII length + json_object_set_new (body, + "sub", json_string (subject)); + //aud REQUIRED public key client_id must be there + json_object_set_new (body, + "aud", json_string (audience)); + for (le = attrs->list_head; NULL != le; le = le->next) + { + attr_val_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, + le->claim->data, + le->claim->data_size); + json_object_set_new (body, + le->claim->name, + json_string (attr_val_str)); + GNUNET_free (attr_val_str); + } + body_str = json_dumps (body, JSON_INDENT(0)); + json_decref (body); + + GNUNET_STRINGS_base64_encode (header, + strlen (header), + &header_base64); + //Remove GNUNET padding of base64 + padding = strtok(header_base64, "="); + while (NULL != padding) + padding = strtok(NULL, "="); + + GNUNET_STRINGS_base64_encode (body_str, + strlen (body_str), + &body_base64); + + //Remove GNUNET padding of base64 + padding = strtok(body_base64, "="); + while (NULL != padding) + padding = strtok(NULL, "="); + + GNUNET_free (subject); + GNUNET_free (audience); + + /** + * Creating the JWT signature. This might not be + * standards compliant, check. + */ + GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64); + GNUNET_CRYPTO_hmac (priv_key, signature_target, strlen (signature_target), &signature); + GNUNET_STRINGS_base64_encode ((const char*)&signature, + sizeof (struct GNUNET_HashCode), + &signature_base64); + GNUNET_asprintf (&result, "%s.%s.%s", + header_base64, body_base64, signature_base64); + + GNUNET_free (signature_target); + GNUNET_free (header); + GNUNET_free (body_str); + GNUNET_free (signature_base64); + GNUNET_free (body_base64); + GNUNET_free (header_base64); + return result; +} diff --git a/src/reclaim/jwt.h b/src/reclaim/jwt.h new file mode 100644 index 000000000..4b0b01be3 --- /dev/null +++ b/src/reclaim/jwt.h @@ -0,0 +1,10 @@ +#ifndef JWT_H +#define JWT_H + +char* +jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, + const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_CRYPTO_AuthKey *priv_key); + +#endif diff --git a/src/reclaim/plugin_gnsrecord_reclaim.c b/src/reclaim/plugin_gnsrecord_reclaim.c new file mode 100644 index 000000000..0322df752 --- /dev/null +++ b/src/reclaim/plugin_gnsrecord_reclaim.c @@ -0,0 +1,265 @@ +/* + This file is part of GNUnet + Copyright (C) 2013, 2014 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @file reclaim/plugin_gnsrecord_reclaim.c + * @brief gnsrecord plugin to provide the API for identity records + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_gnsrecord_plugin.h" + + +/** + * Convert the 'value' of a record to a string. + * + * @param cls closure, unused + * @param type type of the record + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +static char * +value_to_string (void *cls, + uint32_t type, + 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: + return GNUNET_STRINGS_data_to_string_alloc (data, data_size); + case GNUNET_GNSRECORD_TYPE_ID_TOKEN: //DEPRECATED + return GNUNET_strndup (data, data_size); + case GNUNET_GNSRECORD_TYPE_ABE_KEY: + case GNUNET_GNSRECORD_TYPE_ABE_MASTER: + return GNUNET_STRINGS_data_to_string_alloc (data, data_size); + case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: //DEPRECATED + 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); + GNUNET_free (aud_str); + GNUNET_free (ecdhe_str); + return result; + + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of a record to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the record + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +static int +string_to_value (void *cls, + uint32_t type, + const char *s, + 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) + { + case GNUNET_GNSRECORD_TYPE_ID_ATTR: + return GNUNET_STRINGS_string_to_data (s, + strlen (s), + *data, + *data_size); + case GNUNET_GNSRECORD_TYPE_ID_TOKEN: + *data = GNUNET_strdup (s); + *data_size = strlen (s); + return GNUNET_OK; + case GNUNET_GNSRECORD_TYPE_ABE_KEY: + case GNUNET_GNSRECORD_TYPE_ABE_MASTER: + return GNUNET_STRINGS_string_to_data (s, + strlen (s), + *data, + *data_size); + 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); + GNUNET_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 }, + { "ABE_KEY", GNUNET_GNSRECORD_TYPE_ABE_KEY }, + { "ABE_MASTER", GNUNET_GNSRECORD_TYPE_ABE_MASTER }, + { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA }, + { NULL, UINT32_MAX } +}; + + +/** + * Convert a type name (i.e. "AAAA") to the corresponding number. + * + * @param cls closure, unused + * @param dns_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +typename_to_number (void *cls, + const char *dns_typename) +{ + unsigned int i; + + i=0; + while ( (NULL != name_map[i].name) && + (0 != strcasecmp (dns_typename, name_map[i].name)) ) + i++; + return name_map[i].number; +} + + +/** + * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +number_to_typename (void *cls, + uint32_t type) +{ + unsigned int i; + + i=0; + while ( (NULL != name_map[i].name) && + (type != name_map[i].number) ) + i++; + return name_map[i].name; +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_gnsrecord_reclaim_init (void *cls) +{ + struct GNUNET_GNSRECORD_PluginFunctions *api; + + api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions); + api->value_to_string = &value_to_string; + api->string_to_value = &string_to_value; + api->typename_to_number = &typename_to_number; + api->number_to_typename = &number_to_typename; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init + * @return NULL + */ +void * +libgnunet_plugin_gnsrecord_reclaim_done (void *cls) +{ + struct GNUNET_GNSRECORD_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_gnsrecord_dns.c */ diff --git a/src/reclaim/plugin_reclaim_sqlite.c b/src/reclaim/plugin_reclaim_sqlite.c new file mode 100644 index 000000000..b545a94e8 --- /dev/null +++ b/src/reclaim/plugin_reclaim_sqlite.c @@ -0,0 +1,734 @@ + /* + * This file is part of GNUnet + * Copyright (C) 2009-2017 GNUnet e.V. + * + * GNUnet is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, + * 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * @file reclaim/plugin_reclaim_sqlite.c + * @brief sqlite-based idp backend + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_reclaim_plugin.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_sq_lib.h" +#include + +/** + * After how many ms "busy" should a DB operation fail for good? A + * low value makes sure that we are more responsive to requests + * (especially PUTs). A high value guarantees a higher success rate + * (SELECTs in iterate can take several seconds despite LIMIT=1). + * + * The default value of 1s should ensure that users do not experience + * huge latencies while at the same time allowing operations to + * succeed with reasonable probability. + */ +#define BUSY_TIMEOUT_MS 1000 + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "reclaim", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) + +#define LOG(kind,...) GNUNET_log_from (kind, "reclaim-sqlite", __VA_ARGS__) + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Database filename. + */ + char *fn; + + /** + * Native SQLite database handle. + */ + sqlite3 *dbh; + + /** + * Precompiled SQL to store ticket. + */ + sqlite3_stmt *store_ticket; + + /** + * Precompiled SQL to delete existing ticket. + */ + sqlite3_stmt *delete_ticket; + + /** + * Precompiled SQL to iterate tickets. + */ + sqlite3_stmt *iterate_tickets; + + /** + * Precompiled SQL to get ticket attributes. + */ + sqlite3_stmt *get_ticket_attrs; + + /** + * Precompiled SQL to iterate tickets by audience. + */ + sqlite3_stmt *iterate_tickets_by_audience; +}; + + +/** + * @brief Prepare a SQL statement + * + * @param dbh handle to the database + * @param zSql SQL statement, UTF-8 encoded + * @param ppStmt set to the prepared statement + * @return 0 on success + */ +static int +sq_prepare (sqlite3 *dbh, + const char *zSql, + sqlite3_stmt **ppStmt) +{ + char *dummy; + int result; + + result = + sqlite3_prepare_v2 (dbh, + zSql, + strlen (zSql), + ppStmt, + (const char **) &dummy); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Prepared `%s' / %p: %d\n", + zSql, + *ppStmt, + result); + return result; +} + +/** + * Create our database indices. + * + * @param dbh handle to the database + */ +static void +create_indices (sqlite3 * dbh) +{ + /* create indices */ + if ( (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)", + NULL, NULL, NULL)) ) + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to create indices: %s\n", + sqlite3_errmsg (dbh)); +} + + + +#if 0 +#define CHECK(a) GNUNET_break(a) +#define ENULL NULL +#else +#define ENULL &e +#define ENULL_DEFINED 1 +#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } +#endif + + +/** + * Initialize the database connections and associated + * data structures (create tables and indices + * as needed as well). + * + * @param plugin the plugin context (state for this module) + * @return #GNUNET_OK on success + */ +static int +database_setup (struct Plugin *plugin) +{ + sqlite3_stmt *stmt; + char *afsdir; +#if ENULL_DEFINED + char *e; +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, + "reclaim-sqlite", + "FILENAME", + &afsdir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "reclaim-sqlite", + "FILENAME"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_DISK_file_test (afsdir)) + { + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (afsdir)) + { + GNUNET_break (0); + GNUNET_free (afsdir); + return GNUNET_SYSERR; + } + } + /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ + plugin->fn = afsdir; + + /* Open database and precompile statements */ + if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Unable to initialize SQLite: %s.\n"), + sqlite3_errmsg (plugin->dbh)); + return GNUNET_SYSERR; + } + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA temp_store=MEMORY", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA synchronous=NORMAL", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA legacy_file_format=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA auto_vacuum=INCREMENTAL", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA encoding=\"UTF-8\"", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA page_size=4092", NULL, NULL, + ENULL)); + + CHECK (SQLITE_OK == + sqlite3_busy_timeout (plugin->dbh, + BUSY_TIMEOUT_MS)); + + + /* Create table */ + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'", + &stmt)); + if ((sqlite3_step (stmt) == SQLITE_DONE) && + (sqlite3_exec + (plugin->dbh, + "CREATE TABLE identity001tickets (" + " identity BLOB NOT NULL DEFAULT ''," + " audience BLOB NOT NULL DEFAULT ''," + " rnd INT8 NOT NULL DEFAULT ''," + " attributes BLOB NOT NULL DEFAULT ''" + ")", + NULL, NULL, NULL) != SQLITE_OK)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, + "sqlite3_exec"); + sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + sqlite3_finalize (stmt); + + create_indices (plugin->dbh); + + if ( (SQLITE_OK != + sq_prepare (plugin->dbh, + "INSERT INTO identity001tickets (identity, audience, rnd, attributes)" + " VALUES (?, ?, ?, ?)", + &plugin->store_ticket)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "DELETE FROM identity001tickets WHERE identity=? AND rnd=?", + &plugin->delete_ticket)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE identity=? AND rnd=?", + &plugin->get_ticket_attrs)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE identity=?" + " ORDER BY rnd LIMIT 1 OFFSET ?", + &plugin->iterate_tickets)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE audience=?" + " ORDER BY rnd LIMIT 1 OFFSET ?", + &plugin->iterate_tickets_by_audience)) ) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "precompiling"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Shutdown database connection and associate data + * structures. + * @param plugin the plugin context (state for this module) + */ +static void +database_shutdown (struct Plugin *plugin) +{ + int result; + sqlite3_stmt *stmt; + + if (NULL != plugin->store_ticket) + sqlite3_finalize (plugin->store_ticket); + if (NULL != plugin->delete_ticket) + sqlite3_finalize (plugin->delete_ticket); + if (NULL != plugin->iterate_tickets) + sqlite3_finalize (plugin->iterate_tickets); + if (NULL != plugin->iterate_tickets_by_audience) + sqlite3_finalize (plugin->iterate_tickets_by_audience); + if (NULL != plugin->get_ticket_attrs) + sqlite3_finalize (plugin->get_ticket_attrs); + result = sqlite3_close (plugin->dbh); + if (result == SQLITE_BUSY) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Tried to close sqlite without finalizing all prepared statements.\n")); + stmt = sqlite3_next_stmt (plugin->dbh, + NULL); + while (NULL != stmt) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Closing statement %p\n", + stmt); + result = sqlite3_finalize (stmt); + if (result != SQLITE_OK) + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "sqlite", + "Failed to close statement %p: %d\n", + stmt, + result); + stmt = sqlite3_next_stmt (plugin->dbh, + NULL); + } + result = sqlite3_close (plugin->dbh); + } + if (SQLITE_OK != result) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "sqlite3_close"); + + GNUNET_free_non_null (plugin->fn); +} + + +/** + * Store a ticket in the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to persist + * @param attrs the attributes associated with the ticket + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +reclaim_sqlite_store_ticket (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct Plugin *plugin = cls; + size_t attrs_len; + char *attrs_ser; + int n; + + { + /* First delete duplicates */ + struct GNUNET_SQ_QueryParam dparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->delete_ticket, + dparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->delete_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + + attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs); + attrs_ser = GNUNET_malloc (attrs_len); + GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, + attrs_ser); + struct GNUNET_SQ_QueryParam sparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_auto_from_type (&ticket->audience), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_fixed_size (attrs_ser, attrs_len), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->store_ticket, + sparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->store_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + GNUNET_free (attrs_ser); + } + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Ticket stored\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * Store a ticket in the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to delete + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +reclaim_sqlite_delete_ticket (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + struct Plugin *plugin = cls; + int n; + + { + struct GNUNET_SQ_QueryParam sparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->delete_ticket, + sparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->delete_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + } + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Ticket deleted\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * The given 'sqlite' statement has been prepared to be run. + * It will return a record which should be given to the iterator. + * Runs the statement and parses the returned record. + * + * @param plugin plugin context + * @param stmt to run (and then clean up) + * @param iter iterator to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ +static int +get_ticket_and_call_iterator (struct Plugin *plugin, + sqlite3_stmt *stmt, + GNUNET_RECLAIM_TicketIterator iter, + void *iter_cls) +{ + struct GNUNET_RECLAIM_Ticket ticket; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + int ret; + int sret; + size_t attrs_len; + char *attrs_ser; + + ret = GNUNET_NO; + if (SQLITE_ROW == (sret = sqlite3_step (stmt))) + { + struct GNUNET_SQ_ResultSpec rs[] = { + GNUNET_SQ_result_spec_auto_from_type (&ticket.identity), + GNUNET_SQ_result_spec_auto_from_type (&ticket.audience), + GNUNET_SQ_result_spec_uint64 (&ticket.rnd), + GNUNET_SQ_result_spec_variable_size ((void**)&attrs_ser, + &attrs_len), + GNUNET_SQ_result_spec_end + + }; + ret = GNUNET_SQ_extract_result (stmt, + rs); + if (GNUNET_OK != ret) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + } + else + { + attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (attrs_ser, + attrs_len); + if (NULL != iter) + iter (iter_cls, + &ticket, + attrs); + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs); + ret = GNUNET_YES; + } + GNUNET_SQ_cleanup_result (rs); + } + else + { + if (SQLITE_DONE != sret) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "sqlite_step"); + } + GNUNET_SQ_reset (plugin->dbh, + stmt); + return ret; +} + + +/** + * Lookup tickets in the datastore. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to retrieve attributes for + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +reclaim_sqlite_ticket_get_attrs (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_TicketIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + struct GNUNET_SQ_QueryParam params[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->get_ticket_attrs, + params)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->get_ticket_attrs); + return GNUNET_SYSERR; + } + return get_ticket_and_call_iterator (plugin, + plugin->get_ticket_attrs, + iter, + iter_cls); +} + + +/** + * Iterate over the results for a particular key and zone in the + * datastore. Will return at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param identity the issuing identity or audience (depending on audience switch) + * @param audience GNUNET_YES if identity is audience + * @param offset offset in the list of all matching records + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ +static int +reclaim_sqlite_iterate_tickets (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + int audience, + uint64_t offset, + GNUNET_RECLAIM_TicketIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + int err; + + if (NULL == identity) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + struct GNUNET_SQ_QueryParam params[] = { + GNUNET_SQ_query_param_auto_from_type (identity), + GNUNET_SQ_query_param_uint64 (&offset), + GNUNET_SQ_query_param_end + }; + if (GNUNET_YES == audience) + { + stmt = plugin->iterate_tickets_by_audience; + err = GNUNET_SQ_bind (stmt, + params); + } + else + { + stmt = plugin->iterate_tickets; + err = GNUNET_SQ_bind (stmt, + params); + } + if (GNUNET_OK != err) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + stmt); + return GNUNET_SYSERR; + } + return get_ticket_and_call_iterator (plugin, + stmt, + iter, + iter_cls); +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_RECLAIM_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_reclaim_sqlite_init (void *cls) +{ + static struct Plugin plugin; + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_RECLAIM_PluginFunctions *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + if (GNUNET_OK != database_setup (&plugin)) + { + database_shutdown (&plugin); + return NULL; + } + api = GNUNET_new (struct GNUNET_RECLAIM_PluginFunctions); + api->cls = &plugin; + api->store_ticket = &reclaim_sqlite_store_ticket; + api->delete_ticket = &reclaim_sqlite_delete_ticket; + api->iterate_tickets = &reclaim_sqlite_iterate_tickets; + api->get_ticket_attributes = &reclaim_sqlite_ticket_get_attrs; + LOG (GNUNET_ERROR_TYPE_INFO, + _("Sqlite database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_reclaim_sqlite_done (void *cls) +{ + struct GNUNET_RECLAIM_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + database_shutdown (plugin); + plugin->cfg = NULL; + GNUNET_free (api); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "sqlite plugin is finished\n"); + return NULL; +} + +/* end of plugin_reclaim_sqlite.c */ diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c new file mode 100644 index 000000000..abb3f59f5 --- /dev/null +++ b/src/reclaim/plugin_rest_openid_connect.c @@ -0,0 +1,2227 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file identity/plugin_rest_openid_connect.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 "gnunet_jsonapi_lib.h" +#include "gnunet_jsonapi_util.h" +#include "microhttpd.h" +#include +#include +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_reclaim_service.h" +#include "jwt.h" + +/** + * REST root namespace + */ +#define GNUNET_REST_API_NS_OIDC "/openid" + +/** + * Authorize endpoint + */ +#define GNUNET_REST_API_NS_AUTHORIZE "/openid/authorize" + +/** + * Token endpoint + */ +#define GNUNET_REST_API_NS_TOKEN "/openid/token" + +/** + * UserInfo endpoint + */ +#define GNUNET_REST_API_NS_USERINFO "/openid/userinfo" + +/** + * Login namespace + */ +#define GNUNET_REST_API_NS_LOGIN "/openid/login" + +/** + * Attribute key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" + +/** + * Ticket key + */ +#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" + + +/** + * Value key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 + +/** + * OIDC grant_type key + */ +#define OIDC_GRANT_TYPE_KEY "grant_type" + +/** + * OIDC grant_type key + */ +#define OIDC_GRANT_TYPE_VALUE "authorization_code" + +/** + * OIDC code key + */ +#define OIDC_CODE_KEY "code" + +/** + * OIDC response_type key + */ +#define OIDC_RESPONSE_TYPE_KEY "response_type" + +/** + * OIDC client_id key + */ +#define OIDC_CLIENT_ID_KEY "client_id" + +/** + * OIDC scope key + */ +#define OIDC_SCOPE_KEY "scope" + +/** + * OIDC redirect_uri key + */ +#define OIDC_REDIRECT_URI_KEY "redirect_uri" + +/** + * OIDC state key + */ +#define OIDC_STATE_KEY "state" + +/** + * OIDC nonce key + */ +#define OIDC_NONCE_KEY "nonce" + +/** + * OIDC cookie header key + */ +#define OIDC_COOKIE_HEADER_KEY "cookie" + +/** + * OIDC cookie header information key + */ +#define OIDC_AUTHORIZATION_HEADER_KEY "authorization" + +/** + * OIDC cookie header information key + */ +#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" + +/** + * OIDC expected response_type while authorizing + */ +#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" + +/** + * OIDC expected scope part while authorizing + */ +#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" + +/** + * OIDC ignored parameter array + */ +static char* OIDC_ignored_parameter_array [] = +{ + "display", + "prompt", + "max_age", + "ui_locales", + "response_mode", + "id_token_hint", + "login_hint", + "acr_values" +}; + +/** + * OIDC authorized identities and times hashmap + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; + +/** + * OIDC authorized identities and times hashmap + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; + +/** + * OIDC ticket/code use only once + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; + +/** + * OIDC access_token to ticket and ego + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; + +/** + * 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; +}; + +/** + * OIDC needed variables + */ +struct OIDC_Variables +{ + /** + * The RP client public key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey; + + /** + * The OIDC client id of the RP + */ + char *client_id; + + /** + * GNUNET_YES if there is a delegation to + * this RP or if it is a local identity + */ + int is_client_trusted; + + /** + * The OIDC redirect uri + */ + char *redirect_uri; + + /** + * The list of oidc scopes + */ + char *scope; + + /** + * The OIDC state + */ + char *state; + + /** + * The OIDC nonce + */ + char *nonce; + + /** + * The OIDC response type + */ + char *response_type; + + /** + * The identity chosen by the user to login + */ + char *login_identity; + + /** + * The response JSON + */ + json_t *response; + +}; + +/** + * 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; + + /** + * Pointer to ego private key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; + + /** + * OIDC variables + */ + struct OIDC_Variables *oidc; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *namestore_handle; + + /** + * Iterator for NAMESTORE + */ + struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; + + /** + * Attribute claim list + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Identity Provider + */ + struct GNUNET_RECLAIM_Handle *idp; + + /** + * Idp Operation + */ + struct GNUNET_RECLAIM_Operation *idp_op; + + /** + * Attribute iterator + */ + struct GNUNET_RECLAIM_AttributeIterator *attr_it; + + /** + * Ticket iterator + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it; + + /** + * A ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * 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; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * The tld for redirect + */ + char *tld; + + /** + * Error response message + */ + char *emsg; + + /** + * Error response description + */ + char *edesc; + + /** + * Reponse code + */ + int response_code; + + /** + * Response object + */ + struct GNUNET_JSONAPI_Document *resp_object; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->resp_object) + GNUNET_JSONAPI_document_delete (handle->resp_object); + 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->attr_it) + GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp) + GNUNET_RECLAIM_disconnect (handle->idp); + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->tld) + GNUNET_free (handle->tld); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->edesc) + GNUNET_free (handle->edesc); + if (NULL != handle->namestore_handle) + GNUNET_NAMESTORE_disconnect (handle->namestore_handle); + if (NULL != handle->oidc) + { + if (NULL != handle->oidc->client_id) + GNUNET_free(handle->oidc->client_id); + if (NULL != handle->oidc->login_identity) + GNUNET_free(handle->oidc->login_identity); + if (NULL != handle->oidc->nonce) + GNUNET_free(handle->oidc->nonce); + if (NULL != handle->oidc->redirect_uri) + GNUNET_free(handle->oidc->redirect_uri); + if (NULL != handle->oidc->response_type) + GNUNET_free(handle->oidc->response_type); + if (NULL != handle->oidc->scope) + GNUNET_free(handle->oidc->scope); + if (NULL != handle->oidc->state) + GNUNET_free(handle->oidc->state); + if (NULL != handle->oidc->response) + json_decref(handle->oidc->response); + GNUNET_free(handle->oidc); + } + if ( NULL != handle->attr_list ) + { + for (claim_entry = handle->attr_list->list_head; + NULL != claim_entry;) + { + claim_tmp = claim_entry; + claim_entry = claim_entry->next; + GNUNET_free(claim_tmp->claim); + GNUNET_free(claim_tmp); + } + GNUNET_free (handle->attr_list); + } + 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); + } + if (NULL != handle->attr_it) + { + GNUNET_free(handle->attr_it); + } + GNUNET_free (handle); +} + +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + + +/** + * Task run on error, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *json_error; + + GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", + handle->emsg, + (NULL != handle->edesc) ? handle->edesc : "", + (NULL != handle->oidc->state) ? ", \"state\":\"" : "", + (NULL != handle->oidc->state) ? handle->oidc->state : "", + (NULL != handle->oidc->state) ? "\"" : ""); + if ( 0 == handle->response_code ) + { + handle->response_code = MHD_HTTP_BAD_REQUEST; + } + resp = GNUNET_REST_create_response (json_error); + if (MHD_HTTP_UNAUTHORIZED == handle->response_code) + { + MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); + } + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (json_error); +} + + +/** + * Task run on error in userinfo endpoint, sends error header. Cleans up + * everything + * + * @param cls the `struct RequestHandle` + */ +static void +do_userinfo_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *error; + + GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", + handle->emsg, + (NULL != handle->edesc) ? handle->edesc : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header(resp, "WWW-Authenticate", error); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (error); +} + + +/** + * Task run on error, sends error message and redirects. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_redirect_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char* redirect; + GNUNET_asprintf (&redirect, + "%s?error=%s&error_description=%s%s%s", + handle->oidc->redirect_uri, handle->emsg, handle->edesc, + (NULL != handle->oidc->state) ? "&state=" : "", + (NULL != handle->oidc->state) ? handle->oidc->state : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", redirect); + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (redirect); +} + +/** + * Task run on timeout, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_timeout (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->timeout_task = NULL; + do_error (handle); +} + +/** + * Return attributes for claim + * + * @param cls the request handle + */ +static void +return_userinfo_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + result_str = json_dumps (handle->oidc->response, 0); + + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result_str); + cleanup_handle (handle); +} + +/** + * Returns base64 encoded string without padding + * + * @param string the string to encode + * @return base64 encoded string + */ +static char* +base_64_encode(const char *s) +{ + char *enc; + char *tmp; + + GNUNET_STRINGS_base64_encode(s, strlen(s), &enc); + tmp = strrchr (enc, '='); + *tmp = '\0'; + return enc; +} + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *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_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; +} + +/** + * Interprets cookie header and pass its identity keystring to handle + */ +static void +cookie_identity_interpretation (struct RequestHandle *handle) +{ + struct GNUNET_HashCode cache_key; + char *cookies; + struct GNUNET_TIME_Absolute current_time, *relog_time; + char delimiter[] = "; "; + + //gets identity of login try with cookie + GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), + &cache_key); + if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, + &cache_key) ) + { + //splits cookies and find 'Identity' cookie + cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); + handle->oidc->login_identity = strtok(cookies, delimiter); + + while ( NULL != handle->oidc->login_identity ) + { + if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) + { + break; + } + handle->oidc->login_identity = strtok (NULL, delimiter); + } + GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), + &cache_key); + if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) + { + relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, + &cache_key); + current_time = GNUNET_TIME_absolute_get (); + // 30 min after old login -> redirect to login + if ( current_time.abs_value_us <= relog_time->abs_value_us ) + { + handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); + handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); + } else { + handle->oidc->login_identity = NULL; + } + } + else + { + handle->oidc->login_identity = NULL; + } + } +} + +/** + * Redirects to login page stored in configuration file + */ +static void +login_redirection(void *cls) +{ + char *login_base_url; + char *new_redirect; + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + if ( GNUNET_OK + == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", + "address", &login_base_url) ) + { + GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", + login_base_url, + OIDC_RESPONSE_TYPE_KEY, + handle->oidc->response_type, + OIDC_CLIENT_ID_KEY, + handle->oidc->client_id, + OIDC_REDIRECT_URI_KEY, + handle->oidc->redirect_uri, + OIDC_SCOPE_KEY, + handle->oidc->scope, + OIDC_STATE_KEY, + (NULL != handle->oidc->state) ? handle->oidc->state : "", + OIDC_NONCE_KEY, + (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", new_redirect); + GNUNET_free(login_base_url); + } + else + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_free(new_redirect); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} + +/** + * Does internal server error when iteration failed. + */ +static void +oidc_iteration_error (void *cls) +{ + struct RequestHandle *handle = cls; + handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); +} + +static void get_client_name_result (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *ticket_str; + char *redirect_uri; + char *code_json_string; + char *code_base64_final_string; + char *redirect_path; + char *tmp; + char *tmp_prefix; + char *prefix; + ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + //TODO change if more attributes are needed (see max_age) + GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}", + ticket_str, + (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "", + (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "", + (NULL != handle->oidc->nonce) ? "\"" : ""); + code_base64_final_string = base_64_encode(code_json_string); + tmp = GNUNET_strdup (handle->oidc->redirect_uri); + redirect_path = strtok (tmp, "/"); + redirect_path = strtok (NULL, "/"); + redirect_path = strtok (NULL, "/"); + tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri); + prefix = strrchr (tmp_prefix, + (unsigned char) '.'); + *prefix = '\0'; + GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", + tmp_prefix, + handle->tld, + redirect_path, + handle->oidc->response_type, + code_base64_final_string, handle->oidc->state); + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", redirect_uri); + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (tmp); + GNUNET_free (tmp_prefix); + GNUNET_free (redirect_uri); + GNUNET_free (ticket_str); + GNUNET_free (code_json_string); + GNUNET_free (code_base64_final_string); + return; +} + +static void +get_client_name_error (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); +} + +/** + * Issues ticket and redirects to relying party with the authorization code as + * parameter. Otherwise redirects with error + */ +static void +oidc_ticket_issue_cb (void* cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + struct RequestHandle *handle = cls; + handle->idp_op = NULL; + handle->ticket = *ticket; + if (NULL != ticket) { + GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, + &handle->priv_key, + &handle->oidc->client_pkey, + &get_client_name_error, + handle, + &get_client_name_result, + handle); + return; + } + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup("Server cannot generate ticket."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); +} + +static void +oidc_collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + handle->attr_it = NULL; + handle->ticket_it = NULL; + if (NULL == handle->attr_list->list_head) + { + handle->emsg = GNUNET_strdup("invalid_scope"); + handle->edesc = GNUNET_strdup("The requested scope is not available."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp, + &handle->priv_key, + &handle->oidc->client_pkey, + handle->attr_list, + &oidc_ticket_issue_cb, + handle); +} + + +/** + * Collects all attributes for an ego if in scope parameter + */ +static void +oidc_attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + char* scope_variables; + char* scope_variable; + char delimiter[]=" "; + + if ( (NULL == attr->name) || (NULL == attr->data) ) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + scope_variables = GNUNET_strdup(handle->oidc->scope); + scope_variable = strtok (scope_variables, delimiter); + while (NULL != scope_variable) + { + if ( 0 == strcmp (attr->name, scope_variable) ) + { + break; + } + scope_variable = strtok (NULL, delimiter); + } + if ( NULL == scope_variable ) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + GNUNET_free(scope_variables); + return; + } + GNUNET_free(scope_variables); + + le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type, + attr->data, attr->data_size); + GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, + handle->attr_list->list_tail, le); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + +/** + * Checks time and cookie and redirects accordingly + */ +static void +login_check (void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_TIME_Absolute current_time, *relog_time; + struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; + struct GNUNET_HashCode cache_key; + char *identity_cookie; + + GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); + GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); + GNUNET_free(identity_cookie); + //No login time for identity -> redirect to login + if ( GNUNET_YES + == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, + &cache_key) ) + { + relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, + &cache_key); + current_time = GNUNET_TIME_absolute_get (); + // 30 min after old login -> redirect to login + if ( current_time.abs_value_us <= relog_time->abs_value_us ) + { + if ( GNUNET_OK + != GNUNET_CRYPTO_ecdsa_public_key_from_string ( + handle->oidc->login_identity, + strlen (handle->oidc->login_identity), &pubkey) ) + { + handle->emsg = GNUNET_strdup("invalid_cookie"); + handle->edesc = GNUNET_strdup( + "The cookie of a login identity is not valid"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + // iterate over egos and compare their public key + for (handle->ego_entry = handle->ego_head; + NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); + if ( 0 + == memcmp (&ego_pkey, &pubkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( + handle->ego_entry->ego); + handle->resp_object = GNUNET_JSONAPI_document_new (); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_list = GNUNET_new( + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start ( + handle->idp, &handle->priv_key, &oidc_iteration_error, handle, + &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); + return; + } + } + //handle->emsg = GNUNET_strdup("invalid_cookie"); + //handle->edesc = GNUNET_strdup( + // "The cookie of the login identity is not valid"); + //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + GNUNET_SCHEDULER_add_now (&login_redirection,handle); + return; + } + } +} + +/** + * Searches for client_id in namestore. If found trust status stored in handle + * Else continues to search + * + * @param handle the RequestHandle + */ +static void +namestore_iteration_callback ( + void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, + const char *rname, unsigned int rd_len, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey; + struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey; + int i; + + for (i = 0; i < rd_len; i++) + { + if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type ) + continue; + + if ( NULL != handle->oidc->login_identity ) + { + GNUNET_CRYPTO_ecdsa_public_key_from_string ( + handle->oidc->login_identity, + strlen (handle->oidc->login_identity), + &login_identity_pkey); + GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, + ¤t_zone_pkey); + + if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->oidc->is_client_trusted = GNUNET_YES; + } + } + } + else + { + if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->oidc->is_client_trusted = GNUNET_YES; + } + } + } + + GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it, + 1); +} + + +/** + * Iteration over all results finished, build final + * response. + * + * @param cls the `struct RequestHandle` + */ +static void +namestore_iteration_finished (void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + + char *expected_scope; + char delimiter[]=" "; + int number_of_ignored_parameter, iterator; + + + handle->ego_entry = handle->ego_entry->next; + + if(NULL != handle->ego_entry) + { + handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego); + handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key, + &oidc_iteration_error, handle, &namestore_iteration_callback, handle, + &namestore_iteration_finished, handle); + return; + } + if (GNUNET_NO == handle->oidc->is_client_trusted) + { + handle->emsg = GNUNET_strdup("unauthorized_client"); + handle->edesc = GNUNET_strdup("The client is not authorized to request an " + "authorization code using this method."); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + // REQUIRED value: redirect_uri + GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key)); + + // REQUIRED value: response_type + GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter response_type"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); + + // REQUIRED value: scope + GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter scope"); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); + + //OPTIONAL value: nonce + GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); + } + + //TODO check other values if needed + number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); + for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) + { + GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], + strlen(OIDC_ignored_parameter_array[iterator]), + &cache_key); + if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("access_denied"); + GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", + OIDC_ignored_parameter_array[iterator]); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + } + + // Checks if response_type is 'code' + if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) + { + handle->emsg=GNUNET_strdup("unsupported_response_type"); + handle->edesc=GNUNET_strdup("The authorization server does not support " + "obtaining this authorization code."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + + // Checks if scope contains 'openid' + expected_scope = GNUNET_strdup(handle->oidc->scope); + char* test; + test = strtok (expected_scope, delimiter); + while (NULL != test) + { + if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) + { + break; + } + test = strtok (NULL, delimiter); + } + if (NULL == test) + { + handle->emsg = GNUNET_strdup("invalid_scope"); + handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " + "malformed."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + GNUNET_free(expected_scope); + return; + } + + GNUNET_free(expected_scope); + + if( NULL != handle->oidc->login_identity ) + { + GNUNET_SCHEDULER_add_now(&login_check,handle); + return; + } + + GNUNET_SCHEDULER_add_now(&login_redirection,handle); +} + +/** + * Responds to authorization GET and url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + struct EgoEntry *tmp_ego; + struct GNUNET_CRYPTO_EcdsaPublicKey pkey; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + + cookie_identity_interpretation(handle); + + //RECOMMENDED value: state - REQUIRED for answers + GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key); + handle->oidc->state = GNUNET_strdup (handle->oidc->state); + } + + // REQUIRED value: client_id + GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), + &cache_key); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &cache_key)) + { + handle->emsg=GNUNET_strdup("invalid_request"); + handle->edesc=GNUNET_strdup("missing parameter client_id"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, + &cache_key)); + + if ( GNUNET_OK + != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, + strlen (handle->oidc->client_id), + &handle->oidc->client_pkey) ) + { + handle->emsg = GNUNET_strdup("unauthorized_client"); + handle->edesc = GNUNET_strdup("The client is not authorized to request an " + "authorization code using this method."); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + + if ( NULL == handle->ego_head ) + { + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("Egos are missing"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + handle->ego_entry = handle->ego_head; + handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); + handle->oidc->is_client_trusted = GNUNET_NO; + + //First check if client_id is one of our egos; TODO: handle other TLD cases: Delegation, from config + for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) + { + priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); + GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, + &pkey); + if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + { + handle->tld = GNUNET_strdup (tmp_ego->identifier); + handle->oidc->is_client_trusted = GNUNET_YES; + handle->ego_entry = handle->ego_tail; + } + } + + + // Checks if client_id is valid: + handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start ( + handle->namestore_handle, &handle->priv_key, &oidc_iteration_error, + handle, &namestore_iteration_callback, handle, + &namestore_iteration_finished, handle); +} + +/** + * Combines an identity with a login time and responds OK to login request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +login_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp = GNUNET_REST_create_response (""); + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + struct GNUNET_TIME_Absolute *current_time; + struct GNUNET_TIME_Absolute *last_time; + char* cookie; + json_t *root; + json_error_t error; + json_t *identity; + char term_data[handle->rest_handle->data_size+1]; + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); + root = json_loads (term_data, JSON_DECODE_ANY, &error); + identity = json_object_get (root, "identity"); + if ( json_is_string(identity) ) + { + GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); + MHD_add_response_header (resp, "Set-Cookie", cookie); + MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); + GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); + + current_time = GNUNET_new(struct GNUNET_TIME_Absolute); + *current_time = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), + 5)); + last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); + if (NULL != last_time) + { + GNUNET_free(last_time); + } + GNUNET_CONTAINER_multihashmap_put ( + OIDC_identity_login_time, &cache_key, current_time, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free(cookie); + } + else + { + handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); + } + json_decref (root); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + return; +} + +/** + * Responds to token url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + //TODO static strings + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + char *authorization, *credentials; + char delimiter[]=" "; + char delimiter_user_psw[]=":"; + char *grant_type, *code; + char *user_psw = NULL, *client_id, *psw; + char *expected_psw; + int client_exists = GNUNET_NO; + struct MHD_Response *resp; + char* code_output; + json_t *root, *ticket_string, *nonce, *max_age; + json_error_t error; + char *json_response; + char *jwt_secret; + + /* + * Check Authorization + */ + GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, + strlen (OIDC_AUTHORIZATION_HEADER_KEY), + &cache_key); + if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, + &cache_key) ) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->edesc=GNUNET_strdup("missing authorization"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); + + //split header in "Basic" and [content] + credentials = strtok (authorization, delimiter); + if (0 != strcmp ("Basic",credentials)) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + credentials = strtok(NULL, delimiter); + if (NULL == credentials) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw); + + if ( NULL == user_psw ) + { + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + client_id = strtok (user_psw, delimiter_user_psw); + if ( NULL == client_id ) + { + GNUNET_free_non_null(user_psw); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + psw = strtok (NULL, delimiter_user_psw); + if (NULL == psw) + { + GNUNET_free_non_null(user_psw); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //check client password + if ( GNUNET_OK + == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", + "psw", &expected_psw) ) + { + if (0 != strcmp (expected_psw, psw)) + { + GNUNET_free_non_null(user_psw); + GNUNET_free(expected_psw); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_free(expected_psw); + } + else + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //check client_id + for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) + { + if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) + { + client_exists = GNUNET_YES; + break; + } + handle->ego_entry = handle->ego_entry->next; + } + if (GNUNET_NO == client_exists) + { + GNUNET_free_non_null(user_psw); + handle->emsg=GNUNET_strdup("invalid_client"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + /* + * Check parameter + */ + + //TODO Do not allow multiple equal parameter names + //REQUIRED grant_type + GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains ( + handle->rest_handle->url_param_map, &cache_key) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter grant_type"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + grant_type = GNUNET_CONTAINER_multihashmap_get ( + handle->rest_handle->url_param_map, &cache_key); + + //REQUIRED code + GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains ( + handle->rest_handle->url_param_map, &cache_key) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, + &cache_key); + + //REQUIRED redirect_uri + GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), + &cache_key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains ( + handle->rest_handle->url_param_map, &cache_key) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //Check parameter grant_type == "authorization_code" + if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) + { + GNUNET_free_non_null(user_psw); + handle->emsg=GNUNET_strdup("unsupported_grant_type"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); + int i = 1; + if ( GNUNET_SYSERR + == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, + &cache_key, + &i, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + //decode code + GNUNET_STRINGS_base64_decode(code,strlen(code), (void**)&code_output); + root = json_loads (code_output, 0, &error); + GNUNET_free(code_output); + ticket_string = json_object_get (root, "ticket"); + nonce = json_object_get (root, "nonce"); + max_age = json_object_get (root, "max_age"); + + if(ticket_string == NULL && !json_is_string(ticket_string)) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + struct GNUNET_RECLAIM_Ticket *ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket); + if ( GNUNET_OK + != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string), + strlen (json_string_value(ticket_string)), + ticket, + sizeof(struct GNUNET_RECLAIM_Ticket))) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + // this is the current client (relying party) + struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; + GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key); + if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + + //create jwt + unsigned long long int expiration_time; + if ( GNUNET_OK + != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin", + "expiration_time", &expiration_time) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("server_error"); + handle->edesc = GNUNET_strdup ("gnunet configuration failed"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + //aud REQUIRED public key client_id must be there + GNUNET_RECLAIM_ATTRIBUTE_list_add(cl, + "aud", + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + client_id, + strlen(client_id)); + //exp REQUIRED time expired from config + struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute ( + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), + expiration_time)); + const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time); + GNUNET_RECLAIM_ATTRIBUTE_list_add (cl, + "exp", + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + exp_time_string, + strlen(exp_time_string)); + //iat REQUIRED time now + struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get(); + const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now); + GNUNET_RECLAIM_ATTRIBUTE_list_add (cl, + "iat", + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + time_now_string, + strlen(time_now_string)); + //nonce only if nonce is provided + if ( NULL != nonce && json_is_string(nonce) ) + { + GNUNET_RECLAIM_ATTRIBUTE_list_add (cl, + "nonce", + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + json_string_value(nonce), + strlen(json_string_value(nonce))); + } + //auth_time only if max_age is provided + if ( NULL != max_age && json_is_string(max_age) ) + { + GNUNET_RECLAIM_ATTRIBUTE_list_add (cl, + "auth_time", + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + json_string_value(max_age), + strlen(json_string_value(max_age))); + } + //TODO OPTIONAL acr,amr,azp + + struct EgoEntry *ego_entry; + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); + if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) + { + break; + } + } + if ( NULL == ego_entry ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("invalid code..."); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + if ( GNUNET_OK + != GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", + "jwt_secret", &jwt_secret) ) + { + GNUNET_free_non_null(user_psw); + handle->emsg = GNUNET_strdup("invalid_request"); + handle->edesc = GNUNET_strdup("No signing secret configured!"); + handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_SCHEDULER_add_now (&do_error, handle); + GNUNET_free(ticket); + return; + } + struct GNUNET_CRYPTO_AuthKey jwt_sign_key; + struct GNUNET_CRYPTO_EcdsaPublicKey pk; + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pk); + GNUNET_CRYPTO_hash (jwt_secret, strlen (jwt_secret), (struct GNUNET_HashCode*)jwt_sign_key.key); + char *id_token = jwt_create_from_list(&ticket->audience, + &pk, + cl, + &jwt_sign_key); + + //Create random access_token + char* access_token_number; + char* access_token; + uint64_t random_number; + random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); + GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number); + GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); + + + + //TODO OPTIONAL add refresh_token and scope + GNUNET_asprintf (&json_response, + "{ \"access_token\" : \"%s\", " + "\"token_type\" : \"Bearer\", " + "\"expires_in\" : %d, " + "\"id_token\" : \"%s\"}", + access_token, + expiration_time, + id_token); + GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); + char *id_ticket_combination; + GNUNET_asprintf(&id_ticket_combination, + "%s;%s", + client_id, + json_string_value(ticket_string)); + GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, + &cache_key, + id_ticket_combination, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + + resp = GNUNET_REST_create_response (json_response); + MHD_add_response_header (resp, "Cache-Control", "no-store"); + MHD_add_response_header (resp, "Pragma", "no-cache"); + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + + GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); + GNUNET_free(access_token_number); + GNUNET_free(access_token); + GNUNET_free(user_psw); + GNUNET_free(json_response); + GNUNET_free(ticket); + GNUNET_free(id_token); + json_decref (root); + GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); +} + +/** + * Collects claims and stores them in handle + */ +static void +consume_ticket (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + char *tmp_value; + json_t *value; + + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); + return; + } + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + value = json_string (tmp_value); + + + json_object_set_new (handle->oidc->response, + attr->name, + value); + GNUNET_free (tmp_value); +} + +/** + * Responds to userinfo GET and url-encoded POST request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, void *cls) +{ + //TODO expiration time + struct RequestHandle *handle = cls; + char delimiter[] = " "; + char delimiter_db[] = ";"; + struct GNUNET_HashCode cache_key; + char *authorization, *authorization_type, *authorization_access_token; + char *client_ticket, *client, *ticket_str; + struct GNUNET_RECLAIM_Ticket *ticket; + + GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, + strlen (OIDC_AUTHORIZATION_HEADER_KEY), + &cache_key); + if ( GNUNET_NO + == GNUNET_CONTAINER_multihashmap_contains ( + handle->rest_handle->header_param_map, &cache_key) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + return; + } + authorization = GNUNET_CONTAINER_multihashmap_get ( + handle->rest_handle->header_param_map, &cache_key); + + //split header in "Bearer" and access_token + authorization = GNUNET_strdup(authorization); + authorization_type = strtok (authorization, delimiter); + if ( 0 != strcmp ("Bearer", authorization_type) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + authorization_access_token = strtok (NULL, delimiter); + if ( NULL == authorization_access_token ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("No Access Token"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + + GNUNET_CRYPTO_hash (authorization_access_token, + strlen (authorization_access_token), + &cache_key); + if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, + &cache_key) ) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + return; + } + + client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, + &cache_key); + client_ticket = GNUNET_strdup(client_ticket); + client = strtok(client_ticket,delimiter_db); + if (NULL == client) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + handle->ego_entry = handle->ego_head; + for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) + { + if (0 == strcmp(handle->ego_entry->keystring,client)) + { + break; + } + } + if (NULL == handle->ego_entry) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + ticket_str = strtok(NULL, delimiter_db); + if (NULL == ticket_str) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket); + if ( GNUNET_OK + != GNUNET_STRINGS_string_to_data (ticket_str, + strlen (ticket_str), + ticket, + sizeof(struct GNUNET_RECLAIM_Ticket))) + { + handle->emsg = GNUNET_strdup("invalid_token"); + handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + GNUNET_free(ticket); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + return; + } + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->oidc->response = json_object(); + json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); + handle->idp_op = GNUNET_RECLAIM_ticket_consume ( + handle->idp, + GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), + ticket, + consume_ticket, + handle); + GNUNET_free(ticket); + GNUNET_free(authorization); + GNUNET_free(client_ticket); + +} + + +/** + * Handle rest request + * + * @param handle the request handle + */ +static void +init_cont (struct RequestHandle *handle) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, + &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + 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; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + return; + } + /* Ego renamed or added */ + if (identifier != NULL) { + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { + if (ego_entry->ego == ego) { + /* Rename */ + GNUNET_free (ego_entry->identifier); + ego_entry->identifier = GNUNET_strdup (identifier); + break; + } + } + if (NULL == ego_entry) { + /* Add */ + 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; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + } + } else { + /* Delete */ + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { + if (ego_entry->ego == ego) + break; + } + if (NULL != ego_entry) + GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry); + } + +} + +static void +rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + handle->oidc = GNUNET_new (struct OIDC_Variables); + if ( NULL == OIDC_identity_login_time ) + OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_identity_grants ) + OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_ticket_once ) + OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if ( NULL == OIDC_interpret_access_token ) + OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->state = ID_REST_STATE_INIT; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_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->namestore_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_timeout, + 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_openid_connect_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_OIDC; + 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_DEBUG, + _("Identity Provider 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_openid_connect_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + plugin->cfg = NULL; + + struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; + void *value = NULL; + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( + OIDC_identity_login_time); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); + hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); + while (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) + { + if (NULL != value) + GNUNET_free(value); + } + GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); + GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); + GNUNET_free_non_null (allow_methods); + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Identity Provider REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_identity_provider.c */ diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c new file mode 100644 index 000000000..b54aed5f3 --- /dev/null +++ b/src/reclaim/plugin_rest_reclaim.c @@ -0,0 +1,1253 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +/** + * @author Martin Schanzenbach + * @author Philippe Buschmann + * @file reclaim/plugin_rest_reclaim.c + * @brief GNUnet reclaim 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 "gnunet_jsonapi_lib.h" +#include "gnunet_jsonapi_util.h" +#include "microhttpd.h" +#include +#include +#include "gnunet_signatures.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "gnunet_reclaim_service.h" + +/** + * REST root namespace + */ +#define GNUNET_REST_API_NS_RECLAIM "/idp" + +/** + * Attribute namespace + */ +#define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/idp/attributes" + +/** + * Ticket namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke" + +/** + * Revoke namespace + */ +#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" + +/** + * Attribute key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" + +/** + * Ticket key + */ +#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" + + +/** + * Value key + */ +#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" + +/** + * State while collecting all egos + */ +#define ID_REST_STATE_INIT 0 + +/** + * Done collecting egos + */ +#define ID_REST_STATE_POST_INIT 1 + +/** + * 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; + + /** + * Pointer to ego private key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; + + /** + * The processing state + */ + int state; + + /** + * Handle to Identity service. + */ + struct GNUNET_IDENTITY_Handle *identity_handle; + + /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * Handle to NAMESTORE + */ + struct GNUNET_NAMESTORE_Handle *namestore_handle; + + /** + * Iterator for NAMESTORE + */ + struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it; + + /** + * Attribute claim list + */ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + + /** + * IDENTITY Operation + */ + struct GNUNET_IDENTITY_Operation *op; + + /** + * Identity Provider + */ + struct GNUNET_RECLAIM_Handle *idp; + + /** + * Idp Operation + */ + struct GNUNET_RECLAIM_Operation *idp_op; + + /** + * Attribute iterator + */ + struct GNUNET_RECLAIM_AttributeIterator *attr_it; + + /** + * Ticket iterator + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it; + + /** + * A ticket + */ + struct GNUNET_RECLAIM_Ticket ticket; + + /** + * 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; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The url + */ + char *url; + + /** + * Error response message + */ + char *emsg; + + /** + * Reponse code + */ + int response_code; + + /** + * Response object + */ + struct GNUNET_JSONAPI_Document *resp_object; + +}; + +/** + * Cleanup lookup handle + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; + struct EgoEntry *ego_entry; + struct EgoEntry *ego_tmp; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->resp_object) + GNUNET_JSONAPI_document_delete (handle->resp_object); + 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->attr_it) + GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp) + GNUNET_RECLAIM_disconnect (handle->idp); + if (NULL != handle->url) + GNUNET_free (handle->url); + if (NULL != handle->emsg) + GNUNET_free (handle->emsg); + if (NULL != handle->namestore_handle) + GNUNET_NAMESTORE_disconnect (handle->namestore_handle); + if ( NULL != handle->attr_list ) + { + for (claim_entry = handle->attr_list->list_head; + NULL != claim_entry;) + { + claim_tmp = claim_entry; + claim_entry = claim_entry->next; + GNUNET_free(claim_tmp->claim); + GNUNET_free(claim_tmp); + } + GNUNET_free (handle->attr_list); + } + 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); + } + if (NULL != handle->attr_it) + { + GNUNET_free(handle->attr_it); + } + GNUNET_free (handle); +} + +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + + +/** + * Task run on error, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *json_error; + + GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", + handle->emsg); + if ( 0 == handle->response_code ) + { + handle->response_code = MHD_HTTP_BAD_REQUEST; + } + resp = GNUNET_REST_create_response (json_error); + MHD_add_response_header (resp, "Content-Type", "application/json"); + handle->proc (handle->proc_cls, resp, handle->response_code); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (json_error); +} + + +/** + * Task run on timeout, sends error message. Cleans up everything. + * + * @param cls the `struct RequestHandle` + */ +static void +do_timeout (void *cls) +{ + struct RequestHandle *handle = cls; + + handle->timeout_task = NULL; + do_error (handle); +} + + +static void +collect_error_cb (void *cls) +{ + struct RequestHandle *handle = cls; + + do_error (handle); +} + +static void +finished_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (emsg); + if (GNUNET_OK != success) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} + + +/** + * Return attributes for identity + * + * @param cls the request handle + */ +static void +return_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result_str); + cleanup_handle (handle); +} + +static void +collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + //Done + handle->attr_it = NULL; + handle->ticket_it = NULL; + GNUNET_SCHEDULER_add_now (&return_response, handle); +} + + +/** + * Collect all attributes for an ego + * + */ +static void +ticket_collect (void *cls, + const struct GNUNET_RECLAIM_Ticket *ticket) +{ + struct GNUNET_JSONAPI_Resource *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET, + tmp); + GNUNET_free (tmp); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "issuer", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "audience", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "rnd", + value); + GNUNET_free (tmp); + json_decref (value); + GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it); +} + + + +/** + * List tickets for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = GNUNET_JSONAPI_document_new (); + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->ticket_it = GNUNET_RECLAIM_ticket_iteration_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &ticket_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity; + const char* name_str; + const char* value_str; + const char* exp_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attribute; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_TIME_Relative exp; + char term_data[handle->rest_handle->data_size+1]; + json_t *value_json; + json_t *data_json; + json_t *exp_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + name_str = GNUNET_JSONAPI_resource_get_id (json_res); + exp_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "exp"); + exp_str = json_string_value (exp_json); + if (NULL == exp_str) { + exp = GNUNET_TIME_UNIT_HOURS; + } else { + if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str, + &exp)) { + exp = GNUNET_TIME_UNIT_HOURS; + } + } + + value_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "value"); + value_str = json_string_value (value_json); + attribute = GNUNET_RECLAIM_ATTRIBUTE_claim_new (name_str, + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + value_str, + strlen (value_str) + 1); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp, + identity_priv, + attribute, + &exp, + &finished_cont, + handle); + GNUNET_free (attribute); + GNUNET_JSONAPI_document_delete (json_obj); +} + + + +/** + * Collect all attributes for an ego + * + */ +static void +attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct GNUNET_JSONAPI_Resource *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp_value; + + if ((NULL == attr->name) || (NULL == attr->data)) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + value = json_string (tmp_value); + + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); + GNUNET_free(tmp_value); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + + +/** + * List attributes for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= + strlen (handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = GNUNET_JSONAPI_document_new (); + + + if (NULL == ego_entry) + { + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &attr_collect, + handle, + &collect_finished_cb, + handle); +} + + +static void +revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "issuer"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.identity, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp, + identity_priv, + &ticket, + &finished_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); +} + +static void +consume_cont (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) +{ + struct RequestHandle *handle = cls; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *value; + + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + value = json_string (attr->data); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); +} + +static void +consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_RECLAIM_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "identity"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.audience, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->resp_object = GNUNET_JSONAPI_document_new (); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp, + identity_priv, + &ticket, + &consume_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); +} + + + +/** + * Respond to OPTIONS request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +options_cont (struct GNUNET_REST_RequestHandle *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_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) +{ + struct GNUNET_REST_RequestHandlerError err; + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &list_attribute_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &add_attribute_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, + &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + 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; + ego_entry->identifier = GNUNET_strdup (identifier); + GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + } + +} + +static void +rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + handle->response_code = 0; + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->state = ID_REST_STATE_INIT; + handle->rest_handle = rest_handle; + + handle->url = GNUNET_strdup (rest_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->namestore_handle = GNUNET_NAMESTORE_connect (cfg); + handle->timeout_task = + GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_timeout, + 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_reclaim_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_RECLAIM; + 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_DEBUG, + _("Identity Provider 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_reclaim_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 Provider REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_reclaim.c */ diff --git a/src/reclaim/reclaim.conf b/src/reclaim/reclaim.conf new file mode 100644 index 000000000..e93899e05 --- /dev/null +++ b/src/reclaim/reclaim.conf @@ -0,0 +1,23 @@ +[reclaim] +START_ON_DEMAND = NO +RUN_PER_USER = YES +#PORT = 2108 +HOSTNAME = localhost +BINARY = gnunet-service-reclaim +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-reclaim.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES +TOKEN_EXPIRATION_INTERVAL = 30 m +DATABASE = sqlite + +[reclaim-rest-plugin] +#ADDRESS = https://identity.gnu:8000#/login +ADDRESS = https://reclaim.ui/#/login +PSW = secret +JWT_SECRET = secret +EXPIRATION_TIME = 3600 + +[reclaim-sqlite] +FILENAME = $GNUNET_DATA_HOME/reclaim/sqlite.db diff --git a/src/reclaim/reclaim.h b/src/reclaim/reclaim.h new file mode 100644 index 000000000..d2c84686d --- /dev/null +++ b/src/reclaim/reclaim.h @@ -0,0 +1,410 @@ +/* + This file is part of GNUnet. + Copyright (C) 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @author Martin Schanzenbach + * @file reclaim/reclaim.h + * + * @brief Common type definitions for the identity provider + * service and API. + */ +#ifndef RECLAIM_H +#define RECLAIM_H + +#include "gnunet_common.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Use to store an identity attribute + */ +struct AttributeStoreMessage +{ + /** + * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * The length of the attribute + */ + uint32_t attr_len GNUNET_PACKED; + + /** + * The expiration interval of the attribute + */ + uint64_t exp GNUNET_PACKED; + + /** + * Identity + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /* followed by the serialized attribute */ + +}; + +/** + * Attribute store response message + */ +struct AttributeStoreResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * #GNUNET_SYSERR on failure, #GNUNET_OK on success + */ + int32_t op_result GNUNET_PACKED; + +}; + +/** + * Attribute is returned from the idp. + */ +struct AttributeResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Length of serialized attribute data + */ + uint16_t attr_len GNUNET_PACKED; + + /** + * always zero (for alignment) + */ + uint16_t reserved GNUNET_PACKED; + + /** + * The public key of the identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /* followed by: + * serialized attribute data + */ +}; + + +/** + * Start a attribute iteration for the given identity + */ +struct AttributeIterationStartMessage +{ + /** + * Message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + +}; + + +/** + * Ask for next result of attribute iteration for the given operation + */ +struct AttributeIterationNextMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + + +/** + * Stop attribute iteration for the given operation + */ +struct AttributeIterationStopMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + +/** + * Start a ticket iteration for the given identity + */ +struct TicketIterationStartMessage +{ + /** + * Message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /** + * Identity is audience or issuer + */ + uint32_t is_audience GNUNET_PACKED; +}; + + +/** + * Ask for next result of ticket iteration for the given operation + */ +struct TicketIterationNextMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + + +/** + * Stop ticket iteration for the given operation + */ +struct TicketIterationStopMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + + + +/** + * Ticket issue message + */ +struct IssueTicketMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Requesting party. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey rp; + + /** + * length of serialized attribute list + */ + uint32_t attr_len GNUNET_PACKED; + + //Followed by a serialized attribute list +}; + +/** + * Ticket revoke message + */ +struct RevokeTicketMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * length of serialized attribute list + */ + uint32_t attrs_len GNUNET_PACKED; + + //Followed by a ticket and serialized attribute list +}; + +/** + * Ticket revoke message + */ +struct RevokeTicketResultMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Revocation result + */ + uint32_t success GNUNET_PACKED; +}; + + +/** + * Ticket result message + */ +struct TicketResultMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + +/** + * Ticket consume message + */ +struct ConsumeTicketMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + //Followed by a serialized ticket +}; + +/** + * Attribute list is returned from the idp. + */ +struct ConsumeTicketResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Length of serialized attribute data + */ + uint16_t attrs_len GNUNET_PACKED; + + /** + * always zero (for alignment) + */ + uint16_t reserved GNUNET_PACKED; + + /** + * The public key of the identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /* followed by: + * serialized attributes data + */ +}; + + + +GNUNET_NETWORK_STRUCT_END + +#endif diff --git a/src/reclaim/reclaim_api.c b/src/reclaim/reclaim_api.c new file mode 100644 index 000000000..3f1584ccd --- /dev/null +++ b/src/reclaim/reclaim_api.c @@ -0,0 +1,1383 @@ +/* + This file is part of GNUnet. + Copyright (C) 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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 + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @file reclaim/reclaim_api.c + * @brief api to interact with the reclaim service + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_protocols.h" +#include "gnunet_mq_lib.h" +#include "gnunet_reclaim_service.h" +#include "gnunet_reclaim_attribute_lib.h" +#include "reclaim.h" + +#define LOG(kind,...) GNUNET_log_from (kind, "reclaim-api",__VA_ARGS__) + + +/** + * Handle for an operation with the service. + */ +struct GNUNET_RECLAIM_Operation +{ + + /** + * Main handle. + */ + struct GNUNET_RECLAIM_Handle *h; + + /** + * We keep operations in a DLL. + */ + struct GNUNET_RECLAIM_Operation *next; + + /** + * We keep operations in a DLL. + */ + struct GNUNET_RECLAIM_Operation *prev; + + /** + * Message to send to the service. + * Allocated at the end of this struct. + */ + const struct GNUNET_MessageHeader *msg; + + /** + * Continuation to invoke after attribute store call + */ + GNUNET_RECLAIM_ContinuationWithStatus as_cb; + + /** + * Attribute result callback + */ + GNUNET_RECLAIM_AttributeResult ar_cb; + + /** + * Revocation result callback + */ + GNUNET_RECLAIM_ContinuationWithStatus rvk_cb; + + /** + * Ticket result callback + */ + GNUNET_RECLAIM_TicketCallback tr_cb; + + /** + * Envelope with the message for this queue entry. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * request id + */ + uint32_t r_id; + + /** + * Closure for @e cont or @e cb. + */ + void *cls; + +}; + +/** + * Handle for a ticket iterator operation + */ +struct GNUNET_RECLAIM_TicketIterator +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_RECLAIM_TicketIterator *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_RECLAIM_TicketIterator *prev; + + /** + * Main handle to access the idp. + */ + struct GNUNET_RECLAIM_Handle *h; + + /** + * Function to call on completion. + */ + GNUNET_SCHEDULER_TaskCallback finish_cb; + + /** + * Closure for @e error_cb. + */ + void *finish_cb_cls; + + /** + * The continuation to call with the results + */ + GNUNET_RECLAIM_TicketCallback tr_cb; + + /** + * Closure for @e tr_cb. + */ + void *cls; + + /** + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; + + /** + * Closure for @e error_cb. + */ + void *error_cb_cls; + + /** + * Envelope of the message to send to the service, if not yet + * sent. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * The operation id this zone iteration operation has + */ + uint32_t r_id; + +}; + + +/** + * Handle for a attribute iterator operation + */ +struct GNUNET_RECLAIM_AttributeIterator +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_RECLAIM_AttributeIterator *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_RECLAIM_AttributeIterator *prev; + + /** + * Main handle to access the idp. + */ + struct GNUNET_RECLAIM_Handle *h; + + /** + * Function to call on completion. + */ + GNUNET_SCHEDULER_TaskCallback finish_cb; + + /** + * Closure for @e error_cb. + */ + void *finish_cb_cls; + + /** + * The continuation to call with the results + */ + GNUNET_RECLAIM_AttributeResult proc; + + /** + * Closure for @e proc. + */ + void *proc_cls; + + /** + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; + + /** + * Closure for @e error_cb. + */ + void *error_cb_cls; + + /** + * Envelope of the message to send to the service, if not yet + * sent. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * Private key of the zone. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * The operation id this zone iteration operation has + */ + uint32_t r_id; + +}; + + +/** + * Handle for the service. + */ +struct GNUNET_RECLAIM_Handle +{ + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * Head of active operations. + */ + struct GNUNET_RECLAIM_Operation *op_head; + + /** + * Tail of active operations. + */ + struct GNUNET_RECLAIM_Operation *op_tail; + + /** + * Head of active iterations + */ + struct GNUNET_RECLAIM_AttributeIterator *it_head; + + /** + * Tail of active iterations + */ + struct GNUNET_RECLAIM_AttributeIterator *it_tail; + + /** + * Head of active iterations + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it_head; + + /** + * Tail of active iterations + */ + struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail; + + + /** + * Currently pending transmission request, or NULL for none. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * Task doing exponential back-off trying to reconnect. + */ + struct GNUNET_SCHEDULER_Task * reconnect_task; + + /** + * Time for next connect retry. + */ + struct GNUNET_TIME_Relative reconnect_backoff; + + /** + * Connection to service (if available). + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Request Id generator. Incremented by one for each request. + */ + uint32_t r_id_gen; + + /** + * Are we polling for incoming messages right now? + */ + int in_receive; + +}; + +/** + * Try again to connect to the service. + * + * @param h handle to the reclaim service. + */ +static void +reconnect (struct GNUNET_RECLAIM_Handle *h); + +/** + * Reconnect + * + * @param cls the handle + */ +static void +reconnect_task (void *cls) +{ + struct GNUNET_RECLAIM_Handle *handle = cls; + + handle->reconnect_task = NULL; + reconnect (handle); +} + + +/** + * Disconnect from service and then reconnect. + * + * @param handle our service + */ +static void +force_reconnect (struct GNUNET_RECLAIM_Handle *handle) +{ + GNUNET_MQ_destroy (handle->mq); + handle->mq = NULL; + handle->reconnect_backoff + = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff); + handle->reconnect_task + = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff, + &reconnect_task, + handle); +} + +/** + * Free @a it. + * + * @param it entry to free + */ +static void +free_it (struct GNUNET_RECLAIM_AttributeIterator *it) +{ + struct GNUNET_RECLAIM_Handle *h = it->h; + + GNUNET_CONTAINER_DLL_remove (h->it_head, + h->it_tail, + it); + if (NULL != it->env) + GNUNET_MQ_discard (it->env); + GNUNET_free (it); +} + +static void +free_op (struct GNUNET_RECLAIM_Operation* op) +{ + if (NULL == op) + return; + if (NULL != op->env) + GNUNET_MQ_discard (op->env); + GNUNET_free(op); +} + + +/** + * Generic error handler, called with the appropriate error code and + * the same closure specified at the creation of the message queue. + * Not every message queue implementation supports an error handler. + * + * @param cls closure with the `struct GNUNET_GNS_Handle *` + * @param error error code + */ +static void +mq_error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct GNUNET_RECLAIM_Handle *handle = cls; + force_reconnect (handle); +} + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE + * + * @param cls + * @param msg the message we received + */ +static void +handle_attribute_store_response (void *cls, + const struct AttributeStoreResultMessage *msg) +{ + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_Operation *op; + uint32_t r_id = ntohl (msg->id); + int res; + const char *emsg; + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + + res = ntohl (msg->op_result); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_STORE_RESPONSE with result %d\n", + res); + + /* TODO: add actual error message to response... */ + if (GNUNET_SYSERR == res) + emsg = _("failed to store record\n"); + else + emsg = NULL; + if (NULL != op->as_cb) + op->as_cb (op->cls, + res, + emsg); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + free_op (op); + +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_consume_ticket_result (void *cls, + const struct ConsumeTicketResultMessage *msg) +{ + size_t msg_len; + size_t attrs_len; + + msg_len = ntohs (msg->header.size); + attrs_len = ntohs (msg->attrs_len); + if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_consume_ticket_result (void *cls, + const struct ConsumeTicketResultMessage *msg) +{ + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_Operation *op; + size_t attrs_len; + uint32_t r_id = ntohl (msg->id); + + attrs_len = ntohs (msg->attrs_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing attribute result.\n"); + + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + + { + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&msg[1], + attrs_len); + if (NULL != op->ar_cb) + { + if (NULL == attrs) + { + op->ar_cb (op->cls, + &msg->identity, + NULL); + } + else + { + for (le = attrs->list_head; NULL != le; le = le->next) + op->ar_cb (op->cls, + &msg->identity, + le->claim); + GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs); + } + } + if (NULL != op) + { + op->ar_cb (op->cls, + NULL, + NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + free_op (op); + } + return; + } + GNUNET_assert (0); +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_attribute_result (void *cls, + const struct AttributeResultMessage *msg) +{ + size_t msg_len; + size_t attr_len; + + msg_len = ntohs (msg->header.size); + attr_len = ntohs (msg->attr_len); + if (msg_len != sizeof (struct AttributeResultMessage) + attr_len) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_attribute_result (void *cls, + const struct AttributeResultMessage *msg) +{ + static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy; + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_AttributeIterator *it; + struct GNUNET_RECLAIM_Operation *op; + size_t attr_len; + uint32_t r_id = ntohl (msg->id); + + attr_len = ntohs (msg->attr_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing attribute result.\n"); + + + for (it = h->it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if ((NULL == it) && (NULL == op)) + return; + + if ( (0 == (memcmp (&msg->identity, + &identity_dummy, + sizeof (identity_dummy)))) ) + { + if ((NULL == it) && (NULL == op)) + { + GNUNET_break (0); + force_reconnect (h); + return; + } + if (NULL != it) + { + if (NULL != it->finish_cb) + it->finish_cb (it->finish_cb_cls); + free_it (it); + } + if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, + NULL, + NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + free_op (op); + + } + return; + } + + { + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr; + attr = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&msg[1], + attr_len); + if (NULL != it) + { + if (NULL != it->proc) + it->proc (it->proc_cls, + &msg->identity, + attr); + } else if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, + &msg->identity, + attr); + + } + GNUNET_free (attr); + return; + } + GNUNET_assert (0); +} + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_ticket_result (void *cls, + const struct TicketResultMessage *msg) +{ + size_t msg_len; + + msg_len = ntohs (msg->header.size); + if (msg_len < sizeof (struct TicketResultMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_ticket_result (void *cls, + const struct TicketResultMessage *msg) +{ + struct GNUNET_RECLAIM_Handle *handle = cls; + struct GNUNET_RECLAIM_Operation *op; + struct GNUNET_RECLAIM_TicketIterator *it; + const struct GNUNET_RECLAIM_Ticket *ticket; + uint32_t r_id = ntohl (msg->id); + size_t msg_len; + + for (op = handle->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + for (it = handle->ticket_it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + if ((NULL == op) && (NULL == it)) + return; + msg_len = ntohs (msg->header.size); + if (NULL != op) + { + GNUNET_CONTAINER_DLL_remove (handle->op_head, + handle->op_tail, + op); + if (msg_len == sizeof (struct TicketResultMessage)) + { + if (NULL != op->tr_cb) + op->tr_cb (op->cls, NULL); + } else { + ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1]; + if (NULL != op->tr_cb) + op->tr_cb (op->cls, ticket); + } + free_op (op); + return; + } else if (NULL != it) { + if (msg_len == sizeof (struct TicketResultMessage)) + { + if (NULL != it->tr_cb) + GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head, + handle->ticket_it_tail, + it); + it->finish_cb (it->finish_cb_cls); + GNUNET_free (it); + } else { + ticket = (struct GNUNET_RECLAIM_Ticket *)&msg[1]; + if (NULL != it->tr_cb) + it->tr_cb (it->cls, ticket); + } + return; + } + GNUNET_break (0); +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_revoke_ticket_result (void *cls, + const struct RevokeTicketResultMessage *msg) +{ + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_Operation *op; + uint32_t r_id = ntohl (msg->id); + int32_t success; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing revocation result.\n"); + + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + success = ntohl (msg->success); + { + if (NULL != op->rvk_cb) + { + op->rvk_cb (op->cls, + success, + NULL); + } + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + free_op (op); + return; + } + GNUNET_assert (0); +} + + + +/** + * Try again to connect to the service. + * + * @param h handle to the reclaim service. + */ +static void +reconnect (struct GNUNET_RECLAIM_Handle *h) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_fixed_size (attribute_store_response, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE, + struct AttributeStoreResultMessage, + h), + GNUNET_MQ_hd_var_size (attribute_result, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT, + struct AttributeResultMessage, + h), + GNUNET_MQ_hd_var_size (ticket_result, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT, + struct TicketResultMessage, + h), + GNUNET_MQ_hd_var_size (consume_ticket_result, + GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT, + struct ConsumeTicketResultMessage, + h), + GNUNET_MQ_hd_fixed_size (revoke_ticket_result, + GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT, + struct RevokeTicketResultMessage, + h), + GNUNET_MQ_handler_end () + }; + struct GNUNET_RECLAIM_Operation *op; + + GNUNET_assert (NULL == h->mq); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Connecting to reclaim service.\n"); + + h->mq = GNUNET_CLIENT_connect (h->cfg, + "reclaim", + handlers, + &mq_error_handler, + h); + if (NULL == h->mq) + return; + for (op = h->op_head; NULL != op; op = op->next) + GNUNET_MQ_send_copy (h->mq, + op->env); +} + + +/** + * Connect to the reclaim service. + * + * @param cfg the configuration to use + * @return handle to use + */ +struct GNUNET_RECLAIM_Handle * +GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_RECLAIM_Handle *h; + + h = GNUNET_new (struct GNUNET_RECLAIM_Handle); + h->cfg = cfg; + reconnect (h); + if (NULL == h->mq) + { + GNUNET_free (h); + return NULL; + } + return h; +} + + +/** + * Cancel an operation. Note that the operation MAY still + * be executed; this merely cancels the continuation; if the request + * was already transmitted, the service may still choose to complete + * the operation. + * + * @param op operation to cancel + */ +void +GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op) +{ + struct GNUNET_RECLAIM_Handle *h = op->h; + + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + free_op (op); +} + + +/** + * Disconnect from service + * + * @param h handle to destroy + */ +void +GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h) +{ + GNUNET_assert (NULL != h); + if (NULL != h->mq) + { + GNUNET_MQ_destroy (h->mq); + h->mq = NULL; + } + if (NULL != h->reconnect_task) + { + GNUNET_SCHEDULER_cancel (h->reconnect_task); + h->reconnect_task = NULL; + } + GNUNET_assert (NULL == h->op_head); + GNUNET_free (h); +} + +/** + * Store an attribute. If the attribute is already present, + * it is replaced with the new attribute. + * + * @param h handle to the reclaim + * @param pkey private key of the identity + * @param attr the attribute value + * @param exp_interval the relative expiration interval for the attribute + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attribute_store (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct AttributeStoreMessage *sam; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (sam, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE); + sam->identity = *pkey; + sam->id = htonl (op->r_id); + sam->exp = GNUNET_htonll (exp_interval->rel_value_us); + + GNUNET_RECLAIM_ATTRIBUTE_serialize (attr, + (char*)&sam[1]); + + sam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; + +} + + +/** + * List all attributes for a local identity. + * This MUST lock the `struct GNUNET_RECLAIM_Handle` + * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and + * #GNUNET_RECLAIM_get_attributes_stop. @a proc will be called once + * immediately, and then again after + * #GNUNET_RECLAIM_get_attributes_next() is invoked. + * + * On error (disconnect), @a error_cb will be invoked. + * On normal completion, @a finish_cb proc will be + * invoked. + * + * @param h handle to the idp + * @param identity identity to access + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each attribute; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_AttributeIterator * +GNUNET_RECLAIM_get_attributes_start (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_AttributeResult proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) +{ + struct GNUNET_RECLAIM_AttributeIterator *it; + struct GNUNET_MQ_Envelope *env; + struct AttributeIterationStartMessage *msg; + uint32_t rid; + + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->proc = proc; + it->proc_cls = proc_cls; + it->r_id = rid; + it->identity = *identity; + GNUNET_CONTAINER_DLL_insert_tail (h->it_head, + h->it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START); + msg->id = htonl (rid); + msg->identity = *identity; + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; +} + + +/** + * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it) +{ + struct GNUNET_RECLAIM_Handle *h = it->h; + struct AttributeIterationNextMessage *msg; + struct GNUNET_MQ_Envelope *env; + + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); +} + + +/** + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_RECLAIM_disconnect. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it) +{ + struct GNUNET_RECLAIM_Handle *h = it->h; + struct GNUNET_MQ_Envelope *env; + struct AttributeIterationStopMessage *msg; + + if (NULL != h->mq) + { + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); + } + free_it (it); +} + + +/** TODO + * Issues a ticket to another identity. The identity may use + * @GNUNET_RECLAIM_authorization_ticket_consume to consume the ticket + * and retrieve the attributes specified in the AttributeList. + * + * @param h the reclaim to use + * @param iss the issuing identity + * @param rp the subject of the ticket (the relying party) + * @param attrs the attributes that the relying party is given access to + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_issue (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, + const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + GNUNET_RECLAIM_TicketCallback cb, + void *cb_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct IssueTicketMessage *tim; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->tr_cb = cb; + op->cls = cb_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + attr_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs); + op->env = GNUNET_MQ_msg_extra (tim, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET); + tim->identity = *iss; + tim->rp = *rp; + tim->id = htonl (op->r_id); + + GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, + (char*)&tim[1]); + + tim->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; +} + +/** + * Consumes an issued ticket. The ticket is persisted + * and used to retrieve identity information from the issuer + * + * @param h the reclaim to use + * @param identity the identity that is the subject of the issued ticket (the relying party) + * @param ticket the issued ticket to consume + * @param cb the callback to call + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_consume (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_AttributeResult cb, + void *cb_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct ConsumeTicketMessage *ctm; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->ar_cb = cb; + op->cls = cb_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + op->env = GNUNET_MQ_msg_extra (ctm, + sizeof (const struct GNUNET_RECLAIM_Ticket), + GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET); + ctm->identity = *identity; + ctm->id = htonl (op->r_id); + + GNUNET_memcpy ((char*)&ctm[1], + ticket, + sizeof (const struct GNUNET_RECLAIM_Ticket)); + + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; + +} + + +/** + * Lists all tickets that have been issued to remote + * identites (relying parties) + * + * @param h the reclaim to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_TicketIterator * +GNUNET_RECLAIM_ticket_iteration_start (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) +{ + struct GNUNET_RECLAIM_TicketIterator *it; + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStartMessage *msg; + uint32_t rid; + + GNUNET_CRYPTO_ecdsa_key_get_public (identity, + &identity_pub); + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->tr_cb = proc; + it->cls = proc_cls; + it->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, + h->ticket_it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START); + msg->id = htonl (rid); + msg->identity = identity_pub; + msg->is_audience = htonl (GNUNET_NO); + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; + +} + + +/** + * Lists all tickets that have been issued to remote + * identites (relying parties) + * + * @param h the reclaim to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_RECLAIM_TicketIterator * +GNUNET_RECLAIM_ticket_iteration_start_rp (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_RECLAIM_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) +{ + struct GNUNET_RECLAIM_TicketIterator *it; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStartMessage *msg; + uint32_t rid; + + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->tr_cb = proc; + it->cls = proc_cls; + it->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, + h->ticket_it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START); + msg->id = htonl (rid); + msg->identity = *identity; + msg->is_audience = htonl (GNUNET_YES); + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; + + +} + +/** + * Calls the record processor specified in #GNUNET_RECLAIM_ticket_iteration_start + * for the next record. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it) +{ + struct GNUNET_RECLAIM_Handle *h = it->h; + struct TicketIterationNextMessage *msg; + struct GNUNET_MQ_Envelope *env; + + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); +} + + +/** + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_RECLAIM_disconnect. + * + * @param it the iterator + */ +void +GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it) +{ + struct GNUNET_RECLAIM_Handle *h = it->h; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStopMessage *msg; + + if (NULL != h->mq) + { + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); + } + GNUNET_free (it); +} + +/** + * Revoked an issued ticket. The relying party will be unable to retrieve + * updated attributes. + * + * @param h the reclaim to use + * @param identity the issuing identity + * @param ticket the ticket to revoke + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_ticket_revoke (struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_RECLAIM_Ticket *ticket, + GNUNET_RECLAIM_ContinuationWithStatus cb, + void *cb_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct RevokeTicketMessage *msg; + uint32_t rid; + + rid = h->r_id_gen++; + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->rvk_cb = cb; + op->cls = cb_cls; + op->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + op->env = GNUNET_MQ_msg_extra (msg, + sizeof (struct GNUNET_RECLAIM_Ticket), + GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET); + msg->id = htonl (rid); + msg->identity = *identity; + GNUNET_memcpy (&msg[1], + ticket, + sizeof (struct GNUNET_RECLAIM_Ticket)); + if (NULL != h->mq) { + GNUNET_MQ_send (h->mq, + op->env); + op->env = NULL; + } + return op; +} + + + +/* end of reclaim_api.c */ diff --git a/src/reclaim/test_reclaim.sh b/src/reclaim/test_reclaim.sh new file mode 100755 index 000000000..311f5382a --- /dev/null +++ b/src/reclaim/test_reclaim.sh @@ -0,0 +1,31 @@ +#!/bin/bash +#trap "gnunet-arm -e -c test_reclaim_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_reclaim.conf +gnunet-identity -C testego -c test_reclaim.conf +valgrind gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf +gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf +gnunet-reclaim -e testego -D -c test_reclaim.conf +gnunet-arm -e -c test_reclaim.conf diff --git a/src/reclaim/test_reclaim_attribute.sh b/src/reclaim/test_reclaim_attribute.sh new file mode 100755 index 000000000..39bd715b7 --- /dev/null +++ b/src/reclaim/test_reclaim_attribute.sh @@ -0,0 +1,40 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_reclaim.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_reclaim.conf +#gnunet-arm -i rest -c test_reclaim.conf +gnunet-identity -C testego -c test_reclaim.conf +gnunet-identity -C rpego -c test_reclaim.conf +TEST_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep testego | awk '{print $3}') +gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf +gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf > /dev/null 2>&1 +if test $? != 0 +then + echo "Failed." + exit 1 +fi + +#curl localhost:7776/reclaim/attributes/testego +gnunet-arm -e -c test_reclaim.conf diff --git a/src/reclaim/test_reclaim_consume.sh b/src/reclaim/test_reclaim_consume.sh new file mode 100755 index 000000000..36c8052d0 --- /dev/null +++ b/src/reclaim/test_reclaim_consume.sh @@ -0,0 +1,43 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_reclaim.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_reclaim.conf +#gnunet-arm -i rest -c test_reclaim.conf +gnunet-identity -C testego -c test_reclaim.conf +gnunet-identity -C rpego -c test_reclaim.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep rpego | awk '{print $3}') +TEST_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep testego | awk '{print $3}') +gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf +gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf +TICKET=$(gnunet-reclaim -e testego -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf | awk '{print $1}') +gnunet-reclaim -e rpego -C $TICKET -c test_reclaim.conf > /dev/null 2>&1 + +if test $? != 0 +then + "Failed." + exit 1 +fi +#curl http://localhost:7776/reclaim/tickets/testego +gnunet-arm -e -c test_reclaim.conf diff --git a/src/reclaim/test_reclaim_defaults.conf b/src/reclaim/test_reclaim_defaults.conf new file mode 100644 index 000000000..a9a197dea --- /dev/null +++ b/src/reclaim/test_reclaim_defaults.conf @@ -0,0 +1,24 @@ +@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf + +[PATHS] +GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-idp-testing/ + +[namestore-sqlite] +FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db + +[namecache-sqlite] +FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db + +[identity] +# Directory where we store information about our egos +EGODIR = $GNUNET_TEST_HOME/identity/egos/ + +[dhtcache] +DATABASE = heap + +[transport] +PLUGINS = tcp + +[transport-tcp] +BINDTO = 127.0.0.1 + diff --git a/src/reclaim/test_reclaim_issue.sh b/src/reclaim/test_reclaim_issue.sh new file mode 100755 index 000000000..6a71470e1 --- /dev/null +++ b/src/reclaim/test_reclaim_issue.sh @@ -0,0 +1,42 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_reclaim.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_reclaim.conf +#gnunet-arm -i rest -c test_reclaim.conf +gnunet-identity -C testego -c test_reclaim.conf +gnunet-identity -C rpego -c test_reclaim.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep rpego | awk '{print $3}') +TEST_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep testego | awk '{print $3}') +gnunet-reclaim -e testego -a email -V john@doe.gnu -c test_reclaim.conf > /dev/null 2>&1 +gnunet-reclaim -e testego -a name -V John -c test_reclaim.conf > /dev/null 2>&1 +#gnunet-reclaim -e testego -D -c test_reclaim.conf +gnunet-reclaim -e testego -i "email,name" -r $SUBJECT_KEY -c test_reclaim.conf > /dev/null 2>&1 +if test $? != 0 +then + echo "Failed." + exit 1 +fi +#curl http://localhost:7776/reclaim/attributes/testego +gnunet-arm -e -c test_reclaim.conf diff --git a/src/reclaim/test_reclaim_revoke.sh b/src/reclaim/test_reclaim_revoke.sh new file mode 100755 index 000000000..595752fd8 --- /dev/null +++ b/src/reclaim/test_reclaim_revoke.sh @@ -0,0 +1,65 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_reclaim.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_reclaim.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_reclaim.conf 2&>1 > /dev/null +gnunet-identity -C alice -c test_reclaim.conf +gnunet-identity -C bob -c test_reclaim.conf +gnunet-identity -C eve -c test_reclaim.conf +ALICE_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep alice | awk '{print $3}') +BOB_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep bob | awk '{print $3}') +EVE_KEY=$(gnunet-identity -d -c test_reclaim.conf | grep eve | awk '{print $3}') + +gnunet-reclaim -e alice -E 15s -a email -V john@doe.gnu -c test_reclaim.conf +gnunet-reclaim -e alice -E 15s -a name -V John -c test_reclaim.conf +TICKET_BOB=$(gnunet-reclaim -e alice -i "email,name" -r $BOB_KEY -c test_reclaim.conf | awk '{print $1}') +#gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf +TICKET_EVE=$(gnunet-reclaim -e alice -i "email" -r $EVE_KEY -c test_reclaim.conf | awk '{print $1}') + +#echo "Consuming $TICKET" +#gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf +gnunet-reclaim -e alice -R $TICKET_EVE -c test_reclaim.conf + +#sleep 6 + +gnunet-reclaim -e eve -C $TICKET_EVE -c test_reclaim.conf 2&>1 >/dev/null +if test $? == 0 +then + echo "Eve can still resolve attributes..." + gnunet-arm -e -c test_reclaim.conf + exit 1 +fi + +gnunet-arm -e -c test_reclaim.conf +gnunet-arm -s -c test_reclaim.conf 2&>1 > /dev/null + +gnunet-reclaim -e bob -C $TICKET_BOB -c test_reclaim.conf 2&>1 >/dev/null +if test $? != 0 +then + echo "Bob cannot resolve attributes..." + gnunet-arm -e -c test_reclaim.conf + exit 1 +fi + +gnunet-arm -e -c test_reclaim.conf