Merge remote-tracking branch 'origin/master' into credentials
authorSchanzenbach, Martin <mschanzenbach@posteo.de>
Mon, 3 Jul 2017 08:31:57 +0000 (10:31 +0200)
committerSchanzenbach, Martin <mschanzenbach@posteo.de>
Mon, 3 Jul 2017 08:31:57 +0000 (10:31 +0200)
44 files changed:
configure.ac
po/POTFILES.in
src/Makefile.am
src/credential/Makefile.am [new file with mode: 0644]
src/credential/credential.conf.in [new file with mode: 0644]
src/credential/credential.h [new file with mode: 0644]
src/credential/credential_api.c [new file with mode: 0644]
src/credential/credential_misc.c [new file with mode: 0644]
src/credential/credential_misc.h [new file with mode: 0644]
src/credential/credential_serialization.c [new file with mode: 0644]
src/credential/credential_serialization.h [new file with mode: 0644]
src/credential/gnunet-credential.c [new file with mode: 0644]
src/credential/gnunet-service-credential.c [new file with mode: 0644]
src/credential/plugin_gnsrecord_credential.c [new file with mode: 0644]
src/credential/plugin_rest_credential.c [new file with mode: 0644]
src/credential/test_credential_collect.sh [new file with mode: 0755]
src/credential/test_credential_collect_rest.sh [new file with mode: 0755]
src/credential/test_credential_defaults.conf [new file with mode: 0644]
src/credential/test_credential_issue.sh [new file with mode: 0755]
src/credential/test_credential_issue_rest.sh [new file with mode: 0755]
src/credential/test_credential_lookup.conf [new file with mode: 0644]
src/credential/test_credential_verify.sh [new file with mode: 0755]
src/credential/test_credential_verify_and.sh [new file with mode: 0755]
src/credential/test_credential_verify_rest.sh [new file with mode: 0755]
src/credential/test_credential_verify_simple.sh [new file with mode: 0755]
src/exit/gnunet-daemon-exit.c
src/gns/gns_api.c
src/gns/plugin_gnsrecord_gns.c
src/identity-provider/Makefile.am
src/identity-provider/gnunet-service-identity-provider.c
src/identity-provider/identity_provider.h
src/identity-provider/identity_provider_api.c
src/identity-provider/identity_token.c
src/identity-provider/identity_token.h
src/identity-provider/plugin_rest_identity_provider.c
src/identity/plugin_rest_identity.c
src/include/gnunet_credential_service.h
src/include/gnunet_gnsrecord_lib.h
src/include/gnunet_identity_provider_service.h
src/include/gnunet_protocols.h
src/include/gnunet_signatures.h
src/jsonapi/jsonapi_document.c
src/jsonapi/jsonapi_resource.c
src/namestore/plugin_rest_namestore.c

index c16fbdcbafde5aba2754b5f2960c3dcc9b99ee3f..8a2ab926276d7baab87a8802dc3d004bf185013e 100644 (file)
@@ -1588,6 +1588,8 @@ src/gnsrecord/Makefile
 src/hello/Makefile
 src/identity/Makefile
 src/identity/identity.conf
+src/credential/Makefile
+src/credential/credential.conf
 src/include/Makefile
 src/integration-tests/Makefile
 src/json/Makefile
index 43a5dcb08bbc542a143069232e8e4600df888416..50c1828336f7cda65384eba8bef57361aec21b28 100644 (file)
@@ -75,6 +75,10 @@ src/core/gnunet-service-core.c
 src/core/gnunet-service-core_kx.c
 src/core/gnunet-service-core_sessions.c
 src/core/gnunet-service-core_typemap.c
+src/credential/credential_api.c
+src/credential/gnunet-credential.c
+src/credential/gnunet-service-credential.c
+src/credential/plugin_gnsrecord_credential.c
 src/curl/curl.c
 src/curl/curl_reschedule.c
 src/datacache/datacache.c
index 14c66c5f700135f21b97ae153daf37c48858c3fa..e4d7d8924f0533f43533f9004e56849fc8f135bf 100644 (file)
@@ -116,6 +116,7 @@ SUBDIRS = \
   revocation \
   vpn \
   gns \
+       credential \
   zonemaster \
   $(CONVERSATION_DIR) \
   fs \
diff --git a/src/credential/Makefile.am b/src/credential/Makefile.am
new file mode 100644 (file)
index 0000000..ca11c5e
--- /dev/null
@@ -0,0 +1,112 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+EXTRA_DIST = \
+  test_credential_defaults.conf \
+  test_credential_lookup.conf
+
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+endif
+
+pkgcfgdir = $(pkgdatadir)/config.d/
+
+libexecdir= $(pkglibdir)/libexec/
+
+plugindir = $(libdir)/gnunet
+
+pkgcfg_DATA = \
+  credential.conf
+
+
+# /usr/lib - compiles a layer which can be used to be communicagte with the service
+lib_LTLIBRARIES = \
+  libgnunetcredential.la
+
+# /usr/lib/gnunet/libexec - Business logic . Separate process 
+libexec_PROGRAMS = \
+  gnunet-service-credential 
+
+bin_PROGRAMS = \
+  gnunet-credential
+
+plugin_LTLIBRARIES = \
+  libgnunet_plugin_gnsrecord_credential.la
+
+
+if HAVE_MHD
+if HAVE_JSON
+plugin_LTLIBRARIES += libgnunet_plugin_rest_credential.la
+endif
+endif
+
+
+gnunet_credential_SOURCES = \
+ gnunet-credential.c
+gnunet_credential_LDADD = \
+  libgnunetcredential.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+       $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+  $(top_builddir)/src/identity/libgnunetidentity.la \
+  $(GN_LIBINTL)
+
+
+libgnunet_plugin_gnsrecord_credential_la_SOURCES = \
+  plugin_gnsrecord_credential.c
+libgnunet_plugin_gnsrecord_credential_la_LIBADD = \
+       libgnunetcredential.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(LTLIBINTL)
+libgnunet_plugin_gnsrecord_credential_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+
+
+gnunet_service_credential_SOURCES = \
+ gnunet-service-credential.c
+gnunet_service_credential_LDADD = \
+       libgnunetcredential.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+       $(top_builddir)/src/gns/libgnunetgns.la \
+       $(top_builddir)/src/namestore/libgnunetnamestore.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(GN_LIBINTL)
+
+
+libgnunetcredential_la_SOURCES = \
+ credential_api.c \
+ credential_serialization.c \
+ credential_misc.c
+libgnunetcredential_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) 
+libgnunetcredential_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS)
+
+
+libgnunet_plugin_rest_credential_la_SOURCES = \
+  plugin_rest_credential.c
+libgnunet_plugin_rest_credential_la_LIBADD = \
+  libgnunetcredential.la \
+       $(top_builddir)/src/rest/libgnunetrest.la \
+       $(top_builddir)/src/identity/libgnunetidentity.la \
+       $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \
+  $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \
+  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \
+  $(LTLIBINTL) -ljansson -lmicrohttpd
+libgnunet_plugin_rest_credential_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+
+check_SCRIPTS = \
+  test_credential_issue.sh \
+       test_credential_verify_simple.sh \
+       test_credential_verify.sh \
+       test_credential_verify_and.sh
+
+if ENABLE_TEST_RUN
+if HAVE_SQLITE
+ AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;
+ TESTS = $(check_SCRIPTS)
+endif
+endif
diff --git a/src/credential/credential.conf.in b/src/credential/credential.conf.in
new file mode 100644 (file)
index 0000000..71f3066
--- /dev/null
@@ -0,0 +1,5 @@
+[credential]
+BINARY = gnunet-service-credential
+UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-credential.sock
+USER_SERVICE = YES
+OPTIONS = -L DEBUG
\ No newline at end of file
diff --git a/src/credential/credential.h b/src/credential/credential.h
new file mode 100644 (file)
index 0000000..f16249c
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+      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 General Public License as published
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+      Boston, MA 02110-1301, USA.
+ */
+/**
+ * @file credential/credential.h
+ * @brief IPC messages between CREDENTIAL API and CREDENTIAL service
+ * @author Adnan Husain 
+ */
+#ifndef CREDENTIAL_H
+#define CREDENTIAL_H
+
+#include "gnunet_credential_service.h"
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message from client to Credential service to collect credentials.
+ */
+struct CollectMessage
+{
+  /**
+   * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Subject public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPrivateKey subject_key;
+
+  /**
+   * Trust anchor
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Length of the issuer attribute
+   */
+  uint16_t issuer_attribute_len;
+
+  /**
+   * Unique identifier for this request (for key collisions).
+   */
+  uint32_t id GNUNET_PACKED;
+
+  /* Followed by the zero-terminated attribute */
+
+};
+
+
+/**
+ * Message from client to Credential service to verify attributes.
+ */
+struct VerifyMessage
+{
+  /**
+   * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Subject public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Trust anchor
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Number of credentials
+   */
+  uint32_t c_count;
+
+  /**
+   * Length of the issuer attribute
+   */
+  uint16_t issuer_attribute_len;
+
+  /**
+   * Unique identifier for this request (for key collisions).
+   */
+  uint32_t id GNUNET_PACKED;
+
+  /* Followed by the zero-terminated attribute and credentials to look up */
+
+};
+
+
+/**
+ * Message from CREDENTIAL service to client: new results.
+ */
+struct DelegationChainResultMessage
+{
+  /**
+    * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Unique identifier for this request (for key collisions).
+   */
+  uint32_t id GNUNET_PACKED;
+  
+  /**
+   * Indicates if credential has been found at all
+   */
+  uint32_t cred_found GNUNET_PACKED;
+
+  /**
+   * The number of delegations in the response
+   */
+  uint32_t d_count GNUNET_PACKED;
+
+  /**
+   * The number of credentials in the response
+   */
+  uint32_t c_count GNUNET_PACKED;
+
+  /* followed by ad_count GNUNET_CREDENTIAL_RecordData structs*/
+
+};
+
+struct DelegationRecordData
+{
+  /**
+   * Subject key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+  
+  /**
+   * Subject attributes
+   */
+  uint32_t subject_attribute_len GNUNET_PACKED;
+};
+
+
+struct ChainEntry
+{
+  /**
+   * Issuer key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+  
+  /**
+   * Subject key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+  
+  /**
+   * Issuer attributes
+   */
+  uint32_t issuer_attribute_len GNUNET_PACKED;
+  
+  /**
+   * Subject attributes
+   */
+  uint32_t subject_attribute_len GNUNET_PACKED;
+};
+
+
+struct CredentialEntry
+{
+
+  /**
+   * The signature for this credential by the issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+  /**
+   * Signature meta
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * Public key of the issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Public key of the subject this credential was issued to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Expiration time of this credential
+   */
+  uint64_t expiration GNUNET_PACKED;
+   
+  /**
+   * Issuer attribute length
+   */
+  uint32_t issuer_attribute_len;
+
+  /**
+   * Followed by the attribute string
+   */
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+#endif
+
diff --git a/src/credential/credential_api.c b/src/credential/credential_api.c
new file mode 100644 (file)
index 0000000..ca54137
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013, 2016 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file credential/credential_api.c
+ * @brief library to access the CREDENTIAL service
+ * @author Adnan Husain
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_signatures.h"
+#include "credential.h"
+#include "credential_serialization.h"
+#include "gnunet_credential_service.h"
+#include "gnunet_identity_service.h"
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "credential-api",__VA_ARGS__)
+
+/**
+ * Handle to a verify request
+ */
+struct GNUNET_CREDENTIAL_Request
+{
+
+  /**
+   * DLL
+   */
+  struct GNUNET_CREDENTIAL_Request *next;
+
+  /**
+   * DLL
+   */
+  struct GNUNET_CREDENTIAL_Request *prev;
+
+  /**
+   * handle to credential service
+   */
+  struct GNUNET_CREDENTIAL_Handle *credential_handle;
+
+  /**
+   * processor to call on verify result
+   */
+  GNUNET_CREDENTIAL_CredentialResultProcessor verify_proc;
+
+  /**
+   * @e verify_proc closure
+   */
+  void *proc_cls;
+
+  /**
+   * Envelope with the message for this queue entry.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+  /**
+   * request id
+   */
+  uint32_t r_id;
+
+};
+
+
+/**
+ * Connection to the CREDENTIAL service.
+ */
+struct GNUNET_CREDENTIAL_Handle
+{
+
+  /**
+   * Configuration to use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Connection to service (if available).
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Head of linked list of active verify requests.
+   */
+  struct GNUNET_CREDENTIAL_Request *request_head;
+
+  /**
+   * Tail of linked list of active verify requests.
+   */
+  struct GNUNET_CREDENTIAL_Request *request_tail;
+
+  /**
+   * Reconnect task
+   */
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
+
+  /**
+   * How long do we wait until we try to reconnect?
+   */
+  struct GNUNET_TIME_Relative reconnect_backoff;
+
+  /**
+   * Request Id generator.  Incremented by one for each request.
+   */
+  uint32_t r_id_gen;
+
+};
+
+
+/**
+ * Reconnect to CREDENTIAL service.
+ *
+ * @param handle the handle to the CREDENTIAL service
+ */
+static void
+reconnect (struct GNUNET_CREDENTIAL_Handle *handle);
+
+
+/**
+ * Reconnect to CREDENTIAL
+ *
+ * @param cls the handle
+ */
+static void
+reconnect_task (void *cls)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = cls;
+
+  handle->reconnect_task = NULL;
+  reconnect (handle);
+}
+
+
+/**
+ * Disconnect from service and then reconnect.
+ *
+ * @param handle our handle
+ */
+static void
+force_reconnect (struct GNUNET_CREDENTIAL_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);
+}
+
+
+/**
+ * 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_CREDENTIAL_Handle *`
+ * @param error error code
+ */
+static void
+mq_error_handler (void *cls,
+                  enum GNUNET_MQ_Error error)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = cls;
+
+  force_reconnect (handle);
+}
+
+/**
+ * Check validity of message received from the CREDENTIAL service
+ *
+ * @param cls the `struct GNUNET_CREDENTIAL_Handle *`
+ * @param loookup_msg the incoming message
+ */
+static int
+check_result (void *cls,
+              const struct DelegationChainResultMessage *vr_msg)
+{
+  //TODO
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handler for messages received from the CREDENTIAL service
+ *
+ * @param cls the `struct GNUNET_CREDENTIAL_Handle *`
+ * @param loookup_msg the incoming message
+ */
+static void
+handle_result (void *cls,
+               const struct DelegationChainResultMessage *vr_msg)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = cls;
+  uint32_t r_id = ntohl (vr_msg->id);
+  struct GNUNET_CREDENTIAL_Request *vr;
+  size_t mlen = ntohs (vr_msg->header.size) - sizeof (*vr_msg);
+  uint32_t d_count = ntohl (vr_msg->d_count);
+  uint32_t c_count = ntohl (vr_msg->c_count);
+  struct GNUNET_CREDENTIAL_Delegation d_chain[d_count];
+  struct GNUNET_CREDENTIAL_Credential creds[c_count];
+  GNUNET_CREDENTIAL_CredentialResultProcessor proc;
+  void *proc_cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received verify reply from CREDENTIAL service\n");
+  for (vr = handle->request_head; NULL != vr; vr = vr->next)
+    if (vr->r_id == r_id)
+      break;
+  if (NULL == vr)
+    return;
+  proc = vr->verify_proc;
+  proc_cls = vr->proc_cls;
+  GNUNET_CONTAINER_DLL_remove (handle->request_head,
+                               handle->request_tail,
+                               vr);
+  GNUNET_MQ_discard (vr->env);
+  GNUNET_free (vr);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CREDENTIAL_delegation_chain_deserialize (mlen,
+                                                                 (const char*) &vr_msg[1],
+                                                                 d_count,
+                                                                 d_chain,
+                                                                 c_count,
+                                                                 creds));
+  if (GNUNET_NO == ntohl (vr_msg->cred_found))
+  {
+    proc (proc_cls,
+          0,
+          NULL,
+          0,
+          NULL); // TODO
+  } else {
+    proc (proc_cls,
+          d_count,
+          d_chain,
+          c_count,
+          creds);
+  }
+}
+
+
+/**
+ * Reconnect to CREDENTIAL service.
+ *
+ * @param handle the handle to the CREDENTIAL service
+ */
+static void
+reconnect (struct GNUNET_CREDENTIAL_Handle *handle)
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (result,
+                           GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT,
+                           struct DelegationChainResultMessage,
+                           handle),
+    GNUNET_MQ_hd_var_size (result,
+                           GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT_RESULT,
+                           struct DelegationChainResultMessage,
+                           handle),
+    GNUNET_MQ_handler_end ()
+  };
+  struct GNUNET_CREDENTIAL_Request *vr;
+
+  GNUNET_assert (NULL == handle->mq);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to connect to CREDENTIAL\n");
+  handle->mq = GNUNET_CLIENT_connect (handle->cfg,
+                                      "credential",
+                                      handlers,
+                                      &mq_error_handler,
+                                      handle);
+  if (NULL == handle->mq)
+    return;
+  for (vr = handle->request_head; NULL != vr; vr = vr->next)
+    GNUNET_MQ_send_copy (handle->mq,
+                         vr->env);
+}
+
+
+/**
+ * Initialize the connection with the CREDENTIAL service.
+ *
+ * @param cfg configuration to use
+ * @return handle to the CREDENTIAL service, or NULL on error
+ */
+struct GNUNET_CREDENTIAL_Handle *
+GNUNET_CREDENTIAL_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle;
+
+  handle = GNUNET_new (struct GNUNET_CREDENTIAL_Handle);
+  handle->cfg = cfg;
+  reconnect (handle);
+  if (NULL == handle->mq)
+  {
+    GNUNET_free (handle);
+    return NULL;
+  }
+  return handle;
+}
+
+
+/**
+ * Shutdown connection with the CREDENTIAL service.
+ *
+ * @param handle handle of the CREDENTIAL connection to stop
+ */
+void
+GNUNET_CREDENTIAL_disconnect (struct GNUNET_CREDENTIAL_Handle *handle)
+{
+  if (NULL != handle->mq)
+  {
+    GNUNET_MQ_destroy (handle->mq);
+    handle->mq = NULL;
+  }
+  if (NULL != handle->reconnect_task)
+  {
+    GNUNET_SCHEDULER_cancel (handle->reconnect_task);
+    handle->reconnect_task = NULL;
+  }
+  GNUNET_assert (NULL == handle->request_head);
+  GNUNET_free (handle);
+}
+
+
+/**
+ * Cancel pending verify request
+ *
+ * @param lr the verify request to cancel
+ */
+void
+GNUNET_CREDENTIAL_request_cancel (struct GNUNET_CREDENTIAL_Request *vr)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = vr->credential_handle;
+
+  GNUNET_CONTAINER_DLL_remove (handle->request_head,
+                               handle->request_tail,
+                               vr);
+  GNUNET_MQ_discard (vr->env);
+  GNUNET_free (vr);
+}
+
+
+/**
+ * Performs attribute collection.
+ * Collects all credentials of subject to fulfill the 
+ * attribute, if possible
+ *
+ * @param handle handle to the Credential service
+ * @param issuer_key the issuer public key
+ * @param issuer_attribute the issuer attribute
+ * @param subject_key the subject public key
+ * @param credential_count number of credentials provided
+ * @param credentials subject credentials
+ * @param proc function to call on result
+ * @param proc_cls closure for processor
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Request*
+GNUNET_CREDENTIAL_collect (struct GNUNET_CREDENTIAL_Handle *handle,
+                           const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
+                           const char *issuer_attribute,
+                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *subject_key,
+                           GNUNET_CREDENTIAL_CredentialResultProcessor proc,
+                           void *proc_cls)
+{
+  /* IPC to shorten credential names, return shorten_handle */
+  struct CollectMessage *c_msg;
+  struct GNUNET_CREDENTIAL_Request *vr;
+  size_t nlen;
+
+  if (NULL == issuer_attribute)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  //DEBUG LOG
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to collect `%s' in CREDENTIAL\n",
+       issuer_attribute);
+  nlen = strlen (issuer_attribute) + 1;
+  if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  vr = GNUNET_new (struct GNUNET_CREDENTIAL_Request);
+  vr->credential_handle = handle;
+  vr->verify_proc = proc;
+  vr->proc_cls = proc_cls;
+  vr->r_id = handle->r_id_gen++;
+  vr->env = GNUNET_MQ_msg_extra (c_msg,
+                                 nlen,
+                                 GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT);
+  c_msg->id = htonl (vr->r_id);
+  c_msg->subject_key = *subject_key;
+  c_msg->issuer_key =  *issuer_key;
+  c_msg->issuer_attribute_len = htons(strlen(issuer_attribute));
+  GNUNET_memcpy (&c_msg[1],
+                 issuer_attribute,
+                 strlen (issuer_attribute));
+  GNUNET_CONTAINER_DLL_insert (handle->request_head,
+                               handle->request_tail,
+                               vr);
+  if (NULL != handle->mq)
+    GNUNET_MQ_send_copy (handle->mq,
+                         vr->env);
+  return vr;
+}
+/**
+ * Performs attribute verification.
+ * Checks if there is a delegation chain from
+ * attribute ``issuer_attribute'' issued by the issuer
+ * with public key ``issuer_key'' maps to the attribute
+ * ``subject_attribute'' claimed by the subject with key
+ * ``subject_key''
+ *
+ * @param handle handle to the Credential service
+ * @param issuer_key the issuer public key
+ * @param issuer_attribute the issuer attribute
+ * @param subject_key the subject public key
+ * @param credential_count number of credentials provided
+ * @param credentials subject credentials
+ * @param proc function to call on result
+ * @param proc_cls closure for processor
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Request*
+GNUNET_CREDENTIAL_verify (struct GNUNET_CREDENTIAL_Handle *handle,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
+                          const char *issuer_attribute,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *subject_key,
+                          uint32_t credential_count,
+                          const struct GNUNET_CREDENTIAL_Credential *credentials,
+                          GNUNET_CREDENTIAL_CredentialResultProcessor proc,
+                          void *proc_cls)
+{
+  /* IPC to shorten credential names, return shorten_handle */
+  struct VerifyMessage *v_msg;
+  struct GNUNET_CREDENTIAL_Request *vr;
+  size_t nlen;
+  size_t clen;
+
+  if (NULL == issuer_attribute || NULL == credentials)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+
+  clen = GNUNET_CREDENTIAL_credentials_get_size (credential_count,
+                                                 credentials);
+
+  //DEBUG LOG
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to verify `%s' in CREDENTIAL\n",
+       issuer_attribute);
+  nlen = strlen (issuer_attribute) + 1 + clen;
+  if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  vr = GNUNET_new (struct GNUNET_CREDENTIAL_Request);
+  vr->credential_handle = handle;
+  vr->verify_proc = proc;
+  vr->proc_cls = proc_cls;
+  vr->r_id = handle->r_id_gen++;
+  vr->env = GNUNET_MQ_msg_extra (v_msg,
+                                 nlen,
+                                 GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY);
+  v_msg->id = htonl (vr->r_id);
+  v_msg->subject_key = *subject_key;
+  v_msg->c_count = htonl(credential_count);
+  v_msg->issuer_key =  *issuer_key;
+  v_msg->issuer_attribute_len = htons(strlen(issuer_attribute));
+  GNUNET_memcpy (&v_msg[1],
+                 issuer_attribute,
+                 strlen (issuer_attribute));
+  GNUNET_CREDENTIAL_credentials_serialize (credential_count,
+                                           credentials,
+                                           clen,
+                                           ((char*)&v_msg[1])
+                                           + strlen (issuer_attribute) + 1);
+  GNUNET_CONTAINER_DLL_insert (handle->request_head,
+                               handle->request_tail,
+                               vr);
+  if (NULL != handle->mq)
+    GNUNET_MQ_send_copy (handle->mq,
+                         vr->env);
+  return vr;
+}
+
+/* end of credential_api.c */
diff --git a/src/credential/credential_misc.c b/src/credential/credential_misc.c
new file mode 100644 (file)
index 0000000..7849e81
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013, 2016 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+
+/**
+ * @file credential/credential_mic.c
+ * @brief Misc API for credentials
+ *
+ * @author Martin Schanzenbach
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_credential_service.h"
+#include "gnunet_signatures.h"
+#include "credential.h"
+#include <inttypes.h>
+
+char*
+GNUNET_CREDENTIAL_credential_to_string (const struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  char *cred_str;
+  char *subject_pkey;
+  char *issuer_pkey;
+  char *signature;
+
+
+  subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
+  issuer_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
+  GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
+                                sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
+                                &signature);
+  GNUNET_asprintf (&cred_str,
+                   "%s.%s -> %s | %s | %"SCNu64,
+                   issuer_pkey,
+                   cred->issuer_attribute,
+                   subject_pkey,
+                   signature,
+                   cred->expiration.abs_value_us);
+  GNUNET_free (subject_pkey);
+  GNUNET_free (issuer_pkey);
+  GNUNET_free (signature);
+  return cred_str;
+}
+
+struct GNUNET_CREDENTIAL_Credential*
+GNUNET_CREDENTIAL_credential_from_string (const char* s)
+{
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
+  if (enclen % 5 > 0)
+    enclen += 5 - enclen % 5;
+  enclen /= 5; /* 260/5 = 52 */
+  char subject_pkey[enclen + 1];
+  char issuer_pkey[enclen + 1];
+  char name[253 + 1];
+  char signature[256]; //TODO max payload size
+
+  struct GNUNET_CRYPTO_EcdsaSignature *sig;
+  struct GNUNET_TIME_Absolute etime_abs;
+
+  if (5 != SSCANF (s,
+                   "%52s.%253s -> %52s | %s | %"SCNu64,
+                   issuer_pkey,
+                   name,
+                   subject_pkey,
+                   signature,
+                   &etime_abs.abs_value_us))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                _("Unable to parse CRED record string `%s'\n"),
+                s);
+    return NULL;
+  }
+  cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + strlen (name) + 1);
+  GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
+                                              strlen (subject_pkey),
+                                              &cred->subject_key);
+  GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_pkey,
+                                              strlen (issuer_pkey),
+                                              &cred->issuer_key);
+  GNUNET_assert (sizeof (struct GNUNET_CRYPTO_EcdsaSignature) == GNUNET_STRINGS_base64_decode (signature,
+                                strlen (signature),
+                                (char**)&sig));
+  cred->signature = *sig;
+  cred->expiration = etime_abs;
+  GNUNET_free (sig);
+  GNUNET_memcpy (&cred[1],
+                 name,
+                 strlen (name)+1);
+  cred->issuer_attribute_len = strlen ((char*)&cred[1]);
+  cred->issuer_attribute = (char*)&cred[1];
+  return cred;
+}
+
+/**
+ * Issue an attribute to a subject
+ *
+ * @param handle handle to the Credential service
+ * @param issuer the ego that should be used to issue the attribute
+ * @param subject the subject of the attribute
+ * @param attribute the name of the attribute
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Credential *
+GNUNET_CREDENTIAL_credential_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
+                                    struct GNUNET_CRYPTO_EcdsaPublicKey *subject,
+                                    const char *attribute,
+                                    struct GNUNET_TIME_Absolute *expiration)
+{
+  struct CredentialEntry *crd;
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  size_t size;
+
+  size = sizeof (struct CredentialEntry) + strlen (attribute) + 1;
+  crd = GNUNET_malloc (size);
+  cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + strlen (attribute) + 1);
+  crd->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+
+  crd->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
+  GNUNET_CRYPTO_ecdsa_key_get_public (issuer,
+                                      &crd->issuer_key);
+  crd->subject_key = *subject;
+  crd->expiration = GNUNET_htonll (expiration->abs_value_us);
+  crd->issuer_attribute_len = htonl (strlen (attribute)+1);
+  GNUNET_memcpy ((char*)&crd[1],
+                 attribute,
+                 strlen (attribute)+1);
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_sign (issuer,
+                                &crd->purpose,
+                                &crd->signature))
+  {
+    GNUNET_break (0);
+    GNUNET_free (crd);
+    return NULL;
+  }
+  cred->signature = crd->signature;
+  cred->expiration = *expiration;
+  GNUNET_CRYPTO_ecdsa_key_get_public (issuer,
+                                      &cred->issuer_key);
+
+  cred->subject_key = *subject;
+  GNUNET_memcpy (&cred[1],
+                 attribute,
+                 strlen (attribute)+1);
+  cred->issuer_attribute = (char*)&cred[1];
+  GNUNET_free (crd);
+  return cred;
+}
+
+
diff --git a/src/credential/credential_misc.h b/src/credential/credential_misc.h
new file mode 100644 (file)
index 0000000..c3aa8c2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+      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 General Public License as published
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+      Boston, MA 02110-1301, USA.
+ */
+/**
+ * @file credential/credential_misc.h
+ * @brief Credential helper functions
+ */
+#ifndef CREDENTIAL_MISC_H
+#define CREDENTIAL_MISC_H
+
+
+
+char*
+GNUNET_CREDENTIAL_credential_to_string (const struct GNUNET_CREDENTIAL_Credential *cred);
+
+struct GNUNET_CREDENTIAL_Credential*
+GNUNET_CREDENTIAL_credential_from_string (const char* str);
+
+#endif
diff --git a/src/credential/credential_serialization.c b/src/credential/credential_serialization.c
new file mode 100644 (file)
index 0000000..1fc72c2
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013, 2016 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+
+/**
+ * @file credential/credential_serialization.c
+ * @brief API to serialize and deserialize delegation chains 
+ * and credentials
+ * @author Martin Schanzenbach
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_credential_service.h"
+#include "gnunet_signatures.h"
+#include "credential.h"
+
+/**
+ * Calculate how many bytes we will need to serialize
+ * the given delegation chain and credential
+ *
+ * @param d_count number of delegation chain entries
+ * @param dd array of #GNUNET_CREDENTIAL_Delegation
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @return the required size to serialize
+ */
+size_t
+GNUNET_CREDENTIAL_delegation_set_get_size (unsigned int ds_count,
+                                           const struct GNUNET_CREDENTIAL_DelegationSet *dsr)
+{
+  unsigned int i;
+  size_t ret;
+
+  ret = sizeof (struct DelegationRecordData) * (ds_count);
+
+  for (i=0; i<ds_count;i++)
+  {
+    GNUNET_assert ((ret + dsr[i].subject_attribute_len) >= ret);
+    ret += dsr[i].subject_attribute_len;
+  }
+  return ret;
+}
+
+/**
+ * Serizalize the given delegation chain entries and credential
+ *
+ * @param d_count number of delegation chain entries
+ * @param dd array of #GNUNET_CREDENTIAL_Delegation
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @param dest_size size of the destination
+ * @param dest where to store the result
+ * @return the size of the data, -1 on failure
+ */
+ssize_t
+GNUNET_CREDENTIAL_delegation_set_serialize (unsigned int d_count,
+                                            const struct GNUNET_CREDENTIAL_DelegationSet *dsr,
+                                            size_t dest_size,
+                                            char *dest)
+{
+  struct DelegationRecordData rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<d_count;i++)
+  {
+    rec.subject_attribute_len = htonl ((uint32_t) dsr[i].subject_attribute_len);
+    rec.subject_key = dsr[i].subject_key;
+    if (off + sizeof (rec) > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   &rec,
+                   sizeof (rec));
+    off += sizeof (rec);
+    if (0 == dsr[i].subject_attribute_len)
+      continue;
+    if (off + dsr[i].subject_attribute_len > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   dsr[i].subject_attribute,
+                   dsr[i].subject_attribute_len);
+    off += dsr[i].subject_attribute_len;
+  }
+  return off;
+}
+
+
+/**
+ * Deserialize the given destination
+ *
+ * @param len size of the serialized delegation chain and cred
+ * @param src the serialized data
+ * @param d_count the number of delegation chain entries
+ * @param dd where to put the delegation chain entries
+ * @param cd where to put the credential data
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len,
+                                              const char *src,
+                                              unsigned int d_count,
+                                              struct GNUNET_CREDENTIAL_DelegationSet *dsr)
+{
+  struct DelegationRecordData rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<d_count;i++)
+  {
+    if (off + sizeof (rec) > len)
+      return GNUNET_SYSERR;
+    GNUNET_memcpy (&rec, &src[off], sizeof (rec));
+    dsr[i].subject_key = rec.subject_key;
+    off += sizeof (rec);
+    dsr[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
+    if (off + dsr[i].subject_attribute_len > len)
+      return GNUNET_SYSERR;
+    dsr[i].subject_attribute = (char*)&src[off];
+    off += dsr[i].subject_attribute_len;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Calculate how many bytes we will need to serialize
+ * the credentials
+ *
+ * @param c_count number of credential entries
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @return the required size to serialize
+ */
+size_t
+GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count,
+                                        const struct GNUNET_CREDENTIAL_Credential *cd)
+{
+  unsigned int i;
+  size_t ret;
+
+  ret = sizeof (struct CredentialEntry) * (c_count);
+
+  for (i=0; i<c_count;i++)
+  {
+    GNUNET_assert ((ret + cd[i].issuer_attribute_len) >= ret);
+    ret += cd[i].issuer_attribute_len;
+  }
+  return ret;
+}
+/**
+ * Serizalize the given credentials
+ *
+ * @param c_count number of credential entries
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @param dest_size size of the destination
+ * @param dest where to store the result
+ * @return the size of the data, -1 on failure
+ */
+ssize_t
+GNUNET_CREDENTIAL_credentials_serialize (unsigned int c_count,
+                                         const struct GNUNET_CREDENTIAL_Credential *cd,
+                                         size_t dest_size,
+                                         char *dest)
+{
+  struct CredentialEntry c_rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<c_count;i++)
+  {
+    c_rec.issuer_attribute_len = htonl ((uint32_t) cd[i].issuer_attribute_len);
+    c_rec.issuer_key = cd[i].issuer_key;
+    c_rec.subject_key = cd[i].subject_key;
+    c_rec.signature = cd[i].signature;
+    c_rec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
+    c_rec.purpose.size = htonl ((sizeof (struct CredentialEntry) + cd[i].issuer_attribute_len) - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+    c_rec.expiration = GNUNET_htonll (cd[i].expiration.abs_value_us);
+    if (off + sizeof (c_rec) > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   &c_rec,
+                   sizeof (c_rec));
+    off += sizeof (c_rec);
+    if (off + cd[i].issuer_attribute_len > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   cd[i].issuer_attribute,
+                   cd[i].issuer_attribute_len);
+    off += cd[i].issuer_attribute_len;
+  }
+
+  return off;
+}
+
+
+
+/**
+ * Deserialize the given destination
+ *
+ * @param len size of the serialized creds
+ * @param src the serialized data
+ * @param c_count the number of credential entries
+ * @param cd where to put the credential data
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CREDENTIAL_credentials_deserialize (size_t len,
+                                           const char *src,
+                                           unsigned int c_count,
+                                           struct GNUNET_CREDENTIAL_Credential *cd)
+{
+  struct CredentialEntry c_rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<c_count;i++)
+  {
+    if (off + sizeof (c_rec) > len)
+      return GNUNET_SYSERR;
+    GNUNET_memcpy (&c_rec, &src[off], sizeof (c_rec));
+    cd[i].issuer_attribute_len = ntohl ((uint32_t) c_rec.issuer_attribute_len);
+    cd[i].issuer_key = c_rec.issuer_key;
+    cd[i].subject_key = c_rec.subject_key;
+    cd[i].signature = c_rec.signature;
+    cd[i].expiration.abs_value_us = GNUNET_ntohll(c_rec.expiration);
+    off += sizeof (c_rec);
+    if (off + cd[i].issuer_attribute_len > len)
+      return GNUNET_SYSERR;
+    cd[i].issuer_attribute = &src[off];
+    off += cd[i].issuer_attribute_len;
+  }
+  return GNUNET_OK;
+}
+
+
+
+/**
+ * Calculate how many bytes we will need to serialize
+ * the given delegation chain and credential
+ *
+ * @param d_count number of delegation chain entries
+ * @param dd array of #GNUNET_CREDENTIAL_Delegation
+ * @param c_count number of credential entries
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @return the required size to serialize
+ */
+size_t
+GNUNET_CREDENTIAL_delegation_chain_get_size (unsigned int d_count,
+                                             const struct GNUNET_CREDENTIAL_Delegation *dd,
+                                             unsigned int c_count,
+                                             const struct GNUNET_CREDENTIAL_Credential *cd)
+{
+  unsigned int i;
+  size_t ret;
+
+  ret = sizeof (struct ChainEntry) * (d_count);
+
+  for (i=0; i<d_count;i++)
+  {
+    GNUNET_assert ((ret +
+                    dd[i].issuer_attribute_len +
+                    dd[i].subject_attribute_len) >= ret);
+    ret += dd[i].issuer_attribute_len + dd[i].subject_attribute_len;
+  }
+  return ret+GNUNET_CREDENTIAL_credentials_get_size(c_count, cd);
+  return ret;
+}
+
+/**
+ * Serizalize the given delegation chain entries and credential
+ *
+ * @param d_count number of delegation chain entries
+ * @param dd array of #GNUNET_CREDENTIAL_Delegation
+ * @param c_count number of credential entries
+ * @param cd a #GNUNET_CREDENTIAL_Credential
+ * @param dest_size size of the destination
+ * @param dest where to store the result
+ * @return the size of the data, -1 on failure
+ */
+ssize_t
+GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count,
+                                              const struct GNUNET_CREDENTIAL_Delegation *dd,
+                                              unsigned int c_count,
+                                              const struct GNUNET_CREDENTIAL_Credential *cd,
+                                              size_t dest_size,
+                                              char *dest)
+{
+  struct ChainEntry rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<d_count;i++)
+  {
+    rec.issuer_attribute_len = htonl ((uint32_t) dd[i].issuer_attribute_len);
+    rec.subject_attribute_len = htonl ((uint32_t) dd[i].subject_attribute_len);
+    rec.issuer_key = dd[i].issuer_key;
+    rec.subject_key = dd[i].subject_key;
+    if (off + sizeof (rec) > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   &rec,
+                   sizeof (rec));
+    off += sizeof (rec);
+    if (off + dd[i].issuer_attribute_len > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   dd[i].issuer_attribute,
+                   dd[i].issuer_attribute_len);
+    off += dd[i].issuer_attribute_len;
+    if (0 == dd[i].subject_attribute_len)
+      continue;
+    if (off + dd[i].subject_attribute_len > dest_size)
+      return -1;
+    GNUNET_memcpy (&dest[off],
+                   dd[i].subject_attribute,
+                   dd[i].subject_attribute_len);
+    off += dd[i].subject_attribute_len;
+  }
+  return off+GNUNET_CREDENTIAL_credentials_serialize (c_count,
+                                                      cd,
+                                                      dest_size-off,
+                                                      &dest[off]);
+}
+
+
+/**
+ * Deserialize the given destination
+ *
+ * @param len size of the serialized delegation chain and cred
+ * @param src the serialized data
+ * @param d_count the number of delegation chain entries
+ * @param dd where to put the delegation chain entries
+ * @param c_count the number of credential entries
+ * @param cd where to put the credential data
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len,
+                                                const char *src,
+                                                unsigned int d_count,
+                                                struct GNUNET_CREDENTIAL_Delegation *dd,
+                                                unsigned int c_count,
+                                                struct GNUNET_CREDENTIAL_Credential *cd)
+{
+  struct ChainEntry rec;
+  unsigned int i;
+  size_t off;
+
+  off = 0;
+  for (i=0;i<d_count;i++)
+  {
+    if (off + sizeof (rec) > len)
+      return GNUNET_SYSERR;
+    GNUNET_memcpy (&rec, &src[off], sizeof (rec));
+    dd[i].issuer_attribute_len = ntohl ((uint32_t) rec.issuer_attribute_len);
+    dd[i].issuer_key = rec.issuer_key;
+    dd[i].subject_key = rec.subject_key;
+    off += sizeof (rec);
+    if (off + dd[i].issuer_attribute_len > len)
+      return GNUNET_SYSERR;
+    dd[i].issuer_attribute = &src[off];
+    off += dd[i].issuer_attribute_len;
+    dd[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len);
+    if (off + dd[i].subject_attribute_len > len)
+      return GNUNET_SYSERR;
+    dd[i].subject_attribute = &src[off];
+    off += dd[i].subject_attribute_len;
+  }
+  return GNUNET_CREDENTIAL_credentials_deserialize (len-off,
+                                                    &src[off],
+                                                    c_count,
+                                                    cd);
+}
+int
+GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred,
+                                        char **data)
+{
+  size_t size;
+  struct CredentialEntry *cdata;
+
+  size = sizeof (struct CredentialEntry) + strlen (cred->issuer_attribute) + 1;
+  *data = GNUNET_malloc (size);
+  cdata = (struct CredentialEntry*)*data;
+  cdata->subject_key = cred->subject_key;
+  cdata->issuer_key = cred->issuer_key;
+  cdata->expiration = GNUNET_htonll (cred->expiration.abs_value_us);
+  cdata->signature = cred->signature;
+  cdata->issuer_attribute_len = htonl (strlen (cred->issuer_attribute) + 1);
+  cdata->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL);
+  cdata->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+  GNUNET_memcpy (&cdata[1],
+                 cred->issuer_attribute,
+                 strlen (cred->issuer_attribute));
+
+  if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
+                                             &cdata->purpose,
+                                             &cdata->signature,
+                                             &cdata->issuer_key))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Invalid credential\n");
+    //return NULL;
+  }
+  return size;
+}
+
+struct GNUNET_CREDENTIAL_Credential*
+GNUNET_CREDENTIAL_credential_deserialize (const char* data,
+                                          size_t data_size)
+{
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  struct CredentialEntry *cdata;
+  char *issuer_attribute;
+
+  if (data_size < sizeof (struct CredentialEntry))
+    return NULL;
+  cdata = (struct CredentialEntry*)data;
+  if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, 
+                                             &cdata->purpose,
+                                             &cdata->signature,
+                                             &cdata->issuer_key))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Invalid credential\n");
+    //return NULL;
+  }
+  issuer_attribute = (char*)&cdata[1];
+
+  cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + ntohl(cdata->issuer_attribute_len));
+
+  cred->issuer_key = cdata->issuer_key;
+  cred->subject_key = cdata->subject_key;
+  GNUNET_memcpy (&cred[1],
+                 issuer_attribute,
+                 ntohl (cdata->issuer_attribute_len));
+  cred->signature = cdata->signature;
+  cred->issuer_attribute = (char*)&cred[1];
+  cred->expiration.abs_value_us = GNUNET_ntohll (cdata->expiration);
+  return cred;
+}
+
+
+/* end of credential_serialization.c */
diff --git a/src/credential/credential_serialization.h b/src/credential/credential_serialization.h
new file mode 100644 (file)
index 0000000..b870d47
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013, 2016 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+
+/**
+ * @file credential/credential_serialization.h
+ * @brief API to serialize and deserialize delegation chains 
+ * and credentials
+ * @author Martin Schanzenbach
+ */
+#ifndef CREDENTIAL_SERIALIZATION_H
+#define CREDENTIAL_SERIALIZATION_H
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_credential_service.h"
+
+/**
+ * Calculate how many bytes we will need to serialize
+ * the given delegation record
+ *
+ * @param ds_count number of delegation chain entries
+ * @param dsr array of #GNUNET_CREDENTIAL_Delegation
+ * @return the required size to serialize
+ */
+size_t
+GNUNET_CREDENTIAL_delegation_set_get_size (unsigned int ds_count,
+                                           const struct GNUNET_CREDENTIAL_DelegationSet *dsr);
+
+/**
+ * Serizalize the given delegation record entries
+ *
+ * @param d_count number of delegation chain entries
+ * @param dsr array of #GNUNET_CREDENTIAL_Delegation
+ * @param dest_size size of the destination
+ * @param dest where to store the result
+ * @return the size of the data, -1 on failure
+ */
+ssize_t
+GNUNET_CREDENTIAL_delegation_set_serialize (unsigned int d_count,
+                                            const struct GNUNET_CREDENTIAL_DelegationSet *dsr,
+                                            size_t dest_size,
+                                            char *dest);
+
+
+/**
+ * Deserialize the given destination
+ *
+ * @param len size of the serialized delegation recird
+ * @param src the serialized data
+ * @param d_count the number of delegation chain entries
+ * @param dsr where to put the delegation chain entries
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len,
+                                              const char *src,
+                                              unsigned int d_count,
+                                              struct GNUNET_CREDENTIAL_DelegationSet *dsr);
+
+  /**
+   * Calculate how many bytes we will need to serialize
+   * the given delegation chain and credential
+   *
+   * @param d_count number of delegation chain entries
+   * @param dd array of #GNUNET_CREDENTIAL_Delegation
+   * @param c_count number of credential entries
+   * @param cd a #GNUNET_CREDENTIAL_Credential
+   * @return the required size to serialize
+   */
+  size_t
+    GNUNET_CREDENTIAL_delegation_chain_get_size (unsigned int d_count,
+                                                 const struct GNUNET_CREDENTIAL_Delegation *dd,
+                                                 unsigned int c_count,
+                                                 const struct GNUNET_CREDENTIAL_Credential *cd);
+
+  /**
+   * Serizalize the given delegation chain entries and credential
+   *
+   * @param d_count number of delegation chain entries
+   * @param dd array of #GNUNET_CREDENTIAL_Delegation
+   * @param c_count number of credential entries
+   * @param cd a #GNUNET_CREDENTIAL_Credential
+   * @param dest_size size of the destination
+   * @param dest where to store the result
+   * @return the size of the data, -1 on failure
+   */
+  ssize_t
+    GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count,
+                                                  const struct GNUNET_CREDENTIAL_Delegation *dd,
+                                                  unsigned int c_count,
+                                                  const struct GNUNET_CREDENTIAL_Credential *cd,
+                                                  size_t dest_size,
+                                                  char *dest);
+
+
+  /**
+   * Deserialize the given destination
+   *
+   * @param len size of the serialized delegation chain and cred
+   * @param src the serialized data
+   * @param d_count the number of delegation chain entries
+   * @param dd where to put the delegation chain entries
+   * @param c_count number of credential entries
+   * @param cd where to put the credential data
+   * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+   */
+  int
+    GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len,
+                                                    const char *src,
+                                                    unsigned int d_count,
+                                                    struct GNUNET_CREDENTIAL_Delegation *dd,
+                                                    unsigned int c_count,
+                                                    struct GNUNET_CREDENTIAL_Credential *cd);
+  size_t
+  GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count,
+                                          const struct GNUNET_CREDENTIAL_Credential *cd);
+
+ssize_t
+GNUNET_CREDENTIAL_credentials_serialize (unsigned int c_count,
+                                         const struct GNUNET_CREDENTIAL_Credential *cd,
+                                         size_t dest_size,
+                                         char *dest);
+
+
+int
+GNUNET_CREDENTIAL_credentials_deserialize (size_t len,
+                                           const char *src,
+                                           unsigned int c_count,
+                                           struct GNUNET_CREDENTIAL_Credential *cd);
+
+
+int
+GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred,
+                                        char **data);
+
+struct GNUNET_CREDENTIAL_Credential*
+GNUNET_CREDENTIAL_credential_deserialize (const char* data,
+                                          size_t data_size);
+#endif
+/* end of credential_serialization.h */
diff --git a/src/credential/gnunet-credential.c b/src/credential/gnunet-credential.c
new file mode 100644 (file)
index 0000000..4a6dc5c
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+     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 General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file gnunet-credential.c
+ * @brief command line tool to access command line Credential service
+ * @author Adnan Husain
+ */
+#include "platform.h"
+#include <gnunet_util_lib.h>
+#include <gnunet_credential_service.h>
+#include <gnunet_gnsrecord_lib.h>
+#include "credential_misc.h"
+#include "credential_serialization.h"
+
+/**
+ * Configuration we are using.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * EgoLookup
+ */
+static struct GNUNET_IDENTITY_EgoLookup *el;
+
+/**
+ * Handle to Credential service.
+ */
+static struct GNUNET_CREDENTIAL_Handle *credential;
+
+/**
+ * Desired timeout for the lookup (default is no timeout).
+ */
+static struct GNUNET_TIME_Relative timeout;
+
+/**
+ * Handle to verify request
+ */
+static struct GNUNET_CREDENTIAL_Request *verify_request;
+
+/**
+ * Handle to collect request
+ */
+static struct GNUNET_CREDENTIAL_Request *collect_request;
+
+/**
+ * Task scheduled to handle timeout.
+ */
+static struct GNUNET_SCHEDULER_Task *tt;
+
+/**
+ * Subject pubkey string
+ */
+static char *subject_key;
+
+/**
+ * Subject credential string
+ */
+static char *subject_credential;
+
+/**
+ * Credential TTL
+ */
+static char *expiration;
+
+/**
+ * Subject key
+ */
+struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
+
+/**
+ * Issuer key
+ */
+struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
+
+
+/**
+ * Issuer pubkey string
+ */
+static char *issuer_key;
+
+/**
+ * ego
+ */
+static char *ego_name;
+
+/**
+ * Issuer attribute
+ */
+static char *issuer_attr;
+
+/**
+ * Verify mode
+ */
+static int verify;
+
+/**
+ * Issue mode
+ */
+static int create_cred;
+
+/**
+ * Collect mode
+ */
+static int collect;
+
+/**
+ * Task run on shutdown.  Cleans up everything.
+ *
+ * @param cls unused
+ */
+static void
+do_shutdown (void *cls)
+{
+  if (NULL != verify_request)
+  {
+    GNUNET_CREDENTIAL_request_cancel (verify_request);
+    verify_request = NULL;
+  }
+  if (NULL != credential)
+  {
+    GNUNET_CREDENTIAL_disconnect (credential);
+    credential = NULL;
+  }
+  if (NULL != tt)
+  {
+    GNUNET_SCHEDULER_cancel (tt);
+    tt = NULL;
+  }
+}
+
+
+/**
+ * Task run on timeout. Triggers shutdown.
+ *
+ * @param cls unused
+ */
+static void
+do_timeout (void *cls)
+{
+  tt = NULL;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Function called with the result of a Credential lookup.
+ *
+ * @param cls the 'const char *' name that was resolved
+ * @param cd_count number of records returned
+ * @param cd array of @a cd_count records with the results
+ */
+static void
+handle_collect_result (void *cls,
+                      unsigned int d_count,
+                      struct GNUNET_CREDENTIAL_Delegation *dc,
+                      unsigned int c_count,
+                      struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  int i;
+  char* line;
+
+  verify_request = NULL;
+  if (NULL != cred)
+  {
+    for (i=0;i<c_count;i++)
+    {
+      line = GNUNET_CREDENTIAL_credential_to_string (&cred[i]);
+      printf ("%s\n",
+              line);
+      GNUNET_free (line);
+    }
+  }
+
+
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Function called with the result of a Credential lookup.
+ *
+ * @param cls the 'const char *' name that was resolved
+ * @param cd_count number of records returned
+ * @param cd array of @a cd_count records with the results
+ */
+static void
+handle_verify_result (void *cls,
+                      unsigned int d_count,
+                      struct GNUNET_CREDENTIAL_Delegation *dc,
+                      unsigned int c_count,
+                      struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  int i;
+  char* iss_key;
+  char* sub_key;
+
+  verify_request = NULL;
+  if (NULL == cred)
+    printf ("Failed.\n");
+  else
+  {
+    printf("Delegation Chain:\n");
+    for (i=0;i<d_count;i++)
+    {
+      iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key);
+      sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key);
+      if (0 != dc[i].subject_attribute_len)
+      {
+        printf ("(%d) %s.%s <- %s.%s\n", i,
+                iss_key, dc[i].issuer_attribute,
+                sub_key, dc[i].subject_attribute);
+      } else {
+        printf ("(%d) %s.%s <- %s\n", i,
+                iss_key, dc[i].issuer_attribute,
+                sub_key);
+      }
+      GNUNET_free (iss_key);
+      GNUNET_free (sub_key);
+    }
+    printf("\nCredentials:\n");
+    for (i=0;i<c_count;i++)
+    {
+      iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key);
+      sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key);
+      printf ("%s.%s <- %s\n",
+              iss_key, cred[i].issuer_attribute,
+              sub_key);
+      GNUNET_free (iss_key);
+      GNUNET_free (sub_key);
+
+    }
+    printf ("Successful.\n");
+  }
+
+
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Callback invoked from identity service with ego information.
+ * An @a ego of NULL means the ego was not found.
+ *
+ * @param cls closure with the configuration
+ * @param ego an ego known to identity service, or NULL
+ */
+static void
+identity_cb (void *cls,
+             const struct GNUNET_IDENTITY_Ego *ego)
+{
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
+  struct GNUNET_CREDENTIAL_Credential *crd;
+  struct GNUNET_TIME_Absolute etime_abs;
+  struct GNUNET_TIME_Relative etime_rel;
+  char *res;
+
+  el = NULL;
+  if (NULL == ego)
+  {
+    if (NULL != ego_name)
+    {
+      fprintf (stderr,
+               _("Ego `%s' not known to identity service\n"),
+               ego_name);
+    }
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
+  if (GNUNET_YES == collect)
+  {
+    
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
+                                                    strlen (issuer_key),
+                                                    &issuer_pkey))
+    {
+      fprintf (stderr,
+               _("Issuer public key `%s' is not well-formed\n"),
+               issuer_key);
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
+
+    collect_request = GNUNET_CREDENTIAL_collect(credential,
+                                                &issuer_pkey,
+                                                issuer_attr, //TODO argument
+                                                privkey,
+                                                &handle_collect_result,
+                                                NULL);
+    return;
+  }
+
+  //Else issue
+
+  if (NULL == expiration)
+  {
+    fprintf (stderr,
+             "Please specify a TTL\n");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  } else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration,
+                                                                 &etime_rel))
+  {
+    etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
+  } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration,
+                                                                 &etime_abs))
+  {
+    fprintf (stderr,
+             "%s is not a valid ttl!\n",
+             expiration);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
+
+  privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
+  GNUNET_free_non_null (ego_name);
+  ego_name = NULL;
+  crd = GNUNET_CREDENTIAL_credential_issue (privkey,
+                                            &subject_pkey,
+                                            issuer_attr,
+                                            &etime_abs);
+
+  res = GNUNET_CREDENTIAL_credential_to_string (crd);
+  GNUNET_free (crd);
+  printf ("%s\n", res);
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param c configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *c)
+{
+
+  cfg = c;
+
+
+  tt = GNUNET_SCHEDULER_add_delayed (timeout,
+                                     &do_timeout, NULL);
+  GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
+
+  if (GNUNET_YES == collect) {
+    if (NULL == issuer_key)
+    {
+      fprintf (stderr,
+               _("Issuer public key not well-formed\n"));
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+
+    }
+
+    credential = GNUNET_CREDENTIAL_connect (cfg);
+
+    if (NULL == credential)
+    {
+      fprintf (stderr,
+               _("Failed to connect to CREDENTIAL\n"));
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    if (NULL == issuer_attr)
+    {
+      fprintf (stderr,
+               _("You must provide issuer the attribute\n"));
+      GNUNET_SCHEDULER_shutdown ();
+    }
+
+    if (NULL == ego_name)
+    {
+      fprintf (stderr,
+               _("ego required\n"));
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+
+    }
+    el = GNUNET_IDENTITY_ego_lookup (cfg,
+                                     ego_name,
+                                     &identity_cb,
+                                     (void *) cfg);
+    return;
+
+  } 
+
+  if (NULL == subject_key)
+  {
+    fprintf (stderr,
+             _("Subject public key needed\n"));
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+
+  }
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
+                                                  strlen (subject_key),
+                                                  &subject_pkey))
+  {
+    fprintf (stderr,
+             _("Subject public key `%s' is not well-formed\n"),
+             subject_key);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (GNUNET_YES == verify) {
+    if (NULL == issuer_key)
+    {
+      fprintf (stderr,
+               _("Issuer public key not well-formed\n"));
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+
+    }
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
+                                                    strlen (issuer_key),
+                                                    &issuer_pkey))
+    {
+      fprintf (stderr,
+               _("Issuer public key `%s' is not well-formed\n"),
+               issuer_key);
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    credential = GNUNET_CREDENTIAL_connect (cfg);
+
+    if (NULL == credential)
+    {
+      fprintf (stderr,
+               _("Failed to connect to CREDENTIAL\n"));
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    if (NULL == issuer_attr || NULL == subject_credential)
+    {
+      fprintf (stderr,
+               _("You must provide issuer and subject attributes\n"));
+      GNUNET_SCHEDULER_shutdown ();
+    }
+
+    //Subject credentials are comma separated
+    char *tmp = GNUNET_strdup (subject_credential);
+    char *tok = strtok (tmp, ",");
+    if (NULL == tok)
+    {
+      fprintf (stderr,
+               "Invalid subject credentials\n");
+      GNUNET_free (tmp);
+      GNUNET_SCHEDULER_shutdown ();
+    }
+    int count = 1;
+    int i;
+    while (NULL != (tok = strtok(NULL, ",")))
+      count++;
+    struct GNUNET_CREDENTIAL_Credential credentials[count];
+    struct GNUNET_CREDENTIAL_Credential *cred;
+    GNUNET_free (tmp);
+    tmp = GNUNET_strdup (subject_credential);
+    tok = strtok (tmp, ",");
+    for (i=0;i<count;i++)
+    {
+      cred = GNUNET_CREDENTIAL_credential_from_string (tok);
+      GNUNET_memcpy (&credentials[i],
+                     cred,
+                     sizeof (struct GNUNET_CREDENTIAL_Credential));
+      credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
+      tok = strtok(NULL, ",");
+      GNUNET_free (cred);
+    }
+
+    verify_request = GNUNET_CREDENTIAL_verify(credential,
+                                              &issuer_pkey,
+                                              issuer_attr, //TODO argument
+                                              &subject_pkey,
+                                              count,
+                                              credentials,
+                                              &handle_verify_result,
+                                              NULL);
+    for (i=0;i<count;i++)
+    {
+      GNUNET_free ((char*)credentials[i].issuer_attribute);
+    }
+  } else if (GNUNET_YES == create_cred) {
+    if (NULL == ego_name)
+    {
+      fprintf (stderr,
+               _("Issuer ego required\n"));
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+
+    }
+    el = GNUNET_IDENTITY_ego_lookup (cfg,
+                                     ego_name,
+                                     &identity_cb,
+                                     (void *) cfg);
+    return;
+  } else {
+    fprintf (stderr,
+             _("Please specify name to lookup, subject key and issuer key!\n"));
+    GNUNET_SCHEDULER_shutdown ();
+  }
+  return;
+}
+
+
+/**
+ * The main function for gnunet-gns.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_option_flag ('I',
+                               "issue",
+                               gettext_noop ("create credential"),
+                               &create_cred),
+    GNUNET_GETOPT_option_flag ('V',
+                               "verify",
+                               gettext_noop ("verify credential against attribute"),
+                               &verify),
+    GNUNET_GETOPT_option_string ('s',
+                                 "subject",
+                                 "PKEY",
+                                 gettext_noop ("The public key of the subject to lookup the credential for"),
+                                 &subject_key),
+    GNUNET_GETOPT_option_string ('b',
+                                 "credential",
+                                 "CRED",
+                                 gettext_noop ("The name of the credential presented by the subject"),
+                                 &subject_credential),
+    GNUNET_GETOPT_option_string ('i',
+                                 "issuer",
+                                 "PKEY",
+                                 gettext_noop ("The public key of the authority to verify the credential against"),
+                                 &issuer_key),
+    GNUNET_GETOPT_option_string ('e',
+                                 "ego",
+                                 "EGO",
+                                 gettext_noop ("The ego to use"),
+                                 &ego_name),
+    GNUNET_GETOPT_option_string ('a',
+                                 "attribute",
+                                 "ATTR",
+                                 gettext_noop ("The issuer attribute to verify against or to issue"),
+                                 &issuer_attr),
+    GNUNET_GETOPT_option_string ('T',
+                                 "ttl",
+                                 "EXP",
+                                 gettext_noop ("The time to live for the credential"),
+                                 &expiration),
+    GNUNET_GETOPT_option_flag ('g',
+                               "collect",
+                               gettext_noop ("collect credentials"),
+                               &collect),
+    GNUNET_GETOPT_OPTION_END
+  };
+  int ret;
+
+  timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+    return 2;
+
+  GNUNET_log_setup ("gnunet-credential", "WARNING", NULL);
+  ret =
+    (GNUNET_OK ==
+     GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
+                         _("GNUnet credential resolver tool"),
+                         options,
+                         &run, NULL)) ? 0 : 1;
+  GNUNET_free ((void*) argv);
+  return ret;
+}
+
+/* end of gnunet-credential.c */
diff --git a/src/credential/gnunet-service-credential.c b/src/credential/gnunet-service-credential.c
new file mode 100644 (file)
index 0000000..be75e48
--- /dev/null
@@ -0,0 +1,1238 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2011-2013 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file gns/gnunet-service-credential.c
+ * @brief GNU Credential Service (main service)
+ * @author Adnan Husain 
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_credential_service.h"
+#include "gnunet_statistics_service.h"
+#include "credential.h"
+#include "credential_serialization.h"
+#include "gnunet_protocols.h"
+#include "gnunet_signatures.h"
+
+#include <gnunet_dnsparser_lib.h>
+#include <gnunet_identity_service.h>
+#include <gnunet_gnsrecord_lib.h>
+#include <gnunet_namestore_service.h>
+#include <gnunet_gns_service.h>
+
+
+#define GNUNET_CREDENTIAL_MAX_LENGTH 255
+
+struct VerifyRequestHandle;
+
+struct DelegationSetQueueEntry;
+
+
+struct DelegationChainEntry
+{
+  /**
+   * DLL
+   */
+  struct DelegationChainEntry *next;
+
+  /**
+   * DLL
+   */
+  struct DelegationChainEntry *prev;
+
+  /**
+   * The issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+  
+  /**
+   * The subject
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+  
+  /**
+   * The issued attribute
+   */
+  char *issuer_attribute;
+  
+  /**
+   * The delegated attribute
+   */
+  char *subject_attribute;
+};
+
+/**
+ * DLL for record
+ */
+struct CredentialRecordEntry
+{
+  /**
+   * DLL
+   */
+  struct CredentialRecordEntry *next;
+
+  /**
+   * DLL
+   */
+  struct CredentialRecordEntry *prev;
+  
+  /**
+   * Number of references in delegation chains
+   */
+  uint32_t refcount;
+
+  /**
+   * Payload
+   */
+  struct GNUNET_CREDENTIAL_Credential *credential;
+};
+
+/**
+ * DLL used for delegations
+ * Used for OR delegations
+ */
+struct DelegationQueueEntry
+{
+  /**
+   * DLL
+   */
+  struct DelegationQueueEntry *next;
+
+  /**
+   * DLL
+   */
+  struct DelegationQueueEntry *prev;
+
+  /**
+   * Sets under this Queue
+   */
+  struct DelegationSetQueueEntry *set_entries_head;
+
+  /**
+   * Sets under this Queue
+   */
+  struct DelegationSetQueueEntry *set_entries_tail;
+
+  /**
+   * Parent set
+   */
+  struct DelegationSetQueueEntry *parent_set;
+
+  /**
+   * Required solutions
+   */
+  uint32_t required_solutions;
+};
+
+/**
+ * DLL for delegation sets
+ * Used for AND delegation set
+ */
+struct DelegationSetQueueEntry
+{
+  /**
+   * DLL
+   */
+  struct DelegationSetQueueEntry *next;
+
+  /**
+   * DLL
+   */
+  struct DelegationSetQueueEntry *prev;
+
+    /**
+   * GNS handle
+   */
+  struct GNUNET_GNS_LookupRequest *lookup_request;
+
+  /**
+   * Verify handle
+   */
+  struct VerifyRequestHandle *handle;
+
+  /**
+   * Parent attribute delegation
+   */
+  struct DelegationQueueEntry *parent;
+
+  /**
+   * Issuer key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key;
+
+  /**
+   * Queue entries of this set
+   */
+  struct DelegationQueueEntry *queue_entries_head;
+
+  /**
+   * Queue entries of this set
+   */
+  struct DelegationQueueEntry *queue_entries_tail;
+
+  /**
+   * Parent QueueEntry
+   */
+  struct DelegationQueueEntry *parent_queue_entry;
+
+  /**
+   * Issuer attribute delegated to
+   */
+  char *issuer_attribute;
+
+  /**
+   * The current attribute to look up
+   */
+  char *lookup_attribute;
+
+  /**
+   * Trailing attribute context
+   */
+  char *attr_trailer;
+
+  /**
+   * Still to resolve delegation as string
+   */
+  char *unresolved_attribute_delegation;
+
+  /**
+   * The delegation chain entry
+   */
+  struct DelegationChainEntry *delegation_chain_entry;
+
+};
+
+
+/**
+ * Handle to a lookup operation from api
+ */
+struct VerifyRequestHandle
+{
+
+  /**
+   * We keep these in a DLL.
+   */
+  struct VerifyRequestHandle *next;
+
+  /**
+   * We keep these in a DLL.
+   */
+  struct VerifyRequestHandle *prev;
+
+  /**
+   * Handle to the requesting client
+   */
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * GNS handle
+   */
+  struct GNUNET_GNS_LookupRequest *lookup_request;
+
+  /**
+   * Size of delegation tree
+   */
+  uint32_t delegation_chain_size;
+
+  /**
+   * Children of this attribute
+   */
+  struct DelegationChainEntry *delegation_chain_head;
+
+  /**
+   * Children of this attribute
+   */
+  struct DelegationChainEntry *delegation_chain_tail;
+
+  /**
+   * Issuer public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Issuer attribute
+   */
+  char *issuer_attribute;
+
+  /**
+   * Subject public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Credential DLL
+   */
+  struct CredentialRecordEntry *cred_chain_head;
+
+  /**
+   * Credential DLL
+   */
+  struct CredentialRecordEntry *cred_chain_tail;
+
+  /**
+   * Credential DLL size
+   */
+  uint32_t cred_chain_size;
+
+  /**
+   * Root Delegation Set
+   */
+  struct DelegationSetQueueEntry *root_set;
+
+  /**
+   * Current Delegation Pointer
+   */
+  struct DelegationQueueEntry *current_delegation;
+
+  /**
+   * request id
+   */
+  uint32_t request_id;
+
+  /**
+   * Pending lookups
+   */
+  uint64_t pending_lookups;
+
+  /**
+   * Credential iterator
+   */
+  struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter;
+
+  /**
+   * Collect task
+   */
+  struct GNUNET_SCHEDULER_Task *collect_next_task;
+
+};
+
+
+/**
+ * Head of the DLL.
+ */
+static struct VerifyRequestHandle *vrh_head;
+
+/**
+ * Tail of the DLL.
+ */
+static struct VerifyRequestHandle *vrh_tail;
+
+/**
+ * Handle to the statistics service
+ */
+static struct GNUNET_STATISTICS_Handle *statistics;
+
+/**
+ * Handle to GNS service.
+ */
+static struct GNUNET_GNS_Handle *gns;
+
+
+/**
+ * Handle to namestore service
+ */
+static struct GNUNET_NAMESTORE_Handle *namestore;
+
+static void
+cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry)
+{
+  struct DelegationQueueEntry *dq_entry;
+  struct DelegationSetQueueEntry *child;
+
+  if (NULL == ds_entry)
+    return;
+
+  for (dq_entry = ds_entry->queue_entries_head;
+       NULL != dq_entry;
+       dq_entry = ds_entry->queue_entries_head)
+  {
+    GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head,
+                                 ds_entry->queue_entries_tail,
+                                 dq_entry);
+    for (child = dq_entry->set_entries_head;
+         NULL != child;
+         child = dq_entry->set_entries_head)
+    {
+      GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head,
+                                   dq_entry->set_entries_tail,
+                                   child);
+      cleanup_delegation_set (child);
+    }
+    GNUNET_free (dq_entry);
+  }
+  if (NULL != ds_entry->issuer_key)
+    GNUNET_free (ds_entry->issuer_key);
+  if (NULL != ds_entry->lookup_attribute)
+    GNUNET_free (ds_entry->lookup_attribute);
+  if (NULL != ds_entry->issuer_attribute)
+    GNUNET_free (ds_entry->issuer_attribute);
+  if (NULL != ds_entry->unresolved_attribute_delegation)
+    GNUNET_free (ds_entry->unresolved_attribute_delegation);
+  if (NULL != ds_entry->attr_trailer)
+    GNUNET_free (ds_entry->attr_trailer);
+  if (NULL != ds_entry->lookup_request)
+  {
+    GNUNET_GNS_lookup_cancel (ds_entry->lookup_request);
+    ds_entry->lookup_request = NULL;
+  }
+  if (NULL != ds_entry->delegation_chain_entry)
+  {
+    if (NULL != ds_entry->delegation_chain_entry->subject_attribute)
+      GNUNET_free (ds_entry->delegation_chain_entry->subject_attribute);
+    if (NULL != ds_entry->delegation_chain_entry->issuer_attribute)
+      GNUNET_free (ds_entry->delegation_chain_entry->issuer_attribute);
+    GNUNET_free (ds_entry->delegation_chain_entry);
+  }
+  GNUNET_free (ds_entry);
+}
+
+static void
+cleanup_handle (struct VerifyRequestHandle *vrh)
+{
+  struct CredentialRecordEntry *cr_entry;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Cleaning up...\n");
+  if (NULL != vrh->lookup_request)
+  {
+    GNUNET_GNS_lookup_cancel (vrh->lookup_request);
+    vrh->lookup_request = NULL;
+  }
+  cleanup_delegation_set (vrh->root_set);
+  if (NULL != vrh->issuer_attribute)
+    GNUNET_free (vrh->issuer_attribute);
+  for (cr_entry = vrh->cred_chain_head; 
+       NULL != vrh->cred_chain_head;
+       cr_entry = vrh->cred_chain_head)
+  {
+    GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
+                                 vrh->cred_chain_tail,
+                                 cr_entry);
+    if (NULL != cr_entry->credential);
+      GNUNET_free (cr_entry->credential);
+    GNUNET_free (cr_entry);
+  }
+  GNUNET_free (vrh);
+}
+
+/**
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls)
+{
+  struct VerifyRequestHandle *vrh;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Shutting down!\n");
+
+  while (NULL != (vrh = vrh_head))
+  {
+    //CREDENTIAL_resolver_lookup_cancel (clh->lookup);
+    GNUNET_CONTAINER_DLL_remove (vrh_head,
+                                 vrh_tail,
+                                 vrh);
+    cleanup_handle (vrh);
+  }
+
+  if (NULL != gns)
+  {
+    GNUNET_GNS_disconnect (gns);
+    gns = NULL;
+  }
+  if (NULL != namestore)
+  {
+    GNUNET_NAMESTORE_disconnect (namestore);
+    namestore = NULL;
+  }
+  if (NULL != statistics)
+  {
+    GNUNET_STATISTICS_destroy (statistics,
+                               GNUNET_NO);
+    statistics = NULL;
+  }
+
+}
+
+
+
+/**
+ * Send.
+ *
+ * @param handle the handle to the request
+ */
+static void
+send_lookup_response (struct VerifyRequestHandle *vrh)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct DelegationChainResultMessage *rmsg;
+  struct DelegationChainEntry *dce;
+  struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size];
+  struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size];
+  struct CredentialRecordEntry *cd;
+  struct CredentialRecordEntry *tmp;
+  size_t size;
+  int i;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending response\n");
+  dce = vrh->delegation_chain_head;
+  for (i=0;i<vrh->delegation_chain_size;i++)
+  {
+    dd[i].issuer_key = dce->issuer_key;
+    dd[i].subject_key = dce->subject_key;
+    dd[i].issuer_attribute = dce->issuer_attribute;
+    dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1;
+    dd[i].subject_attribute_len = 0;
+    dd[i].subject_attribute = NULL;
+    if (NULL != dce->subject_attribute)
+    {
+      dd[i].subject_attribute = dce->subject_attribute;
+      dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1;
+    }
+    dce = dce->next;
+  }
+
+  /**
+   * Remove all credentials not needed
+   */
+  for (cd = vrh->cred_chain_head; NULL != cd;)
+  {
+    if (cd->refcount > 0)
+    {
+      cd = cd->next;
+      continue;
+    }
+    tmp = cd;
+    cd = cd->next;
+    GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head,
+                                 vrh->cred_chain_tail,
+                                 tmp);
+    GNUNET_free (tmp->credential);
+    GNUNET_free (tmp);
+    vrh->cred_chain_size--;
+  }
+
+  /**
+   * Get serialized record data
+   * Append at the end of rmsg
+   */
+  cd = vrh->cred_chain_head;
+  for (i=0;i<vrh->cred_chain_size;i++)
+  {
+    cred[i].issuer_key = cd->credential->issuer_key;
+    cred[i].subject_key = cd->credential->subject_key;
+    cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1;
+    cred[i].issuer_attribute = cd->credential->issuer_attribute;
+    cred[i].expiration = cd->credential->expiration;
+    cred[i].signature = cd->credential->signature;
+    cd = cd->next;
+  }
+  size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size,
+                                                      dd,
+                                                      vrh->cred_chain_size,
+                                                      cred);
+  env = GNUNET_MQ_msg_extra (rmsg,
+                             size,
+                             GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
+  //Assign id so that client can find associated request
+  rmsg->id = vrh->request_id;
+  rmsg->d_count = htonl (vrh->delegation_chain_size);
+  rmsg->c_count = htonl (vrh->cred_chain_size);
+
+  if (0 < vrh->cred_chain_size)
+    rmsg->cred_found = htonl (GNUNET_YES);
+  else
+    rmsg->cred_found = htonl (GNUNET_NO);
+
+  GNUNET_assert (-1 != 
+                 GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size,
+                                                               dd,
+                                                               vrh->cred_chain_size,
+                                                               cred,
+                                                               size,
+                                                               (char*)&rmsg[1]));
+
+  GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
+                  env);
+  GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
+  cleanup_handle(vrh);
+
+  GNUNET_STATISTICS_update (statistics,
+                            "Completed verifications", 1,
+                            GNUNET_NO);
+}
+
+
+static void
+backward_resolution (void* cls,
+                     uint32_t rd_count,
+                     const struct GNUNET_GNSRECORD_Data *rd)
+{
+
+  struct VerifyRequestHandle *vrh;
+  const struct GNUNET_CREDENTIAL_DelegationRecord *sets;
+  struct CredentialRecordEntry *cred_pointer;
+  struct DelegationSetQueueEntry *current_set;
+  struct DelegationSetQueueEntry *ds_entry;
+  struct DelegationSetQueueEntry *tmp_set;
+  struct DelegationQueueEntry *dq_entry;
+  char *expanded_attr;
+  char *lookup_attribute;
+  int i;
+  int j;
+
+
+  current_set = cls;
+  current_set->lookup_request = NULL;
+  vrh = current_set->handle;
+  vrh->pending_lookups--;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got %d attrs\n", rd_count);
+
+  // Each OR
+  for (i=0; i < rd_count; i++) 
+  {
+    if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
+      continue;
+
+    sets = rd[i].data;
+    struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)];
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Found new attribute delegation with %d sets. Creating new Job...\n",
+                ntohl (sets->set_count));
+
+    if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size),
+                                                                  (const char*)&sets[1],
+                                                                  ntohl(sets->set_count),
+                                                                  set))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to deserialize!\n");
+      continue;
+    }
+    dq_entry = GNUNET_new (struct DelegationQueueEntry);
+    dq_entry->required_solutions = ntohl(sets->set_count);
+    dq_entry->parent_set = current_set;
+    GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head,
+                                 current_set->queue_entries_tail,
+                                 dq_entry);
+    // Each AND
+    for (j=0; j<ntohl(sets->set_count); j++)
+    {
+      ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
+      if (NULL != current_set->attr_trailer)
+      {
+        if (0 == set[j].subject_attribute_len)
+        {
+          GNUNET_asprintf (&expanded_attr,
+                           "%s",
+                           current_set->attr_trailer);
+
+        } else {
+          GNUNET_asprintf (&expanded_attr,
+                           "%s.%s",
+                           set[j].subject_attribute,
+                           current_set->attr_trailer);
+        }
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Expanded to %s\n", expanded_attr);
+        ds_entry->unresolved_attribute_delegation = expanded_attr;
+      } else {
+        if (0 != set[j].subject_attribute_len)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Not Expanding %s\n", set[j].subject_attribute);
+          ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute);
+        }
+      }
+
+      //Add a credential chain entry
+      ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry);
+      ds_entry->delegation_chain_entry->subject_key = set[j].subject_key;
+      ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
+      GNUNET_memcpy (ds_entry->issuer_key,
+                     &set[j].subject_key,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+      if (0 < set[j].subject_attribute_len)
+        ds_entry->delegation_chain_entry->subject_attribute =  GNUNET_strdup (set[j].subject_attribute);
+      ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key;
+      ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute);
+
+      ds_entry->parent_queue_entry = dq_entry; //current_delegation;
+      GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head,
+                                   dq_entry->set_entries_tail,
+                                   ds_entry);
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Checking for cred match\n");
+      /**
+       * Check if this delegation already matches one of our credentials
+       */
+      for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; 
+          cred_pointer = cred_pointer->next)
+      {
+        if(0 != memcmp (&set->subject_key, 
+                        &cred_pointer->credential->issuer_key,
+                        sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
+          continue;
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Checking if %s matches %s\n",
+                    ds_entry->unresolved_attribute_delegation,
+                    cred_pointer->credential->issuer_attribute);
+
+        if (0 != strcmp (ds_entry->unresolved_attribute_delegation,
+                         cred_pointer->credential->issuer_attribute))
+          continue;
+
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Found issuer\n");
+        cred_pointer->refcount++;
+        //Backtrack
+        for (tmp_set = ds_entry;
+             NULL != tmp_set->parent_queue_entry;
+             tmp_set = tmp_set->parent_queue_entry->parent_set)
+        {
+          tmp_set->parent_queue_entry->required_solutions--;
+          if (NULL != tmp_set->delegation_chain_entry)
+          {
+            vrh->delegation_chain_size++;
+            GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head,
+                                         vrh->delegation_chain_tail,
+                                         tmp_set->delegation_chain_entry);
+          }
+          if (0 < tmp_set->parent_queue_entry->required_solutions)
+            break;
+        }
+
+        if (NULL == tmp_set->parent_queue_entry)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "All solutions found\n");
+          //Found match
+          send_lookup_response (vrh);
+          return;
+        }
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Not all solutions found yet.\n");
+        continue;
+
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Building new lookup request from %s\n",
+                  ds_entry->unresolved_attribute_delegation);
+      //Continue with backward resolution
+      char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1];
+      strcpy (issuer_attribute_name,
+              ds_entry->unresolved_attribute_delegation);
+      char *next_attr = strtok (issuer_attribute_name, ".");
+      GNUNET_asprintf (&lookup_attribute,
+                       "%s.gnu",
+                       next_attr);
+      GNUNET_asprintf (&ds_entry->lookup_attribute,
+                       "%s",
+                       next_attr);
+      if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation))
+      {
+        ds_entry->attr_trailer = NULL;
+      } else {
+        next_attr += strlen (next_attr) + 1;
+        ds_entry->attr_trailer = GNUNET_strdup (next_attr);
+      }
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Looking up %s\n", ds_entry->lookup_attribute);
+      if (NULL != ds_entry->attr_trailer)
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "%s still to go...\n", ds_entry->attr_trailer);
+
+      vrh->pending_lookups++;
+      ds_entry->handle = vrh;
+      ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
+                                                    lookup_attribute,
+                                                    ds_entry->issuer_key, //issuer_key,
+                                                    GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
+                                                    GNUNET_GNS_LO_DEFAULT,
+                                                    &backward_resolution,
+                                                    ds_entry);
+      GNUNET_free (lookup_attribute);
+    }
+  }
+
+  if(0 == vrh->pending_lookups)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "We are all out of attributes...\n");
+    send_lookup_response (vrh);
+    return;
+
+  }
+} 
+
+
+/**
+ * Result from GNS lookup.
+ *
+ * @param cls the closure (our client lookup handle)
+ * @param rd_count the number of records in @a rd
+ * @param rd the record data
+ */
+static void
+delegation_chain_resolution_start (void* cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  struct DelegationSetQueueEntry *ds_entry;
+  struct CredentialRecordEntry *cr_entry;
+  vrh->lookup_request = NULL;
+
+  if (0 == vrh->cred_chain_size)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "No credentials found\n");
+    send_lookup_response (vrh);
+    return;
+  }
+
+  for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next)
+  {
+    if (0 != memcmp (&cr_entry->credential->issuer_key,
+                     &vrh->issuer_key,
+                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
+      continue;
+    if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute))
+      continue;
+    cr_entry->refcount++;
+    //Found match prematurely
+    send_lookup_response (vrh);
+    return;
+
+  }
+
+  /**
+   * Check for attributes from the issuer and follow the chain 
+   * till you get the required subject's attributes
+   */
+  char issuer_attribute_name[strlen (vrh->issuer_attribute)];
+  strcpy (issuer_attribute_name,
+          vrh->issuer_attribute);
+  strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute),
+          ".gnu");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Looking up %s\n", issuer_attribute_name);
+  ds_entry = GNUNET_new (struct DelegationSetQueueEntry);
+  ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
+  memcpy (ds_entry->issuer_key,
+          &vrh->issuer_key,
+          sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+  ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute);
+  ds_entry->handle = vrh;
+  ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute);
+  vrh->root_set = ds_entry;
+  vrh->pending_lookups = 1;
+  //Start with backward resolution
+  ds_entry->lookup_request = GNUNET_GNS_lookup (gns,
+                                                issuer_attribute_name,
+                                                &vrh->issuer_key, //issuer_key,
+                                                GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
+                                                GNUNET_GNS_LO_DEFAULT,
+                                                &backward_resolution,
+                                                ds_entry);
+}
+
+/**
+ * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY message
+ *
+ * @param cls client sending the message
+ * @param v_msg message of type `struct VerifyMessage`
+ * @return #GNUNET_OK if @a v_msg is well-formed
+ */
+static int
+check_verify (void *cls,
+              const struct VerifyMessage *v_msg)
+{
+  size_t msg_size;
+  const char* attr;
+
+  msg_size = ntohs (v_msg->header.size);
+  if (msg_size < sizeof (struct VerifyMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  attr = (const char *) &v_msg[1];
+
+  if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+/**
+ * Handle Credential verification requests from client
+ *
+ * @param cls the closure
+ * @param client the client
+ * @param message the message
+ */
+static void
+handle_verify (void *cls,
+               const struct VerifyMessage *v_msg) 
+{
+  struct VerifyRequestHandle *vrh;
+  struct GNUNET_SERVICE_Client *client = cls;
+  struct CredentialRecordEntry *cr_entry;
+  uint32_t credentials_count;
+  uint32_t credential_data_size;
+  int i;
+  char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char *attrptr = attr;
+  char *credential_data;
+  const char *utf_in;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received VERIFY message\n");
+  utf_in = (const char *) &v_msg[1];
+  GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
+  GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len));
+  issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0';
+  vrh = GNUNET_new (struct VerifyRequestHandle);
+  GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
+  vrh->client = client;
+  vrh->request_id = v_msg->id;
+  vrh->issuer_key = v_msg->issuer_key;
+  vrh->subject_key = v_msg->subject_key;
+  vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
+  if (NULL == issuer_attribute)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "No issuer attribute provided!\n");
+    send_lookup_response (vrh);
+    return;
+  }
+  /**
+   * First, collect credentials
+   * TODO: cleanup!
+   */
+  credentials_count = ntohl(v_msg->c_count);
+  credential_data_size = ntohs (v_msg->header.size) 
+    - sizeof (struct VerifyMessage)
+    - ntohs (v_msg->issuer_attribute_len)
+    - 1;
+  struct GNUNET_CREDENTIAL_Credential credentials[credentials_count];
+  credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1;
+  if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size,
+                                                              credential_data,
+                                                              credentials_count,
+                                                              credentials))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "Cannot deserialize credentials!\n");
+    send_lookup_response (vrh);
+    return;
+  }
+
+  for (i=0;i<credentials_count;i++) {
+    cr_entry = GNUNET_new (struct CredentialRecordEntry);
+    cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) +
+                                          credentials[i].issuer_attribute_len);
+    GNUNET_memcpy (cr_entry->credential,
+                   &credentials[i],
+                   sizeof (struct GNUNET_CREDENTIAL_Credential));
+    GNUNET_memcpy (&cr_entry->credential[1],
+                   credentials[i].issuer_attribute,
+                   credentials[i].issuer_attribute_len);
+    cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1];
+    GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
+                                      vrh->cred_chain_tail,
+                                      cr_entry);
+    vrh->cred_chain_size++;
+  }
+
+  delegation_chain_resolution_start (vrh);
+
+}
+
+/**
+ * We encountered an error while collecting
+ */
+static void
+handle_cred_collection_error_cb (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Got disconnected from namestore database.\n");
+  vrh->cred_collection_iter = NULL;
+  send_lookup_response (vrh);
+}
+
+static void
+collect_next (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  vrh->collect_next_task = NULL;
+  GNUNET_assert (NULL != vrh->cred_collection_iter);
+  GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter);
+}
+
+/**
+ * Store credential
+ */
+static void
+handle_cred_collection_cb (void *cls,
+                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
+                           const char *label,
+                           unsigned int rd_count,
+                           const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  struct GNUNET_CREDENTIAL_Credential *crd;
+  struct CredentialRecordEntry *cr_entry;
+  int cred_record_count;
+  int i;
+
+  cred_record_count = 0;
+  for (i=0; i < rd_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type)
+      continue;
+    cred_record_count++;
+    crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data,
+                                                    rd[i].data_size);
+    if (NULL == crd)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Invalid credential found\n");
+      continue;
+    }
+    cr_entry = GNUNET_new (struct CredentialRecordEntry);
+    cr_entry->credential = crd;
+    GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head,
+                                      vrh->cred_chain_tail,
+                                      cr_entry);
+    vrh->cred_chain_size++;
+  }
+  vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next,
+                                                     vrh);
+}
+
+/**
+ * We encountered an error while collecting
+ */
+static void
+handle_cred_collection_finished_cb (void *cls)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Done collecting credentials.\n");
+  vrh->cred_collection_iter = NULL;
+  delegation_chain_resolution_start (vrh);
+}
+
+/**
+ * Handle Credential collection requests from client
+ *
+ * @param cls the closure
+ * @param client the client
+ * @param message the message
+ */
+static void
+handle_collect (void *cls,
+                const struct CollectMessage *c_msg) 
+{
+  char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  struct VerifyRequestHandle *vrh;
+  struct GNUNET_SERVICE_Client *client = cls;
+  char *attrptr = attr;
+  const char *utf_in;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received COLLECT message\n");
+
+  utf_in = (const char *) &c_msg[1];
+  GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
+
+  GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len));
+  issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0';
+  vrh = GNUNET_new (struct VerifyRequestHandle);
+  GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh);
+  vrh->client = client;
+  vrh->request_id = c_msg->id;
+  vrh->issuer_key = c_msg->issuer_key;
+  GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key,
+                                      &vrh->subject_key);
+  vrh->issuer_attribute = GNUNET_strdup (issuer_attribute);
+
+  if (NULL == issuer_attribute)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "No issuer attribute provided!\n");
+    send_lookup_response (vrh);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Getting credentials for subject\n");
+  /**
+   * First, get attribute from subject
+   */
+  vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore,
+                                                                     &c_msg->subject_key,
+                                                                     &handle_cred_collection_error_cb,
+                                                                     vrh,
+                                                                     &handle_cred_collection_cb,
+                                                                     vrh,
+                                                                     &handle_cred_collection_finished_cb,
+                                                                     vrh);
+}
+
+
+/**
+ * Checks a #GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT message
+ *
+ * @param cls client sending the message
+ * @param v_msg message of type `struct CollectMessage`
+ * @return #GNUNET_OK if @a v_msg is well-formed
+ */
+static int
+check_collect (void *cls,
+               const struct CollectMessage *c_msg)
+{
+  size_t msg_size;
+  const char* attr;
+
+  msg_size = ntohs (c_msg->header.size);
+  if (msg_size < sizeof (struct CollectMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  attr = (const char *) &c_msg[1];
+
+  if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) ||
+       (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+/**
+ * One of our clients disconnected, clean up after it.
+ *
+ * @param cls NULL
+ * @param client the client that disconnected
+ */
+static void
+client_disconnect_cb (void *cls,
+                      struct GNUNET_SERVICE_Client *client,
+                      void *app_ctx)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client %p disconnected\n",
+              client);
+}
+
+/**
+ * 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 this client
+ */
+static void *
+client_connect_cb (void *cls,
+                   struct GNUNET_SERVICE_Client *client,
+                   struct GNUNET_MQ_Handle *mq)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client %p connected\n",
+              client);
+  return client;
+}
+
+/**
+ * Process Credential requests.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *handle)
+{
+
+  gns = GNUNET_GNS_connect (c);
+  if (NULL == gns)
+  {
+    fprintf (stderr,
+             _("Failed to connect to GNS\n"));
+  }
+  namestore = GNUNET_NAMESTORE_connect (c);
+  if (NULL == namestore)
+  {
+    fprintf (stderr,
+             _("Failed to connect to namestore\n"));
+  }
+
+  statistics = GNUNET_STATISTICS_create ("credential", c);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
+}
+
+
+/**
+ * Define "main" method using service macro
+ */
+GNUNET_SERVICE_MAIN
+("credential",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (verify,
+                        GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY,
+                        struct VerifyMessage,
+                        NULL),
+ GNUNET_MQ_hd_var_size (collect,
+                        GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT,
+                        struct CollectMessage,
+                        NULL),
+ GNUNET_MQ_handler_end());
+
+/* end of gnunet-service-credential.c */
diff --git a/src/credential/plugin_gnsrecord_credential.c b/src/credential/plugin_gnsrecord_credential.c
new file mode 100644 (file)
index 0000000..daecc1b
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+     This file is part of GNUnet
+     Copyright (C) 2013 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file credential/plugin_gnsrecord_credential.c
+ * @brief gnsrecord plugin to provide the API for CREDENTIAL records
+ * @author Adnan Husain
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_gnsrecord_lib.h"
+#include "gnunet_credential_service.h"
+#include "gnunet_gnsrecord_plugin.h"
+#include "gnunet_signatures.h"
+#include "credential_serialization.h"
+#include "credential_misc.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 *
+credential_value_to_string (void *cls,
+                              uint32_t type,
+                              const void *data,
+                              size_t data_size)
+{
+
+  const char *cdata;
+
+  switch (type)
+  {
+   case GNUNET_GNSRECORD_TYPE_ATTRIBUTE:
+   {
+    struct GNUNET_CREDENTIAL_DelegationRecord sets;
+    char *attr_str;
+    char *subject_pkey;
+    char *tmp_str;
+    int i;
+    if (data_size < sizeof (struct GNUNET_CREDENTIAL_DelegationRecord))
+      return NULL; /* malformed */
+    memcpy (&sets,
+            data,
+            sizeof (sets));
+    cdata = data;
+    struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets.set_count)];
+    if (GNUNET_OK != GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll (sets.data_size),
+                                                                   &cdata[sizeof (sets)],
+                                                                   ntohl (sets.set_count),
+                                                                   set))
+      return NULL;
+
+    for (i=0;i<ntohl(sets.set_count);i++)
+    {
+      subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&set[i].subject_key);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "%d len attr\n", set[i].subject_attribute_len);
+      if (0 == set[i].subject_attribute_len)
+      {
+        if (0 == i)
+        {
+          GNUNET_asprintf (&attr_str,
+                           "%s",
+                           subject_pkey);
+        } else {
+          GNUNET_asprintf (&tmp_str,
+                           "%s,%s",
+                           attr_str,
+                           subject_pkey);
+          GNUNET_free (attr_str);
+          attr_str = tmp_str;
+        }
+      } else {
+        if (0 == i)
+        {
+          GNUNET_asprintf (&attr_str,
+                           "%s %s",
+                           subject_pkey,
+                           set[i].subject_attribute);
+        } else {
+          GNUNET_asprintf (&tmp_str,
+                           "%s,%s %s",
+                           attr_str,
+                           subject_pkey,
+                           set[i].subject_attribute);
+          GNUNET_free (attr_str);
+          attr_str = tmp_str;
+        }
+      }
+      GNUNET_free (subject_pkey);
+    }
+    return attr_str;
+   }
+   case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
+   {
+     struct GNUNET_CREDENTIAL_Credential *cred;
+     char *cred_str;
+
+     cred = GNUNET_CREDENTIAL_credential_deserialize (data,
+                                                      data_size);
+     cred_str = GNUNET_CREDENTIAL_credential_to_string (cred);
+     GNUNET_free (cred);
+     return cred_str;
+   }
+   case GNUNET_GNSRECORD_TYPE_POLICY:
+   {
+     return GNUNET_strndup (data,data_size);
+   }
+   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
+credential_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_GNSRECORD_TYPE_ATTRIBUTE:
+      {
+        struct GNUNET_CREDENTIAL_DelegationRecord *sets;
+        char attr_str[253 + 1];
+        char subject_pkey[52 + 1];
+        char *token;
+        char *tmp_str;
+        int matches = 0;
+        int entries;
+        size_t tmp_data_size;
+        int i;
+
+        tmp_str = GNUNET_strdup (s);
+        token = strtok (tmp_str, ",");
+        entries = 0;
+        tmp_data_size = 0;
+        *data_size = sizeof (struct GNUNET_CREDENTIAL_DelegationRecord);
+        while (NULL != token)
+        {
+          matches = SSCANF (token,
+                            "%s %s",
+                            subject_pkey,
+                            attr_str);
+          if (0 == matches)
+          {
+            GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                        _("Unable to parse ATTR record string `%s'\n"),
+                        s);
+            GNUNET_free (tmp_str);
+            return GNUNET_SYSERR;
+          }
+          if (1 == matches) {
+            tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet);
+          } else if (2 == matches) {
+            tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet) + strlen (attr_str) + 1;
+          }
+          entries++;
+          token = strtok (NULL, ",");
+        }
+        GNUNET_free (tmp_str);
+        tmp_str = GNUNET_strdup (s);
+        token = strtok (tmp_str, ",");
+        struct GNUNET_CREDENTIAL_DelegationSet set[entries];
+        for (i=0;i<entries;i++)
+        {
+          matches = SSCANF (token,
+                            "%s %s",
+                            subject_pkey,
+                            attr_str);
+          GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey,
+                                                      strlen (subject_pkey),
+                                                      &set[i].subject_key);
+          if (2 == matches) {
+            set[i].subject_attribute_len = strlen (attr_str) + 1;
+            set[i].subject_attribute = GNUNET_strdup (attr_str);
+          }
+          token = strtok (NULL , ",");
+        }
+        tmp_data_size = GNUNET_CREDENTIAL_delegation_set_get_size (entries,
+                                                                   set);
+        
+        if (-1 == tmp_data_size)
+          return GNUNET_SYSERR;
+        *data_size += tmp_data_size;
+        *data = sets = GNUNET_malloc (*data_size);
+        GNUNET_CREDENTIAL_delegation_set_serialize (entries,
+                                                    set,
+                                                    tmp_data_size,
+                                                    (char*)&sets[1]);
+        for (i=0;i<entries;i++)
+        {
+          if (0 != set[i].subject_attribute_len)
+            GNUNET_free ((char*)set[i].subject_attribute);
+        }
+        sets->set_count = htonl (entries);
+        sets->data_size = GNUNET_htonll (tmp_data_size);
+
+        GNUNET_free (tmp_str);
+        return GNUNET_OK;
+      }
+    case GNUNET_GNSRECORD_TYPE_CREDENTIAL:
+      { 
+        struct GNUNET_CREDENTIAL_Credential *cred;
+        cred = GNUNET_CREDENTIAL_credential_from_string (s);
+
+        *data_size = GNUNET_CREDENTIAL_credential_serialize (cred,
+                                                             (char**)data);
+        return GNUNET_OK;
+      }
+    case GNUNET_GNSRECORD_TYPE_POLICY:
+      {
+        *data_size = strlen (s);
+        *data = GNUNET_strdup (s);
+        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[] = {
+  { "CRED", GNUNET_GNSRECORD_TYPE_CREDENTIAL },
+  { "ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE },
+  { "POLICY", GNUNET_GNSRECORD_TYPE_POLICY },
+  { NULL, UINT32_MAX }
+};
+
+
+/**
+ * Convert a type name (i.e. "AAAA") to the corresponding number.
+ *
+ * @param cls closure, unused
+ * @param gns_typename name to convert
+ * @return corresponding number, UINT32_MAX on error
+ */
+static uint32_t
+credential_typename_to_number (void *cls,
+                               const char *gns_typename)
+{
+  unsigned int i;
+
+  i=0;
+  while ( (name_map[i].name != NULL) &&
+          (0 != strcasecmp (gns_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 *
+credential_number_to_typename (void *cls,
+                               uint32_t type)
+{
+  unsigned int i;
+
+  i=0;
+  while ( (name_map[i].name != NULL) &&
+          (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_credential_init (void *cls)
+{
+  struct GNUNET_GNSRECORD_PluginFunctions *api;
+
+  api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
+  api->value_to_string = &credential_value_to_string;
+  api->string_to_value = &credential_string_to_value;
+  api->typename_to_number = &credential_typename_to_number;
+  api->number_to_typename = &credential_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_credential_done (void *cls)
+{
+  struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
+
+  GNUNET_free (api);
+  return NULL;
+}
+
+/* end of plugin_gnsrecord_credential.c */
diff --git a/src/credential/plugin_rest_credential.c b/src/credential/plugin_rest_credential.c
new file mode 100644 (file)
index 0000000..48d48fb
--- /dev/null
@@ -0,0 +1,1179 @@
+/*
+   This file is part of GNUnet.
+   Copyright (C) 2012-2016 GNUnet e.V.
+
+   GNUnet is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GNUnet is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNUnet; see the file COPYING.  If not, write to the
+   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.
+   */
+/**
+ * @author Martin Schanzenbach
+ * @file gns/plugin_rest_credential.c
+ * @brief GNUnet CREDENTIAL REST plugin
+ *
+ */
+
+#include "platform.h"
+#include "gnunet_rest_plugin.h"
+#include <gnunet_identity_service.h>
+#include <gnunet_gnsrecord_lib.h>
+#include <gnunet_namestore_service.h>
+#include <gnunet_credential_service.h>
+#include <gnunet_rest_lib.h>
+#include <gnunet_jsonapi_lib.h>
+#include <gnunet_jsonapi_util.h>
+#include <jansson.h>
+
+#define GNUNET_REST_API_NS_CREDENTIAL "/credential"
+
+#define GNUNET_REST_API_NS_CREDENTIAL_ISSUE "/credential/issue"
+
+#define GNUNET_REST_API_NS_CREDENTIAL_VERIFY "/credential/verify"
+
+#define GNUNET_REST_API_NS_CREDENTIAL_COLLECT "/credential/collect"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION "expiration"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY "subject_key"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO "subject"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL "credential"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential"
+
+#define GNUNET_REST_JSONAPI_DELEGATIONS "delegations"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute"
+
+#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential"
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct Plugin
+{
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+};
+
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+struct RequestHandle
+{
+  /**
+   * Handle to Credential service.
+   */
+  struct GNUNET_CREDENTIAL_Handle *credential;
+
+  /**
+   * Handle to lookup request
+   */
+  struct GNUNET_CREDENTIAL_Request *verify_request;
+
+  /**
+   * Handle to issue request
+   */
+  struct GNUNET_CREDENTIAL_Request *issue_request;
+
+  /**
+   * Handle to identity
+   */
+  struct GNUNET_IDENTITY_Handle *identity;
+
+  /**
+   * Handle to identity operation
+   */
+  struct GNUNET_IDENTITY_Operation *id_op;
+
+  /**
+   * Handle to ego lookup
+   */
+  struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
+
+  /**
+   * Handle to rest request
+   */
+  struct GNUNET_REST_RequestHandle *rest_handle;
+
+  /**
+   * ID of a task associated with the resolution process.
+   */
+  struct GNUNET_SCHEDULER_Task * timeout_task;
+
+  /**
+   * The root of the received JSON or NULL
+   */
+  json_t *json_root;
+
+  /**
+   * The plugin result processor
+   */
+  GNUNET_REST_ResultProcessor proc;
+
+  /**
+   * The closure of the result processor
+   */
+  void *proc_cls;
+
+  /**
+   * The issuer attribute to verify
+   */
+  char *issuer_attr;
+
+  /**
+   * The subject attribute
+   */
+  char *subject_attr;
+
+  /**
+   * The public key of the issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * The public key of the subject
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * HTTP response code
+   */
+  int response_code;
+
+  /**
+   * Timeout
+   */
+  struct GNUNET_TIME_Relative timeout;
+
+};
+
+
+/**
+ * Cleanup lookup handle.
+ *
+ * @param handle Handle to clean up
+ */
+static void
+cleanup_handle (struct RequestHandle *handle)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Cleaning up\n");
+  if (NULL != handle->json_root)
+    json_decref (handle->json_root);
+
+  if (NULL != handle->issuer_attr)
+    GNUNET_free (handle->issuer_attr);
+  if (NULL != handle->subject_attr)
+    GNUNET_free (handle->subject_attr);
+  if (NULL != handle->verify_request)
+    GNUNET_CREDENTIAL_request_cancel (handle->verify_request);
+  if (NULL != handle->credential)
+    GNUNET_CREDENTIAL_disconnect (handle->credential);
+  if (NULL != handle->id_op)
+    GNUNET_IDENTITY_cancel (handle->id_op);
+  if (NULL != handle->ego_lookup)
+    GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup);
+  if (NULL != handle->identity)
+    GNUNET_IDENTITY_disconnect (handle->identity);
+  if (NULL != handle->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (handle->timeout_task);
+  }
+  GNUNET_free (handle);
+}
+
+
+/**
+ * Task run on shutdown.  Cleans up everything.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+do_error (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+
+  resp = GNUNET_REST_create_response (NULL);
+  handle->proc (handle->proc_cls, resp, handle->response_code);
+  cleanup_handle (handle);
+}
+
+/**
+ * Attribute delegation to JSON
+ * @param attr the attribute
+ * @return JSON, NULL if failed
+ */
+static json_t*
+attribute_delegation_to_json (struct GNUNET_CREDENTIAL_Delegation *delegation_chain_entry)
+{
+  char *subject;
+  char *issuer;
+  json_t *attr_obj;
+
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer in delegation malformed\n");
+    return NULL;
+  }
+  subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->subject_key);
+  if (NULL == subject)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject in credential malformed\n");
+    GNUNET_free (issuer);
+    return NULL;
+  }
+  attr_obj = json_object ();
+
+    json_object_set_new (attr_obj, "issuer", json_string (issuer));
+  json_object_set_new (attr_obj, "issuer_attribute",
+                       json_string (delegation_chain_entry->issuer_attribute));
+
+  json_object_set_new (attr_obj, "subject", json_string (subject));
+  if (0 < delegation_chain_entry->subject_attribute_len)
+  {
+    json_object_set_new (attr_obj, "subject_attribute",
+                         json_string (delegation_chain_entry->subject_attribute));
+  }
+  GNUNET_free (issuer);
+  GNUNET_free (subject);
+  return attr_obj;
+}
+
+/**
+ * JSONAPI resource to Credential
+ * @param res the JSONAPI resource
+ * @return the resulting credential, NULL if failed
+ */
+static struct GNUNET_CREDENTIAL_Credential*
+json_to_credential (json_t *res)
+{
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  json_t *tmp;
+  const char *attribute;
+  const char *signature;
+  char *sig;
+
+  tmp = json_object_get (res, "attribute");
+  if (0 == json_is_string (tmp))
+  {
+    return NULL;
+  }
+  attribute = json_string_value (tmp);
+  cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential)
+                        + strlen (attribute));
+  cred->issuer_attribute = attribute;
+  cred->issuer_attribute_len = strlen (attribute);
+  tmp = json_object_get (res, "issuer");
+  if (0 == json_is_string (tmp))
+  {
+    GNUNET_free (cred);
+    return NULL;
+  }
+
+  GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp),
+                                              strlen (json_string_value(tmp)),
+                                              &cred->issuer_key);
+  tmp = json_object_get (res, "subject");
+  if (0 == json_is_string (tmp))
+  {
+    GNUNET_free (cred);
+    return NULL;
+  }
+  GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp),
+                                              strlen (json_string_value(tmp)),
+                                              &cred->subject_key);
+
+  tmp = json_object_get (res, "signature");
+  if (0 == json_is_string (tmp))
+  {
+    GNUNET_free (cred);
+    return NULL;
+  }
+  signature = json_string_value (tmp);
+  GNUNET_STRINGS_base64_decode (signature,
+                                strlen (signature),
+                                (char**)&sig);
+  GNUNET_memcpy (&cred->signature,
+                 sig,
+                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
+  GNUNET_free (sig);
+  tmp = json_object_get (res, "expiration");
+  if (0 == json_is_integer (tmp))
+  {
+    GNUNET_free (cred);
+    return NULL;
+  }
+  cred->expiration.abs_value_us = json_integer_value (tmp); 
+  return cred;
+}
+
+
+/**
+ * Credential to JSON
+ * @param cred the credential
+ * @return the resulting json, NULL if failed
+ */
+static json_t*
+credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  char *issuer;
+  char *subject;
+  char *signature;
+  char attribute[cred->issuer_attribute_len + 1];
+  json_t *cred_obj;
+
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer in credential malformed\n");
+    return NULL;
+  }  
+  subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
+  if (NULL == subject)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject in credential malformed\n");
+    GNUNET_free (issuer);
+    return NULL;
+  }
+  GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
+                                sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
+                                &signature);
+  memcpy (attribute,
+          cred->issuer_attribute,
+          cred->issuer_attribute_len);
+  attribute[cred->issuer_attribute_len] = '\0';
+  cred_obj = json_object ();
+  json_object_set_new (cred_obj, "issuer", json_string (issuer));
+  json_object_set_new (cred_obj, "subject", json_string (subject));
+  json_object_set_new (cred_obj, "attribute", json_string (attribute));
+  json_object_set_new (cred_obj, "signature", json_string (signature));
+  json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
+  GNUNET_free (issuer);
+  GNUNET_free (subject);
+  GNUNET_free (signature);
+  return cred_obj;
+}
+
+/**
+ * Function called with the result of a Credential lookup.
+ *
+ * @param cls the 'const char *' name that was resolved
+ * @param cd_count number of records returned
+ * @param cd array of @a cd_count records with the results
+ */
+static void
+handle_collect_response (void *cls,
+                        unsigned int d_count,
+                        struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
+                        unsigned int c_count,
+                        struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  struct GNUNET_JSONAPI_Document *json_document;
+  struct GNUNET_JSONAPI_Resource *json_resource;
+  json_t *cred_obj;
+  json_t *cred_array;
+  char *result;
+  char *issuer;
+  char *id;
+  uint32_t i;
+
+  handle->verify_request = NULL;
+  if (NULL == cred) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Verify failed.\n");
+    handle->response_code = MHD_HTTP_NOT_FOUND;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer in delegation malformed\n");
+    return;
+  }
+  GNUNET_asprintf (&id,
+                   "%s.%s",
+                   issuer,
+                   handle->issuer_attr);
+  GNUNET_free (issuer);
+  json_document = GNUNET_JSONAPI_document_new ();
+  json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
+                                               id);
+  GNUNET_free (id);
+  cred_array = json_array ();
+  for (i=0;i<c_count;i++)
+  {
+    cred_obj = credential_to_json (&cred[i]);
+    json_array_append_new (cred_array, cred_obj);
+  }
+  GNUNET_JSONAPI_resource_add_attr (json_resource,
+                                    GNUNET_REST_JSONAPI_CREDENTIAL,
+                                    cred_array);
+  GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
+  GNUNET_JSONAPI_document_serialize (json_document, &result);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Result %s\n",
+              result);
+  json_decref (cred_array);
+  GNUNET_JSONAPI_document_delete (json_document);
+  resp = GNUNET_REST_create_response (result);
+  GNUNET_free(result);
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  cleanup_handle (handle);
+}
+
+static void
+subject_ego_lookup (void *cls,
+                    const struct GNUNET_IDENTITY_Ego *ego)
+{
+  struct RequestHandle *handle = cls;
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *sub_key;
+  handle->ego_lookup = NULL;
+
+  if (NULL == ego)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject not found\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  sub_key = GNUNET_IDENTITY_ego_get_private_key (ego);
+  handle->verify_request = GNUNET_CREDENTIAL_collect (handle->credential,
+                                                      &handle->issuer_key,
+                                                      handle->issuer_attr,
+                                                      sub_key,
+                                                      &handle_collect_response,
+                                                      handle);
+}
+
+
+
+/**
+ * Function called with the result of a Credential lookup.
+ *
+ * @param cls the 'const char *' name that was resolved
+ * @param cd_count number of records returned
+ * @param cd array of @a cd_count records with the results
+ */
+static void
+handle_verify_response (void *cls,
+                        unsigned int d_count,
+                        struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
+                        unsigned int c_count,
+                        struct GNUNET_CREDENTIAL_Credential *cred)
+{
+
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  struct GNUNET_JSONAPI_Document *json_document;
+  struct GNUNET_JSONAPI_Resource *json_resource;
+  json_t *cred_obj;
+  json_t *attr_obj;
+  json_t *cred_array;
+  json_t *attr_array;
+  char *result;
+  char *issuer;
+  char *id;
+  uint32_t i;
+
+  handle->verify_request = NULL;
+  if (NULL == cred) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Verify failed.\n");
+    handle->response_code = MHD_HTTP_NOT_FOUND;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer in delegation malformed\n");
+    return;
+  }
+  GNUNET_asprintf (&id,
+                   "%s.%s",
+                   issuer,
+                   handle->issuer_attr);
+  GNUNET_free (issuer);
+  json_document = GNUNET_JSONAPI_document_new ();
+  json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
+                                               id);
+  GNUNET_free (id);
+  attr_array = json_array ();
+  for (i = 0; i < d_count; i++)
+  {
+    attr_obj = attribute_delegation_to_json (&delegation_chain[i]);
+    json_array_append_new (attr_array, attr_obj);
+  }
+  cred_array = json_array ();
+  for (i=0;i<c_count;i++)
+  {
+    cred_obj = credential_to_json (&cred[i]);
+    json_array_append_new (cred_array, cred_obj);
+  }
+  GNUNET_JSONAPI_resource_add_attr (json_resource,
+                                    GNUNET_REST_JSONAPI_CREDENTIAL,
+                                    cred_array);
+  GNUNET_JSONAPI_resource_add_attr (json_resource,
+                                    GNUNET_REST_JSONAPI_DELEGATIONS,
+                                    attr_array);
+  GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
+  GNUNET_JSONAPI_document_serialize (json_document, &result);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Result %s\n",
+              result);
+  json_decref (attr_array);
+  json_decref (cred_array);
+  GNUNET_JSONAPI_document_delete (json_document);
+  resp = GNUNET_REST_create_response (result);
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  GNUNET_free (result);
+  cleanup_handle (handle);
+}
+
+static void
+collect_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
+                   const char* url,
+                   void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode key;
+  char *tmp;
+  char *entity_attr;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connecting...\n");
+  handle->credential = GNUNET_CREDENTIAL_connect (cfg);
+  handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
+                                                       &do_error, handle);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connected\n");
+  if (NULL == handle->credential)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Connecting to CREDENTIAL failed\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing issuer attribute\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
+                                           &key);
+  entity_attr = GNUNET_strdup (tmp);
+  tmp = strtok(entity_attr, ".");
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed issuer or attribute\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  if (GNUNET_OK != 
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
+                                                  strlen (tmp),
+                                                  &handle->issuer_key))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed issuer key\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  tmp = strtok (NULL, "."); //Issuer attribute
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed attribute\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  handle->issuer_attr = GNUNET_strdup (tmp);
+  GNUNET_free (entity_attr);
+
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing subject\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
+                                           &key);
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed subject\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg,
+                                                   tmp,
+                                                   &subject_ego_lookup,
+                                                   handle);
+}
+
+
+
+static void
+verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
+                  const char* url,
+                  void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode key;
+  struct GNUNET_JSONAPI_Document *json_obj;
+  struct GNUNET_JSONAPI_Resource *res;
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  char *tmp;
+  char *entity_attr;
+  int i;
+  uint32_t credential_count;
+  uint32_t resource_count;
+  json_t *cred_json;
+  json_t *data_js;
+  json_error_t err;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connecting...\n");
+  handle->credential = GNUNET_CREDENTIAL_connect (cfg);
+  handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
+                                                       &do_error, handle);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connected\n");
+  if (NULL == handle->credential)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Connecting to CREDENTIAL failed\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing issuer attribute\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
+                                           &key);
+  entity_attr = GNUNET_strdup (tmp);
+  tmp = strtok(entity_attr, ".");
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed issuer or attribute\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  if (GNUNET_OK != 
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
+                                                  strlen (tmp),
+                                                  &handle->issuer_key))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed issuer key\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  tmp = strtok (NULL, "."); //Issuer attribute
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed attribute\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  handle->issuer_attr = GNUNET_strdup (tmp);
+  GNUNET_free (entity_attr);
+
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing subject key\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map,
+                                           &key);
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed subject\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
+                                                  strlen (tmp),
+                                                  &handle->subject_key)) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed subject key\n");
+    GNUNET_free (entity_attr);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  if (0 >= handle->rest_handle->data_size)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing credentials\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  struct GNUNET_JSON_Specification docspec[] = {
+    GNUNET_JSON_spec_jsonapi_document (&json_obj),
+    GNUNET_JSON_spec_end()
+  };
+  char term_data[handle->rest_handle->data_size+1];
+  term_data[handle->rest_handle->data_size] = '\0';
+  credential_count = 0;
+  GNUNET_memcpy (term_data,
+                 handle->rest_handle->data,
+                 handle->rest_handle->data_size);
+  data_js = json_loads (term_data,
+                        JSON_DECODE_ANY,
+                        &err);
+  GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (data_js, docspec,
+                                                 NULL, NULL));
+  json_decref (data_js);
+  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;
+  }
+
+  resource_count = GNUNET_JSONAPI_document_resource_count(json_obj);
+  GNUNET_assert (1 == resource_count);
+  res = (GNUNET_JSONAPI_document_get_resource(json_obj, 0));
+  if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type(res,
+                                                      GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Resource not a credential!\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unable to parse JSONAPI Object from %s\n",
+                term_data);
+    GNUNET_JSONAPI_document_delete (json_obj);
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  cred_json = GNUNET_JSONAPI_resource_read_attr (res,
+                                                 GNUNET_REST_JSONAPI_CREDENTIAL);
+
+  GNUNET_assert (json_is_array (cred_json));
+
+  credential_count = json_array_size(cred_json);
+
+  struct GNUNET_CREDENTIAL_Credential credentials[credential_count];
+  for (i=0;i<credential_count;i++)
+  {
+    cred = json_to_credential (json_array_get (cred_json, i));
+    if (NULL == cred)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Unable to parse credential!\n");
+      continue;
+    }
+    GNUNET_memcpy (&credentials[i],
+                   cred,
+                   sizeof (struct GNUNET_CREDENTIAL_Credential));
+    credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute);
+    GNUNET_free (cred);
+  }
+  GNUNET_JSONAPI_document_delete(json_obj);
+  handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential,
+                                                     &handle->issuer_key,
+                                                     handle->issuer_attr,
+                                                     &handle->subject_key,
+                                                     credential_count,
+                                                     credentials,
+                                                     &handle_verify_response,
+                                                     handle);
+  for (i=0;i<credential_count;i++)
+    GNUNET_free ((char*)credentials[i].issuer_attribute);
+
+}
+
+void
+send_cred_response (struct RequestHandle *handle,
+                    struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  struct MHD_Response *resp;
+  struct GNUNET_JSONAPI_Document *json_document;
+  struct GNUNET_JSONAPI_Resource *json_resource;
+  json_t *cred_obj;
+  char *result;
+  char *issuer;
+  char *subject;
+  char *signature;
+  char *id;
+
+  GNUNET_assert (NULL != cred);
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject malformed\n");
+    return;
+  }
+  GNUNET_asprintf (&id,
+                   "%s.%s",
+                   issuer,
+                   (char*)&cred[1]);
+  subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
+  if (NULL == subject)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject malformed\n");
+    return;
+  }
+  GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
+                                sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
+                                &signature);
+  json_document = GNUNET_JSONAPI_document_new ();
+  json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO,
+                                               id);
+  GNUNET_free (id);
+  cred_obj = json_object();
+  json_object_set_new (cred_obj, "issuer", json_string (issuer));
+  json_object_set_new (cred_obj, "subject", json_string (subject));
+  json_object_set_new (cred_obj, "expiration", json_integer( cred->expiration.abs_value_us));
+  json_object_set_new (cred_obj, "signature", json_string (signature));
+  GNUNET_JSONAPI_resource_add_attr (json_resource,
+                                    GNUNET_REST_JSONAPI_CREDENTIAL,
+                                    cred_obj);
+  GNUNET_JSONAPI_document_resource_add (json_document, json_resource);
+  GNUNET_JSONAPI_document_serialize (json_document, &result);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Result %s\n",
+              result);
+  json_decref (cred_obj);
+  GNUNET_JSONAPI_document_delete (json_document);
+  resp = GNUNET_REST_create_response (result);
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  GNUNET_free (result);
+  GNUNET_free (signature);
+  GNUNET_free (issuer);
+  GNUNET_free (subject);
+  cleanup_handle (handle);
+}
+
+void
+get_cred_issuer_cb (void *cls,
+                    struct GNUNET_IDENTITY_Ego *ego,
+                    void **ctx,
+                    const char *name)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_TIME_Absolute etime_abs;
+  struct GNUNET_TIME_Relative etime_rel;
+  const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key;
+  struct GNUNET_HashCode key;
+  struct GNUNET_CREDENTIAL_Credential *cred;
+  char* expiration_str;
+  char* tmp;
+
+  handle->id_op = NULL;
+
+  if (NULL == name)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer not configured!\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connecting to credential service...\n");
+  handle->credential = GNUNET_CREDENTIAL_connect (cfg);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Connected\n");
+  if (NULL == handle->credential)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Connecting to CREDENTIAL failed\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing expiration\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  expiration_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
+                                                      &key);
+  if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str,
+                                                          &etime_rel))
+  {
+    etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel);
+  } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str,
+                                                                 &etime_abs))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed expiration: %s\n", expiration_str);
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing issuer attribute\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  handle->issuer_attr = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get 
+                                      (handle->rest_handle->url_param_map,
+                                       &key));
+  GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY,
+                      strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY),
+                      &key);
+  if ( GNUNET_NO ==
+       GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
+                                               &key) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Missing subject\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
+                                           &key);
+  if (NULL == tmp)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed subject\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle); 
+    return;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp,
+                                                  strlen (tmp),
+                                                  &handle->subject_key)) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Malformed subject key\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego);
+  cred = GNUNET_CREDENTIAL_credential_issue (issuer_key,
+                                             &handle->subject_key,
+                                             handle->issuer_attr,
+                                             &etime_abs);
+  if (NULL == cred)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to create credential\n");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  send_cred_response (handle, cred);
+}
+
+
+static void
+issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle,
+                 const char* url,
+                 void *cls)
+{
+  struct RequestHandle *handle = cls;
+
+  handle->identity = GNUNET_IDENTITY_connect (cfg,
+                                              NULL,
+                                              NULL);
+  handle->id_op = GNUNET_IDENTITY_get(handle->identity,
+                                      "credential-issuer",
+                                      &get_cred_issuer_cb,
+                                      handle);
+  handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout,
+                                                       &do_error,
+                                                       handle);
+}
+
+/**
+ * Handle rest request
+ *
+ * @param handle the lookup handle
+ */
+static void
+options_cont (struct GNUNET_REST_RequestHandle *con_handle,
+              const char* url,
+              void *cls)
+{
+  struct MHD_Response *resp;
+  struct RequestHandle *handle = cls;
+
+  //For GNS, independent of path return all options
+  resp = GNUNET_REST_create_response (NULL);
+  MHD_add_response_header (resp,
+                           "Access-Control-Allow-Methods",
+                           MHD_HTTP_METHOD_GET);
+  handle->proc (handle->proc_cls,
+                resp,
+                MHD_HTTP_OK);
+  cleanup_handle (handle);
+}
+
+
+/**
+ * Function processing the REST call
+ *
+ * @param method HTTP method
+ * @param url URL of the HTTP request
+ * @param data body of the HTTP request (optional)
+ * @param data_size length of the body
+ * @param proc callback function for the result
+ * @param proc_cls closure for callback function
+ * @return GNUNET_OK if request accepted
+ */
+static void
+rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
+                                GNUNET_REST_ResultProcessor proc,
+                                void *proc_cls)
+{
+  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+  struct GNUNET_REST_RequestHandlerError err;
+
+  handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  handle->proc_cls = proc_cls;
+  handle->proc = proc;
+  handle->rest_handle = conndata_handle;
+
+  static const struct GNUNET_REST_RequestHandler handlers[] = {
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont},
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_COLLECT, &collect_cred_cont},
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont},
+    {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont},
+    GNUNET_REST_HANDLER_END
+  };
+
+  if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle,
+                                                  handlers,
+                                                  &err,
+                                                  handle))
+  {
+    handle->response_code = err.error_code;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+  }
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_rest_credential_init (void *cls)
+{
+  static struct Plugin plugin;
+  cfg = cls;
+  struct GNUNET_REST_Plugin *api;
+
+  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_CREDENTIAL;
+  api->process_request = &rest_credential_process_request;
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              _("GNS 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_credential_done (void *cls)
+{
+  struct GNUNET_REST_Plugin *api = cls;
+  struct Plugin *plugin = api->cls;
+
+  plugin->cfg = NULL;
+  GNUNET_free (api);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "GNS REST plugin is finished\n");
+  return NULL;
+}
+
+/* end of plugin_rest_gns.c */
diff --git a/src/credential/test_credential_collect.sh b/src/credential/test_credential_collect.sh
new file mode 100755 (executable)
index 0000000..6c71306
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.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"
+TEST_ATTR2="test2"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C testissuer -c test_credential_lookup.conf
+gnunet-identity -C testsubject -c test_credential_lookup.conf
+SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}')
+ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}')
+#TODO1 Get credential and store it with subject (3)
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf`
+$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR2 --ttl=5m -c test_credential_lookup.conf`
+$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c2 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$ISSUER_KEY --attribute=$TEST_ATTR --ego=testsubject -c test_credential_lookup.conf | paste -d, -s`
+echo $CREDS
+RES=$?
+gnunet-arm -e -c test_credential_lookup.conf
+
+if test $? != 0
+then
+  echo "Error collecting..."
+  exit 1
+fi
+
diff --git a/src/credential/test_credential_collect_rest.sh b/src/credential/test_credential_collect_rest.sh
new file mode 100755 (executable)
index 0000000..0b31f85
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f`
+
+#  (1) Service.user -> GNU.project.member
+#  (2) GNU.project -> GNUnet
+#  (3) GNUnet.member -> GNUnet.developer
+#  (4) GNUnet.member -> GNUnet.user
+#  (5) GNUnet.developer -> Alice
+
+
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C service -c test_credential_lookup.conf
+gnunet-identity -C alice -c test_credential_lookup.conf
+gnunet-identity -C gnu -c test_credential_lookup.conf
+gnunet-identity -C gnunet -c test_credential_lookup.conf
+
+GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}')
+ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}')
+GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}')
+SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}')
+
+USER_ATTR="user"
+GNU_PROJECT_ATTR="project"
+MEMBER_ATTR="member"
+DEVELOPER_ATTR="developer"
+DEV_ATTR="developer"
+TEST_CREDENTIAL="mygnunetcreds"
+
+# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU
+gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute
+gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf
+
+# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user"
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (5) GNUnet issues Alice the credential "developer"
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf`
+
+# Alice stores the credential under "mygnunetcreds"
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+
+# (5) GNUnet issues Alice the credential "developer"
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$USER_ATTR --ttl=5m -c test_credential_lookup.conf`
+
+# Alice stores the credential under "mygnunetcreds"
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+
+#TODO2 Add -z swich like in gnunet-gns
+#RES_CRED=`gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY -c test_credential_lookup.conf`
+
+gnunet-arm -i rest -c test_credential_lookup.conf
+
+sleep 5
+
+curl -v "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice"
+
+#TODO cleanup properly
+gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf
+gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf
+echo "Stopping arm..."
+gnunet-arm -e -c test_credential_lookup.conf
+echo "Done"
+if [ "$RES_CRED" != "Failed." ]
+then
+  echo -e "${RES_CRED}"
+  exit 0
+else
+  echo "FAIL: Failed to verify credential $RES_CRED."
+  exit 1
+fi
diff --git a/src/credential/test_credential_defaults.conf b/src/credential/test_credential_defaults.conf
new file mode 100644 (file)
index 0000000..d157ddd
--- /dev/null
@@ -0,0 +1,24 @@
+@INLINE@ ../../contrib/no_forcestart.conf
+
+[PATHS]
+GNUNET_TEST_HOME = /tmp/test-gnunet-credential-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/credential/test_credential_issue.sh b/src/credential/test_credential_issue.sh
new file mode 100755 (executable)
index 0000000..158d91c
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.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_credential_lookup.conf
+gnunet-identity -C testissuer -c test_credential_lookup.conf
+gnunet-identity -C testsubject -c test_credential_lookup.conf
+SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}')
+ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}')
+#TODO1 Get credential and store it with subject (3)
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf`
+STATUS=$?
+
+if test $? != 0
+then
+  echo "Error issuing..."
+  exit 1
+fi
+#Try import
+$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+RES=$?
+gnunet-arm -e -c test_credential_lookup.conf
+exit $RES
diff --git a/src/credential/test_credential_issue_rest.sh b/src/credential/test_credential_issue_rest.sh
new file mode 100755 (executable)
index 0000000..15cd550
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.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_credential_lookup.conf
+gnunet-arm -i gns
+gnunet-arm -i credential
+gnunet-arm -i identity
+gnunet-arm -i rest -c test_credential_lookup.conf
+
+gnunet-arm -I -c test_credential_lookup.conf
+gnunet-identity -C testissuer -c test_credential_lookup.conf
+gnunet-identity -C testsubject -c test_credential_lookup.conf
+gnunet-identity -s credential-issuer -e testissuer
+SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}')
+ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}')
+#TODO1 Get credential and store it with subject (3)
+sleep 5
+curl "localhost:7776/credential/issue?subject_key=$SUBJECT_KEY&attribute=$TEST_ATTR&expiration=1d"
+#CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf`
+STATUS=$?
+
+if test $? != 0
+then
+  echo "Error issuing..."
+  exit 1
+fi
+#Try import
+#$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+RES=$?
+gnunet-arm -e -c test_credential_lookup.conf
+exit $RES
diff --git a/src/credential/test_credential_lookup.conf b/src/credential/test_credential_lookup.conf
new file mode 100644 (file)
index 0000000..3684063
--- /dev/null
@@ -0,0 +1,28 @@
+@INLINE@ test_credential_defaults.conf
+
+[PATHS]
+GNUNET_TEST_HOME = /tmp/test-gnunet-credential-peer-1/
+
+[dht]
+AUTOSTART = YES
+
+[transport]
+PLUGINS =
+
+[credential]
+AUTOSTART = YES
+PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/credlog
+
+[rest]
+PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog
+
+[gns]
+#PREFIX = valgrind --leak-check=full --track-origins=yes
+AUTOSTART = 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
+
diff --git a/src/credential/test_credential_verify.sh b/src/credential/test_credential_verify.sh
new file mode 100755 (executable)
index 0000000..d042bcf
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f`
+
+#  (1) Service.user -> GNU.project.member
+#  (2) GNU.project -> GNUnet
+#  (3) GNUnet.member -> GNUnet.developer
+#  (4) GNUnet.member -> GNUnet.user
+#  (5) GNUnet.developer -> Alice
+
+
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C service -c test_credential_lookup.conf
+gnunet-identity -C alice -c test_credential_lookup.conf
+gnunet-identity -C gnu -c test_credential_lookup.conf
+gnunet-identity -C gnunet -c test_credential_lookup.conf
+
+GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}')
+ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}')
+GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}')
+SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}')
+
+USER_ATTR="user"
+GNU_PROJECT_ATTR="project"
+MEMBER_ATTR="member"
+DEVELOPER_ATTR="developer"
+DEV_ATTR="developer"
+TEST_CREDENTIAL="mygnunetcreds"
+
+# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU
+gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute
+gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf
+
+# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user"
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (5) GNUnet issues Alice the credential "developer"
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf`
+
+# Alice stores the credential under "mygnunetcreds"
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+
+CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --ego=alice -c test_credential_lookup.conf | paste -d, -s`
+
+echo gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=\'$CREDS\' -c test_credential_lookup.conf
+#TODO2 Add -z swich like in gnunet-gns
+gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential="$CREDS" -c test_credential_lookup.conf
+
+
+#TODO cleanup properly
+gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf
+gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-arm -e -c test_credential_lookup.conf
+
+if [ "$RES_CRED" != "Failed." ]
+then
+  echo -e "${RES_CRED}"
+  exit 0
+else
+  echo "FAIL: Failed to verify credential $RES_CRED."
+  exit 1
+fi
diff --git a/src/credential/test_credential_verify_and.sh b/src/credential/test_credential_verify_and.sh
new file mode 100755 (executable)
index 0000000..9d5c196
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f`
+
+#  (1) Service.user -> GNU.project.member
+#  (2) GNU.project -> GNUnet
+#  (3) GNUnet.member -> GNUnet.developer
+#  (4) GNUnet.member -> GNUnet.user
+#  (5) GNUnet.developer -> Alice
+
+
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C service -c test_credential_lookup.conf
+gnunet-identity -C alice -c test_credential_lookup.conf
+gnunet-identity -C gnu -c test_credential_lookup.conf
+gnunet-identity -C gnunet -c test_credential_lookup.conf
+
+GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}')
+ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}')
+GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}')
+SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}')
+
+USER_ATTR="user"
+GNU_PROJECT_ATTR="project"
+MEMBER_ATTR="member"
+DEVELOPER_ATTR="developer"
+DEV_ATTR="developer"
+TEST_CREDENTIAL="mygnunetcreds"
+
+# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU
+gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute
+gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf
+
+# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user"
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR,$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (5) GNUnet issues Alice the credential "developer"
+CRED1=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf`
+# (5) GNUnet issues Alice the credential "user"
+CRED2=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$USER_ATTR --ttl=5m -c test_credential_lookup.conf`
+# Alice stores the credential under "mygnunetcreds"
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED1" -e 5m -c test_credential_lookup.conf
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED2" -e 5m -c test_credential_lookup.conf
+
+CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --ego=alice -c test_credential_lookup.conf | paste -d, -s`
+
+#TODO2 Add -z swich like in gnunet-gns
+RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential="$CREDS" -c test_credential_lookup.conf`
+
+
+#TODO cleanup properly
+gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf
+gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-arm -e -c test_credential_lookup.conf
+
+if [ "$RES_CRED" != "Failed." ]
+then
+  echo -e "${RES_CRED}"
+  exit 0
+else
+  echo "FAIL: Failed to verify credential $RES_CRED."
+  exit 1
+fi
diff --git a/src/credential/test_credential_verify_rest.sh b/src/credential/test_credential_verify_rest.sh
new file mode 100755 (executable)
index 0000000..6133ea2
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f`
+
+#  (1) Service.user -> GNU.project.member
+#  (2) GNU.project -> GNUnet
+#  (3) GNUnet.member -> GNUnet.developer
+#  (4) GNUnet.member -> GNUnet.user
+#  (5) GNUnet.developer -> Alice
+
+
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C service -c test_credential_lookup.conf
+gnunet-identity -C alice -c test_credential_lookup.conf
+gnunet-identity -C gnu -c test_credential_lookup.conf
+gnunet-identity -C gnunet -c test_credential_lookup.conf
+
+GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}')
+ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}')
+GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}')
+SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}')
+
+USER_ATTR="user"
+GNU_PROJECT_ATTR="project"
+MEMBER_ATTR="member"
+DEVELOPER_ATTR="developer"
+DEV_ATTR="developer"
+TEST_CREDENTIAL="mygnunetcreds"
+
+# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU
+gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute
+gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf
+
+# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user"
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf
+gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf
+
+# (5) GNUnet issues Alice the credential "developer"
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf`
+
+# Alice stores the credential under "mygnunetcreds"
+gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+
+#TODO2 Add -z swich like in gnunet-gns
+#RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf`
+
+gnunet-arm -i rest -c test_credential_lookup.conf
+
+sleep 5
+
+CREDS=`curl "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice"`
+
+echo $CREDS
+
+curl -v "localhost:7776/credential/verify?attribute=$SERVICE_KEY.$USER_ATTR&subject_key=$ALICE_KEY" --data "$CREDS"
+
+#TODO cleanup properly
+gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf
+gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf
+gnunet-arm -e -c test_credential_lookup.conf
+
+if [ "$RES_CRED" != "Failed." ]
+then
+  echo -e "${RES_CRED}"
+  exit 0
+else
+  echo "FAIL: Failed to verify credential $RES_CRED."
+  exit 1
+fi
diff --git a/src/credential/test_credential_verify_simple.sh b/src/credential/test_credential_verify_simple.sh
new file mode 100755 (executable)
index 0000000..c4fd8c7
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+trap "gnunet-arm -e -c test_credential_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_credential_lookup.conf -s PATHS -o GNUNET_HOME -f`
+
+#  (3) Isser.user -> Subject
+
+
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C testissuer -c test_credential_lookup.conf
+gnunet-identity -C testsubject -c test_credential_lookup.conf
+
+TEST_ATTR="user"
+SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}')
+ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}')
+CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf`
+
+TEST_CREDENTIAL="t1"
+gnunet-namestore -p -z testsubject -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf
+
+#TODO2 Add -z swich like in gnunet-gns
+#RES_CRED=`$DO_TIMEOUT gnunet-credential --verify --issuer=$ISSUER_KEY --attribute="$TEST_ATTR" --subject=$SUBJECT_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf`
+RES_CRED=`gnunet-credential --verify --issuer=$ISSUER_KEY --attribute=$TEST_ATTR --subject=$SUBJECT_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf`
+
+#TODO cleanup properly
+gnunet-namestore -z testsubject -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf
+gnunet-identity -D testsubject -c test_credential_lookup.conf
+gnunet-arm -e -c test_credential_lookup.conf
+echo $RES_CRED
+#TODO3 proper test
+if [ "$RES_CRED" == "Successful." ]
+then
+  exit 0
+else
+  echo "FAIL: Failed to verify credential."
+  exit 1
+fi
index 7196a18446d121ad43fba3abb0b52b0d1b59928b..d9a5dd6848a0596723a485e4694fa7b629408ff2 100644 (file)
@@ -3802,7 +3802,7 @@ run (void *cls,
     if (GNUNET_YES !=
        GNUNET_OS_check_helper_binary (binary,
                                        GNUNET_YES,
-                                       "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) //no nat, ipv4 only
+                                       "gnunet-vpn - - - 169.1.3.7 255.255.255.0")) //no nat, ipv4 only
     {
       GNUNET_free (binary);
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
index 26293f4df836a161665e3842d8ce8f57e55ca4d1..84c4ae189f3ee760450062b39309285fbfc67be4 100644 (file)
@@ -244,10 +244,7 @@ handle_result (void *cls,
     return;
   proc = lr->lookup_proc;
   proc_cls = lr->proc_cls;
-  GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
-                               handle->lookup_tail,
-                               lr);
-  GNUNET_free (lr);
+  
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_GNSRECORD_records_deserialize (mlen,
                                                        (const char*) &lookup_msg[1],
@@ -256,6 +253,12 @@ handle_result (void *cls,
   proc (proc_cls,
         rd_count,
         rd);
+  GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
+                               handle->lookup_tail,
+                               lr);
+  if (NULL != lr->env)
+    GNUNET_MQ_discard (lr->env);
+  GNUNET_free (lr);
 }
 
 
index 5d611e19e4ddd72afcd4855ae96379a7c11b7e4e..6adad0f3480ab4a24e7442009db1dbd5a757d4d8 100644 (file)
@@ -140,30 +140,6 @@ gns_value_to_string (void *cls,
       GNUNET_free (ival);
       return box_str;
     }
-  case GNUNET_GNSRECORD_TYPE_REVERSE:
-    {
-      struct GNUNET_GNSRECORD_ReverseRecord rev;
-      char *rev_str;
-      char *pkey_str;
-
-      if (data_size < sizeof (struct GNUNET_GNSRECORD_ReverseRecord))
-        return NULL; /* malformed */
-
-      memcpy (&rev,
-              data,
-              sizeof (rev));
-      cdata = data;
-      pkey_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&rev.pkey);
-
-      GNUNET_asprintf (&rev_str,
-                       "%s %s %"SCNu64,
-                       &cdata[sizeof (rev)],
-                       pkey_str,
-                       rev.expiration.abs_value_us);
-      GNUNET_free (pkey_str);
-      return rev_str;
-
-    }
   default:
     return NULL;
   }
@@ -335,48 +311,6 @@ gns_string_to_value (void *cls,
         GNUNET_free (bval);
         return GNUNET_OK;
       }
-    case GNUNET_GNSRECORD_TYPE_REVERSE:
-      {
-        struct GNUNET_GNSRECORD_ReverseRecord *rev;
-        char known_by[253 + 1];
-        struct GNUNET_TIME_Absolute expiration;
-
-        /* TODO: From crypto_ecc.c
-         * Why is this not a constant???
-         */
-        size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
-        if (enclen % 5 > 0)
-          enclen += 5 - enclen % 5;
-        enclen /= 5; /* 260/5 = 52 */
-        char pkey_str[enclen + 1];
-
-        if (3 != SSCANF (s,
-                         "%253s %52s %"SCNu64,
-                         known_by,
-                         pkey_str,
-                         &expiration.abs_value_us))
-        {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      _("Unable to parse REVERSE record string `%s'\n"),
-                      s);
-          return GNUNET_SYSERR;
-        }
-        *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1;
-        *data = rev = GNUNET_malloc (*data_size);
-        if (GNUNET_OK !=
-            GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
-                                                        strlen (pkey_str),
-                                                        &rev->pkey))
-        {
-          GNUNET_free (rev);
-          return GNUNET_SYSERR;
-        }
-        rev->expiration = expiration;
-        GNUNET_memcpy (&rev[1],
-                       known_by,
-                       strlen (known_by));
-        return GNUNET_OK;
-      }
     default:
       return GNUNET_SYSERR;
   }
@@ -397,7 +331,6 @@ static struct {
   { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
   { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
   { "BOX", GNUNET_GNSRECORD_TYPE_BOX },
-  { "REVERSE", GNUNET_GNSRECORD_TYPE_REVERSE },
   { NULL, UINT32_MAX }
 };
 
index 7c2bb9646b87e68f6854414bf060cab005a177bb..cc9692a9a5382006e45930c0dffb1d724b7eecbf 100644 (file)
@@ -39,6 +39,7 @@ gnunet_service_identity_provider_LDADD = \
  $(top_builddir)/src/namestore/libgnunetnamestore.la \
  $(top_builddir)/src/identity/libgnunetidentity.la \
  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/credential/libgnunetcredential.la \
  $(top_builddir)/src/gns/libgnunetgns.la \
  $(GN_LIBINTL) \
  -ljansson
index 53fd02c9ffef54f657dbe73211d3a58064d3bcea..f4ea352d4bd6a48325a561e237b8825a1ffed7f6 100644 (file)
@@ -30,6 +30,7 @@
 #include "gnunet_identity_service.h"
 #include "gnunet_gnsrecord_lib.h"
 #include "gnunet_namestore_service.h"
+#include "gnunet_credential_service.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_gns_service.h"
 #include "gnunet_signatures.h"
@@ -92,6 +93,11 @@ static struct GNUNET_NAMESTORE_Handle *ns_handle;
  */
 static struct GNUNET_GNS_Handle *gns_handle;
 
+/**
+ * Credential handle
+ */
+static struct GNUNET_CREDENTIAL_Handle *credential_handle;
+
 /**
  * Namestore qe
  */
@@ -153,6 +159,23 @@ static struct GNUNET_STATISTICS_Handle *stats;
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
+struct VerifiedAttributeEntry
+{
+  /**
+   * DLL
+   */
+  struct VerifiedAttributeEntry *prev;
+
+  /**
+   * DLL
+   */
+  struct VerifiedAttributeEntry *next;
+
+  /**
+   * Attribute Name
+   */
+  char* name;
+};
 
 struct ExchangeHandle
 {
@@ -226,6 +249,16 @@ struct IssueHandle
    */
   char *scopes;
 
+  /**
+   * DLL
+   */
+  struct VerifiedAttributeEntry *v_attr_head;
+
+  /**
+   * DLL
+   */
+  struct VerifiedAttributeEntry *v_attr_tail;
+
   /**
    * nonce
    */
@@ -236,6 +269,11 @@ struct IssueHandle
    */
   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
 
+  /**
+   * Cred request
+   */
+  struct GNUNET_CREDENTIAL_Request *credential_request;
+
   /**
    * Attribute map
    */
@@ -877,6 +915,8 @@ cleanup()
     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)
@@ -975,6 +1015,10 @@ cleanup_issue_handle (struct IssueHandle *handle)
     ticket_destroy (handle->ticket);
   if (NULL != handle->label)
     GNUNET_free (handle->label);
+  if (NULL != handle->ns_it)
+    GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
+  if (NULL != handle->credential_request)
+    GNUNET_CREDENTIAL_request_cancel (handle->credential_request);
   GNUNET_free (handle);
 }
 
@@ -1115,6 +1159,108 @@ sign_and_return_token (void *cls)
   GNUNET_free (token_metadata);
 }
 
+/**
+ * Credential to JSON
+ * @param cred the credential
+ * @return the resulting json, NULL if failed
+ */
+static json_t*
+credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  char *issuer;
+  char *subject;
+  char *signature;
+  char attribute[cred->issuer_attribute_len + 1];
+  json_t *cred_obj;
+
+  issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
+  if (NULL == issuer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Issuer in credential malformed\n");
+    return NULL;
+  }  
+  subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
+  if (NULL == subject)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Subject in credential malformed\n");
+    GNUNET_free (issuer);
+    return NULL;
+  }
+  GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
+                                sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
+                                &signature);
+  memcpy (attribute,
+          cred->issuer_attribute,
+          cred->issuer_attribute_len);
+  attribute[cred->issuer_attribute_len] = '\0';
+  cred_obj = json_object ();
+  json_object_set_new (cred_obj, "issuer", json_string (issuer));
+  json_object_set_new (cred_obj, "subject", json_string (subject));
+  json_object_set_new (cred_obj, "attribute", json_string (attribute));
+  json_object_set_new (cred_obj, "signature", json_string (signature));
+  json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
+  GNUNET_free (issuer);
+  GNUNET_free (subject);
+  GNUNET_free (signature);
+  return cred_obj;
+}
+
+
+static void
+handle_vattr_collection (void* cls,
+                         unsigned int d_count,
+                         struct GNUNET_CREDENTIAL_Delegation *dc,
+                         unsigned int c_count,
+                         struct GNUNET_CREDENTIAL_Credential *cred)
+{
+  struct IssueHandle *handle = cls;
+  struct VerifiedAttributeEntry *vattr;
+  json_t *cred_json;
+  json_t *cred_array;
+  int i;
+  handle->credential_request = NULL;
+
+  if (NULL == cred)
+  {
+    GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
+    return;
+  }
+  cred_array = json_array();
+  for (i=0;i<c_count;i++)
+  {
+    cred_json = credential_to_json (cred);
+    if (NULL == cred_json)
+      continue;
+    json_array_append (cred_array, cred_json);
+    token_add_attr_json (handle->token,
+                    handle->v_attr_head->name,
+                    cred_array);
+  }
+  json_decref (cred_array);
+  vattr = handle->v_attr_head;
+
+  GNUNET_CONTAINER_DLL_remove (handle->v_attr_head,
+                               handle->v_attr_tail,
+                               vattr);
+  GNUNET_free (vattr->name);
+  GNUNET_free (vattr);
+  
+  if (NULL == handle->v_attr_head)
+  {
+    GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
+    return;
+  }
+  handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
+                                                          &handle->aud_key,
+                                                          handle->v_attr_head->name,
+                                                          &handle->iss_key,
+                                                          &handle_vattr_collection,
+                                                          handle);
+
+}
+
 
 static void
 attr_collect_error (void *cls)
@@ -1134,10 +1280,19 @@ attr_collect_finished (void *cls)
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
   handle->ns_it = NULL;
-  GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
-}
-
 
+  if (NULL == handle->v_attr_head)
+  {
+    GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
+    return;
+  }
+  handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
+                                                          &handle->aud_key,
+                                                          handle->v_attr_head->name,
+                                                          &handle->iss_key,
+                                                          &handle_vattr_collection,
+                                                          handle);
+}
 /**
  * Collect attributes for token
  */
@@ -1333,160 +1488,6 @@ handle_exchange_message (void *cls,
 
 }
 
-
-static void
-find_existing_token_error (void *cls)
-{
-  struct IssueHandle *handle = cls;
-  cleanup_issue_handle (handle);
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n");
-  GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
-}
-
-
-static void
-find_existing_token_finished (void *cls)
-{
-  struct IssueHandle *handle = cls;
-  uint64_t rnd_key;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              ">>> No existing token found\n");
-  rnd_key =
-    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
-                              UINT64_MAX);
-  GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
-                                sizeof (uint64_t),
-                                &handle->label);
-  handle->ns_it = NULL;
-  handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
-                                                         &handle->iss_key,
-                                                         &attr_collect_error,
-                                                         handle,
-                                                         &attr_collect,
-                                                         handle,
-                                                         &attr_collect_finished,
-                                                         handle);
-}
-
-
-/**
- *
- * Look for existing token
- *
- * @param cls the identity entry
- * @param zone the identity
- * @param lbl the name of the record
- * @param rd_count number of records
- * @param rd record data
- *
- */
-static void
-find_existing_token (void *cls,
-                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                     const char *lbl,
-                     unsigned int rd_count,
-                     const struct GNUNET_GNSRECORD_Data *rd)
-{
-  struct IssueHandle *handle = cls;
-  const struct GNUNET_GNSRECORD_Data *token_metadata_record;
-  struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
-  struct GNUNET_HashCode key;
-  int scope_count_token;
-  char *scope;
-  char *tmp_scopes;
-
-  //There should be only a single record for a token under a label
-  if (2 != rd_count)
-  {
-    GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-    return;
-  }
-
-  if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
-  {
-    token_metadata_record = &rd[0];
-  }
-  else
-  {
-    token_metadata_record = &rd[1];
-  }
-  if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
-  {
-    GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-    return;
-  }
-  ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
-  aud_key =
-    (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
-  tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
-  if (0 != memcmp (aud_key, &handle->aud_key,
-                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
-  {
-    char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
-                                                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-    //Audience does not match!
-    char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
-                                                  token_metadata_record->data,
-                                                  token_metadata_record->data_size);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Token does not match audience %s vs %s. Moving on\n",
-                tmp2,
-                tmp);
-    GNUNET_free (tmp_scopes);
-    GNUNET_free (tmp2);
-    GNUNET_free (tmp);
-    GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-    return;
-  }
-
-  scope = strtok (tmp_scopes, ",");
-  scope_count_token = 0;
-  while (NULL != scope)
-  {
-    GNUNET_CRYPTO_hash (scope,
-                        strlen (scope),
-                        &key);
-
-    if ((NULL != handle->attr_map) &&
-        (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Issued token does not include `%s'. Moving on\n", scope);
-      GNUNET_free (tmp_scopes);
-      GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-      return;
-    }
-    scope_count_token++;
-    scope = strtok (NULL, ",");
-  }
-  GNUNET_free (tmp_scopes);
-  //All scopes in token are also in request. Now
-  //Check length
-  if ((NULL != handle->attr_map) &&
-      (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token))
-  {
-    //We have an existing token
-    handle->label = GNUNET_strdup (lbl);
-    handle->ns_it = NULL;
-    handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
-                                                           &handle->iss_key,
-                                                           &attr_collect_error,
-                                                           handle,
-                                                           &attr_collect,
-                                                           handle,
-                                                           &attr_collect_finished,
-                                                           handle);
-
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Nuber of attributes in token do not match request\n");
-  //No luck
-  GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
-}
-
 /**
  * Checks an issue message
  *
@@ -1532,11 +1533,15 @@ handle_issue_message (void *cls,
   const char *scopes;
   char *scopes_tmp;
   char *scope;
+  const char *v_attrs;
+  uint64_t rnd_key;
   struct GNUNET_HashCode key;
   struct IssueHandle *issue_handle;
+  struct VerifiedAttributeEntry *vattr_entry;
   struct GNUNET_SERVICE_Client *client = cls;
 
   scopes = (const char *) &im[1];
+  v_attrs = (const char *) &im[1] + ntohl(im->scope_len);
   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
                                                                  GNUNET_NO);
@@ -1553,6 +1558,20 @@ handle_issue_message (void *cls,
                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
   }
   GNUNET_free (scopes_tmp);
+  scopes_tmp = GNUNET_strdup (v_attrs);
+
+  for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
+  {
+    vattr_entry = GNUNET_new (struct VerifiedAttributeEntry);
+    vattr_entry->name = GNUNET_strdup (scope);
+    GNUNET_CONTAINER_DLL_insert (issue_handle->v_attr_head,
+                                 issue_handle->v_attr_tail,
+                                 vattr_entry);
+  }
+  GNUNET_free (scopes_tmp);
+
+
+
   issue_handle->r_id = im->id;
   issue_handle->aud_key = im->aud_key;
   issue_handle->iss_key = im->iss_key;
@@ -1565,14 +1584,20 @@ handle_issue_message (void *cls,
   issue_handle->scopes = GNUNET_strdup (scopes);
   issue_handle->token = token_create (&issue_handle->iss_pkey,
                                       &issue_handle->aud_key);
+  rnd_key =
+    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
+                              UINT64_MAX);
+  GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
+                                sizeof (uint64_t),
+                                &issue_handle->label);
 
   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
-                                                               &im->iss_key,
-                                                               &find_existing_token_error,
+                                                               &issue_handle->iss_key,
+                                                               &attr_collect_error,
                                                                issue_handle,
-                                                               &find_existing_token,
+                                                               &attr_collect,
                                                                issue_handle,
-                                                               &find_existing_token_finished,
+                                                               &attr_collect_finished,
                                                                issue_handle);
 }
 
@@ -1606,7 +1631,11 @@ run (void *cls,
   {
     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,
                                              &list_ego,
                                              NULL);
index 6fe6102c857caf7766859f95ac0986337741c8f5..9d2675c35af020a28f371550a6b9bff3c82f731e 100644 (file)
@@ -133,6 +133,11 @@ struct IssueMessage
    */
   uint64_t nonce;
 
+  /**
+   * Length of scopes
+   */
+  uint64_t scope_len;
+
   /**
    * Expiration of token in NBO.
    */
index 845d1f7534d2c476722bf32bbc62a1b0b1a679b5..9a330433473a37bbbd82c7b52ccf10dd960b470b 100644 (file)
@@ -223,12 +223,12 @@ check_exchange_result (void *cls,
               const struct ExchangeResultMessage *erm)
 {
   char *str;
-  size_t size = ntohs (erm->header.size) - sizeof (*erm);
+  size_t size = ntohs (erm->header.size);
   
 
-  str = (char *) &erm[1];
+  str = (char *) &erm[0];
   if ( (size > sizeof (struct ExchangeResultMessage)) &&
-       ('\0' != str[size - sizeof (struct ExchangeResultMessage) - 1]) )
+       ('\0' != str[size - 1]) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -248,10 +248,10 @@ check_result (void *cls,
               const struct IssueResultMessage *irm)
 {
   char *str;
-  size_t size = ntohs (irm->header.size) - sizeof (*irm);
-  str = (char*) &irm[1];
+  size_t size = ntohs (irm->header.size);
+  str = (char*) &irm[0];
   if ( (size > sizeof (struct IssueResultMessage)) &&
-       ('\0' != str[size - sizeof (struct IssueResultMessage) - 1]) )
+       ('\0' != str[size - 1]) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -430,6 +430,7 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
                                       const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss_key,
                                       const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
                                       const char* scopes,
+                                      const char* vattr,
                                       struct GNUNET_TIME_Absolute expiration,
                                       uint64_t nonce,
                                       GNUNET_IDENTITY_PROVIDER_IssueCallback cb,
@@ -440,6 +441,8 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
   size_t slen;
 
   slen = strlen (scopes) + 1;
+  if (NULL != vattr)
+    slen += strlen (vattr) + 1;
   if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage))
   {
     GNUNET_break (0);
@@ -456,9 +459,12 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
   im->id = op->r_id;
   im->iss_key = *iss_key;
   im->aud_key = *aud_key;
+  im->scope_len = htonl (strlen(scopes)+1);
   im->nonce = htonl (nonce);
   im->expiration = GNUNET_TIME_absolute_hton (expiration);
-  GNUNET_memcpy (&im[1], scopes, slen);
+  GNUNET_memcpy (&im[1], scopes, strlen(scopes));
+  if (NULL != vattr)
+    GNUNET_memcpy ((char*)&im[1]+strlen(scopes)+1, vattr, strlen(vattr));
   GNUNET_CONTAINER_DLL_insert_tail (id->op_head,
                                     id->op_tail,
                                     op);
index 31249840b0ff989ac4b5375601549336adf9b4fe..6794e373c0df80f771f99340875c4d0d46f0cefe 100644 (file)
@@ -256,6 +256,38 @@ token_destroy (struct IdentityToken *token)
   GNUNET_free (token);
 }
 
+void
+token_add_attr_json (struct IdentityToken *token,
+                     const char* key,
+                     json_t* value)
+{
+  struct TokenAttr *attr;
+  struct TokenAttrValue *new_val;
+  GNUNET_assert (NULL != token);
+
+  new_val = GNUNET_malloc (sizeof (struct TokenAttrValue));
+  new_val->json_value = value;
+  json_incref(value);
+  for (attr = token->attr_head; NULL != attr; attr = attr->next)
+  {
+    if (0 == strcmp (key, attr->name))
+      break;
+  }
+
+  if (NULL == attr)
+  {
+    attr = GNUNET_malloc (sizeof (struct TokenAttr));
+    attr->name = GNUNET_strdup (key);
+    GNUNET_CONTAINER_DLL_insert (token->attr_head,
+                                 token->attr_tail,
+                                 attr);
+  }
+
+  GNUNET_CONTAINER_DLL_insert (attr->val_head,
+                               attr->val_tail,
+                               new_val);
+}
+
 void
 token_add_attr (struct IdentityToken *token,
                 const char* key,
@@ -345,17 +377,23 @@ parse_json_payload(const char* payload_base64,
         if (json_is_integer (arr_value))
           token_add_attr_int (token, key,
                               json_integer_value (arr_value));
-        else
+        else if (json_is_string (arr_value))
           token_add_attr (token,
                           key,
                           json_string_value (arr_value));
+        else
+          token_add_attr_json (token,
+                               key,
+                               (json_t*)arr_value);
       }
     } else {
       if (json_is_integer (value))
         token_add_attr_int (token, key,
                             json_integer_value (value));
-      else
+      else if (json_is_string (value))
         token_add_attr (token, key, json_string_value (value));
+      else
+        token_add_attr_json (token, key, (json_t*)value);
     }
   }
 
@@ -424,7 +462,7 @@ token_parse (const char* raw_data,
   GNUNET_asprintf (&tmp_buf, "%s", raw_data);
   ecdh_pubkey_str = strtok (tmp_buf, ",");
   enc_token_str = strtok (NULL, ",");
-  
+
   GNUNET_assert (NULL != ecdh_pubkey_str);
   GNUNET_assert (NULL != enc_token_str);
 
@@ -476,7 +514,11 @@ create_json_payload (const struct IdentityToken *token)
         json_object_set_new (root,
                              attr->name,
                              json_string (val->value)); 
-      } else {
+      } else if (NULL != val->json_value) {
+        json_object_set (root,
+                         attr->name,
+                         val->json_value);
+      }else {
         json_object_set_new (root,
                              attr->name,
                              json_integer (val->int_value));
@@ -715,8 +757,8 @@ ticket_serialize (struct TokenTicket *ticket,
   purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET);
   write_ptr = (char*) &purpose[1];
   GNUNET_memcpy (write_ptr,
-          &ticket->ecdh_pubkey,
-          sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
+                 &ticket->ecdh_pubkey,
+                 sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey);
   GNUNET_memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str));
   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key,
@@ -825,7 +867,7 @@ ticket_payload_parse(const char *raw_data,
 
   nonce_str = json_string_value (nonce_json);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found nonce: %s\n", nonce_str);
-  
+
   GNUNET_assert (0 != sscanf (nonce_str, "%"SCNu64, &nonce));
 
   *result = ticket_payload_create (nonce,
index 7ded6662ee99f615137463e71fd59de4af29c388..5988bc6685a10ce58ef5c53de9e26c2a1bc81936 100644 (file)
@@ -103,6 +103,11 @@ struct TokenAttrValue
    * used if NULL == value
    */
   uint64_t int_value;
+
+  /**
+   * Json value
+   */
+  json_t *json_value;
 };
 
 struct TokenTicketPayload
@@ -213,10 +218,10 @@ token_add_attr_int (struct IdentityToken *token,
  * @param value the value
  *
  */
-  void
-  token_add_json (const struct IdentityToken *token,
-                  const char* key,
-                  json_t* value);
+void
+token_add_attr_json (struct IdentityToken *token,
+                     const char* key,
+                     json_t* value);
 
 /**
  * Serialize a token. The token will be signed and base64 according to the
@@ -234,11 +239,11 @@ token_add_attr_int (struct IdentityToken *token,
  *
  * @return GNUNET_OK on success
  */
-  int 
-  token_serialize (const struct IdentityToken*token,
-                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
-                   struct GNUNET_CRYPTO_EcdhePrivateKey **ecdhe_privkey,
-                   char **result);
+int 
+token_serialize (const struct IdentityToken*token,
+                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+                 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdhe_privkey,
+                 char **result);
 
 /**
  * Parses the serialized token and returns a token
@@ -249,10 +254,10 @@ token_add_attr_int (struct IdentityToken *token,
  *
  * @return GNUNET_OK on success
  */
-               int
-               token_parse (const char* data,
-                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
-                            struct IdentityToken **result);
+int
+token_parse (const char* data,
+             const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+             struct IdentityToken **result);
 
 /**
  * Parses the serialized token and returns a token
@@ -283,10 +288,10 @@ token_parse2 (const char* data,
  *
  * @return GNUNET_OK on success
  */
-  int
-  token_to_string (const struct IdentityToken *token,
-                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
-                   char **result);
+int
+token_to_string (const struct IdentityToken *token,
+                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+                 char **result);
 
 /**
  *
@@ -316,10 +321,10 @@ ticket_create (uint64_t nonce,
  *
  * @return GNUNET_OK on success
  */
-  int
-  ticket_serialize (struct TokenTicket *ticket,
-                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
-                    char **result);
+int
+ticket_serialize (struct TokenTicket *ticket,
+                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key,
+                  char **result);
 
 /**
  * Destroys a ticket
index 907b28ba9e3d2585eb19adbef4f1924aabe18efe..dfb935f5babc2e8b13bb90204300b03a5571f051 100644 (file)
  */
 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
 
+/**
+ * Attributes passed to issue request
+ */
+#define GNUNET_IDENTITY_TOKEN_V_ATTR_LIST "requested_verified_attrs"
+
+
 /**
  * Token expiration string
  */
@@ -396,6 +402,8 @@ token_creat_cont (void *cls,
   char *ticket_str;
   char *token_str;
   char *result_str;
+  
+  handle->idp_op = NULL;
 
   if (NULL == ticket)
   {
@@ -460,6 +468,7 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
   char *exp_str;
   char *nonce_str;
   char *scopes;
+  char *vattrs;
   uint64_t time;
   uint64_t nonce;
 
@@ -536,6 +545,21 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
   scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
                                               &key);
 
+  //vattrs
+  GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_V_ATTR_LIST,
+                      strlen (GNUNET_IDENTITY_TOKEN_V_ATTR_LIST),
+                      &key);
+
+  vattrs = NULL;
+  if ( GNUNET_YES ==
+       GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
+                                               &key) )
+  {
+    vattrs = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
+                                                &key);
+  }
+
+
 
   //Token audience
   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
@@ -547,15 +571,15 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
                                                &key) )
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Audience missing!\n");
+                "Audience missing!\n");
     GNUNET_SCHEDULER_add_now (&do_error, handle);
     return;
   }
   audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
                                                 &key);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Audience to issue token for: %s\n",
-             audience);
+              "Audience to issue token for: %s\n",
+              audience);
 
   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
@@ -582,8 +606,8 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
                                                  &key);
   GNUNET_assert (NULL != nonce_str);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Request nonce: %s\n",
-             nonce_str);
+              "Request nonce: %s\n",
+              nonce_str);
   GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &nonce));
 
   //Get expiration for token from URL parameter
@@ -620,6 +644,7 @@ issue_token_cont (struct GNUNET_REST_RequestHandle *con,
                                                          priv_key,
                                                          &aud_key,
                                                          scopes,
+                                                         vattrs,
                                                          exp_time,
                                                          nonce,
                                                          &token_creat_cont,
@@ -740,16 +765,16 @@ token_collect (void *cls,
                                                rd[i].data_size);
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
       json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
-                                                        label);
+                                                   label);
       issuer = json_string (handle->ego_head->identifier);
       GNUNET_JSONAPI_resource_add_attr (json_resource,
-                                             GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
-                                             issuer);
+                                        GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
+                                        issuer);
       json_decref (issuer);
       token = json_string (data);
       GNUNET_JSONAPI_resource_add_attr (json_resource,
-                                             GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
-                                             token);
+                                        GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
+                                        token);
       json_decref (token);
 
       GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
@@ -867,7 +892,7 @@ exchange_cont (void *cls,
     return;
   }
   nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
-                                                  &key);
+                                                 &key);
   GNUNET_assert (NULL != nonce_str);
   GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce));
 
index e64b2685a220dc19350f24393607fdaa1310bbc4..5f34d0f1bff3a962c865d5463f8cab195c934aa6 100644 (file)
@@ -427,9 +427,6 @@ ego_info_response (struct GNUNET_REST_RequestHandle *con,
       continue;
     json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO,
                                                       ego_entry->keystring);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Egoname: %s\n",
-                ego_entry->identifier);
     name_str = json_string (ego_entry->identifier);
     GNUNET_JSONAPI_resource_add_attr (
                                            json_resource,
index 9e765c12b22f5bb9fdfd37518c6c366383e2a7c5..67c2f2b4c64ac838fa3e893065e4df981f6ff110 100644 (file)
@@ -20,6 +20,7 @@
 
 /**
  * @author Martin Schanzenbach
+ * @author Adnan Husain
  *
  * @file
  * API to the Credential service
@@ -34,6 +35,7 @@
 
 #include "gnunet_util_lib.h"
 #include "gnunet_gns_service.h"
+#include "gnunet_identity_service.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -52,7 +54,157 @@ struct GNUNET_CREDENTIAL_Handle;
 /**
  * Handle to control a lookup operation.
  */
-struct GNUNET_CREDENTIAL_LookupRequest;
+struct GNUNET_CREDENTIAL_Request;
+
+/*
+* Enum used for checking whether the issuer has the authority to issue credentials or is just a subject
+*/
+enum GNUNET_CREDENTIAL_CredentialFlags {
+
+  //Subject had credentials before, but have been revoked now
+  GNUNET_CREDENTIAL_FLAG_REVOKED=0,
+
+  //Subject flag indicates that the subject is a holder of this credential and may present it as such
+  GNUNET_CREDENTIAL_FLAG_SUBJECT=1,
+
+  //Issuer flag is used to signify that the subject is allowed to issue this credential and delegate issuance
+  GNUNET_CREDENTIAL_FLAG_ISSUER=2
+
+};
+
+GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * The attribute delegation record
+ */
+struct GNUNET_CREDENTIAL_DelegationRecord {
+
+  /**
+   * Number of delegation sets in this record
+   */
+  uint32_t set_count;
+
+  /**
+   * Length of delegation sets
+   */
+  uint64_t data_size;
+  /**
+   * Followed by set_count DelegationSetRecords
+   *
+   */
+};
+
+/**
+ * The attribute delegation record
+ */
+struct GNUNET_CREDENTIAL_DelegationRecordSet {
+
+  /**
+   * Public key of the subject this attribute was delegated to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Length of attribute, may be 0
+   */
+  uint32_t subject_attribute_len;
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * The attribute delegation record
+ */
+struct GNUNET_CREDENTIAL_DelegationSet {
+
+  /**
+   * Public key of the subject this attribute was delegated to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  uint32_t subject_attribute_len;
+
+  /**
+   * The subject attribute
+   */
+  const char *subject_attribute;
+};
+
+
+/**
+ * A delegation
+ */
+struct GNUNET_CREDENTIAL_Delegation {
+
+  /**
+   * The issuer of the delegation
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Public key of the subject this attribute was delegated to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Length of the attribute
+   */
+  uint32_t issuer_attribute_len;
+
+  /**
+   * The attribute
+   */
+  const char *issuer_attribute;
+
+  /**
+   * Length of the attribute
+   */
+  uint32_t subject_attribute_len;
+
+  /**
+   * The attribute
+   */
+  const char *subject_attribute;
+};
+
+
+/**
+ * A credential
+ */
+struct GNUNET_CREDENTIAL_Credential {
+
+  /**
+   * The issuer of the credential
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Public key of the subject this credential was issued to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Signature of this credential
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature signature;
+
+  /**
+   * Expiration of this credential
+   */
+  struct GNUNET_TIME_Absolute expiration;
+
+  /**
+   * Length of the attribute
+   */
+  uint32_t issuer_attribute_len;
+
+  /**
+   * The attribute
+   */
+  const char *issuer_attribute;
+
+};
+
 
 
 /**
@@ -61,7 +213,7 @@ struct GNUNET_CREDENTIAL_LookupRequest;
  * @param cfg configuration to use
  * @return handle to the Credential service, or NULL on error
  */
-struct GNUNET_Credential_Handle *
+struct GNUNET_CREDENTIAL_Handle *
 GNUNET_CREDENTIAL_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
@@ -75,56 +227,129 @@ GNUNET_CREDENTIAL_disconnect (struct GNUNET_CREDENTIAL_Handle *handle);
 
 
 /**
- * Iterator called on obtained result for a Credential lookup.
+ * Iterator called on obtained result for an attribute verification.
  *
  * @param cls closure
- * @param issuer the issuer chain
- * @param issuer_len length of issuer chain
- * @param value the value returned
+ * @param d_count the number of delegations processed
+ * @param delegation_chain the delegations processed
+ * @param c_count the number of credentials found
+ * @param credential the credentials
  */
-typedef void
-(*GNUNET_CREDENTIAL_LookupResultProcessor) (void *cls,
-                                            struct GNUNET_IDENTITY_Ego *issuer,
-                                            uint16_t issuer_len,
-                                            const struct GNUNET_CREDENTIAL_Value *value);
+typedef void (*GNUNET_CREDENTIAL_CredentialResultProcessor) (void *cls,
+                                                         unsigned int d_count,
+                                                         struct GNUNET_CREDENTIAL_Delegation *delegation_chain,
+                                                         unsigned int c_count,
+                                                         struct GNUNET_CREDENTIAL_Credential *credential);
 
+/**
+ * Iterator called on obtained result for an attribute delegation.
+ *
+ * @param cls closure
+ * @param success GNUNET_YES if successful
+ * @param result the record data that can be handed to the subject
+ */
+typedef void (*GNUNET_CREDENTIAL_DelegateResultProcessor) (void *cls,
+                                                           uint32_t success);
 
 /**
- * Perform an asynchronous lookup operation for a credential.
+ * Iterator called on obtained result for an attribute delegation removal.
+ *
+ * @param cls closure
+ * @param success GNUNET_YES if successful
+ * @param result the record data that can be handed to the subject
+ */
+typedef void (*GNUNET_CREDENTIAL_RemoveDelegateResultProcessor) (void *cls,
+                                                                 uint32_t success);
+
+
+/**
+ * Performs attribute verification.
+ * Checks if there is a delegation chain from
+ * attribute ``issuer_attribute'' issued by the issuer
+ * with public key ``issuer_key'' maps to the attribute
+ * ``subject_attribute'' claimed by the subject with key
+ * ``subject_key''
  *
  * @param handle handle to the Credential service
- * @param credential the credential to look up
- * @param subject Ego to check the credential for
+ * @param issuer_key the issuer public key
+ * @param issuer_attribute the issuer attribute
+ * @param subject_key the subject public key
+ * @param subject_attribute the attribute claimed by the subject
  * @param proc function to call on result
  * @param proc_cls closure for processor
  * @return handle to the queued request
  */
-struct GNUNET_CREDENTIAL_LookupRequest *
-GNUNET_CREDENTIAL_lookup (struct GNUNET_CREDENTIAL_Handle *handle,
-                          const char *credential,
-                          const struct GNUNET_IDENTITY_Ego *subject,
-                          GNUNET_CREDENTIAL_LookupResultProcessor proc,
+struct GNUNET_CREDENTIAL_Request*
+GNUNET_CREDENTIAL_verify (struct GNUNET_CREDENTIAL_Handle *handle,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
+                          const char *issuer_attribute,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *subject_key,
+                          uint32_t credential_count,
+                          const struct GNUNET_CREDENTIAL_Credential *credentials,
+                          GNUNET_CREDENTIAL_CredentialResultProcessor proc,
                           void *proc_cls);
 
+struct GNUNET_CREDENTIAL_Request*
+GNUNET_CREDENTIAL_collect (struct GNUNET_CREDENTIAL_Handle *handle,
+                           const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key,
+                           const char *issuer_attribute,
+                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *subject_key,
+                           GNUNET_CREDENTIAL_CredentialResultProcessor proc,
+                           void *proc_cls);
 
 /**
- * Issue a credential to an identity
+ * Delegate an attribute
  *
  * @param handle handle to the Credential service
- * @param issuer the identity that issues the credential
- * @param subject the subject of the credential
- * @param credential the name of the credential
- * @param value the value of the credential
+ * @param issuer the ego that should be used to delegate the attribute
+ * @param attribute the name of the attribute to delegate
+ * @param subject the subject of the delegation
+ * @param delegated_attribute the name of the attribute that is delegated to
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Request *
+GNUNET_CREDENTIAL_add_delegation (struct GNUNET_CREDENTIAL_Handle *handle,
+                                  struct GNUNET_IDENTITY_Ego *issuer,
+                                  const char *attribute,
+                                  struct GNUNET_CRYPTO_EcdsaPublicKey *subject,
+                                  const char *delegated_attribute,
+                                  GNUNET_CREDENTIAL_DelegateResultProcessor proc,
+                                  void *proc_cls);
+
+/**
+ * Remove a delegation
+ *
+ * @param handle handle to the Credential service
+ * @param issuer the ego that was used to delegate the attribute
+ * @param attribute the name of the attribute that is delegated
  * @return handle to the queued request
  */
-struct GNUNET_CREDENTIAL_IssueRequest *
-GNUNET_CREDENTIAL_issue (struct GNUNET_CREDENTIAL_Handle *handle,
-                         struct GNUNET_IDENTITY_Ego *issuer,
-                         struct GNUNET_IDENTITY_Ego *subject,
-                         const char *credential,
-                         struct GNUNET_CREDENTIAL_Value *value,
-                         GNUNET_CREDENTIAL_IssueResultProcessor proc,
-                         void *proc_cls);
+struct GNUNET_CREDENTIAL_Request *
+GNUNET_CREDENTIAL_remove_delegation (struct GNUNET_CREDENTIAL_Handle *handle,
+                                     struct GNUNET_IDENTITY_Ego *issuer,
+                                     const char *attribute,
+                                     GNUNET_CREDENTIAL_RemoveDelegateResultProcessor proc,
+                                     void *proc_cls);
+
+
+
+/**
+ * Issue an attribute to a subject
+ *
+ * @param handle handle to the Credential service
+ * @param issuer the ego that should be used to issue the attribute
+ * @param subject the subject of the attribute
+ * @param attribute the name of the attribute
+ * @param expiration the TTL of the credential
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Credential*
+GNUNET_CREDENTIAL_credential_issue (
+                                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
+                                    struct GNUNET_CRYPTO_EcdsaPublicKey *subject,
+                                    const char *attribute,
+                                    struct GNUNET_TIME_Absolute *expiration);
+
 
 /**
  * Remove a credential
@@ -135,14 +360,15 @@ GNUNET_CREDENTIAL_issue (struct GNUNET_CREDENTIAL_Handle *handle,
  * @param credential the name of the credential
  * @return handle to the queued request
  */
-struct GNUNET_CREDENTIAL_IssueRequest *
-GNUNET_CREDENTIAL_remove (struct GNUNET_CREDENTIAL_Handle *handle,
-                          struct GNUNET_IDENTITY_Ego *issuer,
-                          struct GNUNET_IDENTITY_Ego *subject,
-                          const char *credential,
-                          GNUNET_CREDENTIAL_IssueResultProcessor proc,
-                          void *proc_cls);
-
+/**
+  struct GNUNET_CREDENTIAL_IssueRequest *
+  GNUNET_CREDENTIAL_remove (struct GNUNET_CREDENTIAL_Handle *handle,
+  struct GNUNET_IDENTITY_Ego *issuer,
+  struct GNUNET_IDENTITY_Ego *subject,
+  const char *credential,
+  GNUNET_CREDENTIAL_IssueResultProcessor proc,
+  void *proc_cls);
+  */
 
 
 /**
@@ -151,7 +377,7 @@ GNUNET_CREDENTIAL_remove (struct GNUNET_CREDENTIAL_Handle *handle,
  * @param lr the lookup request to cancel
  */
 void
-GNUNET_CREDENTIAL_lookup_cancel (struct GNUNET_CREDENTIAL_LookupRequest *lr);
+GNUNET_CREDENTIAL_request_cancel (struct GNUNET_CREDENTIAL_Request *vr);
 
 
 #if 0                           /* keep Emacsens' auto-indent happy */
index 985ae1f7ab0d5489d6ffbc3b00644787bf119990..e33d52819137b413694fd718828acb25bc4f4ee9 100644 (file)
@@ -108,10 +108,21 @@ extern "C"
  */
 #define GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA 65546
 
+/**
+ * Record type for credential
+ */
+#define GNUNET_GNSRECORD_TYPE_CREDENTIAL 65547
+
+/**
+ * Record type for policies
+ */
+#define GNUNET_GNSRECORD_TYPE_POLICY 65548
+
 /**
  * Record type for reverse lookups
  */
-#define GNUNET_GNSRECORD_TYPE_REVERSE 65548
+#define GNUNET_GNSRECORD_TYPE_ATTRIBUTE 65549
+
 
 /**
  * Flags that can be set for a record.
index e533f6f8cffea8aae9417883e8354cd7b5f438f3..ba727eb9261ae267e35e22f9bdd7509101ef231e 100644 (file)
@@ -126,6 +126,7 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss_key,
          const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
          const char* scope,
+         const char* vattr,
          struct GNUNET_TIME_Absolute expiration,
          uint64_t nonce,
                     GNUNET_IDENTITY_PROVIDER_IssueCallback cb,
index 72054913f74eaebb7e54b81263a9bad2ad6c0015..455a8292b0de80db1eec8ffede0b848d89f0aeec 100644 (file)
@@ -2628,6 +2628,19 @@ extern "C"
 
 #define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT  964
 
+
+/**************************************************
+ *
+ * CREDENTIAL MESSAGE TYPES
+ */
+#define GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY     971
+
+#define GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT 972
+
+#define GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT 973
+
+#define GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT_RESULT 974
+
 /******************************************************************************/
 
 
index c1e0d005c23538efdd60fc50848b35bde76b4f08..03bc4575ed52f1e7c7698430b683e929415f8e0e 100644 (file)
@@ -185,6 +185,11 @@ extern "C"
  */
 #define GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET 27
 
+/**
+ * Signature for a GNUnet credential
+ */
+#define GNUNET_SIGNATURE_PURPOSE_CREDENTIAL 28
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
index 600b7ee6aa46a1684ca4b679b8f7d159e6066db9..3a60940f6e22d3ff96f57f88711302ed6c6f1dbc 100644 (file)
@@ -332,28 +332,20 @@ GNUNET_JSONAPI_document_to_json (const struct GNUNET_JSONAPI_Document *doc,
                          GNUNET_JSONAPI_KEY_ERRORS,
                          res_json);
   } else {
-    switch (doc->res_count)
+    if (0 == doc->res_count)
     {
-      case 0:
-        res_json = json_null();
-        break;
-      case 1:
+      res_json = json_null();
+    } else {
+      res_json = json_array ();
+      for (res = doc->res_list_head;
+           res != NULL;
+           res = res->next)
+      {
         GNUNET_assert (GNUNET_OK ==
-                       GNUNET_JSONAPI_resource_to_json (doc->res_list_head,
-                                                        &res_json));
-        break;
-      default:
-        res_json = json_array ();
-        for (res = doc->res_list_head;
-             res != NULL;
-             res = res->next)
-        {
-          GNUNET_assert (GNUNET_OK ==
-                         GNUNET_JSONAPI_resource_to_json (res,
-                                                          &res_json_tmp));
-          json_array_append (res_json, res_json_tmp);
-        }
-        break;
+                       GNUNET_JSONAPI_resource_to_json (res,
+                                                        &res_json_tmp));
+        json_array_append_new (res_json, res_json_tmp);
+      }
     }
     json_object_set_new (*root_json,
                          GNUNET_JSONAPI_KEY_DATA,
index 85bca10eeb860ac167a7046f25721ccfab740d33..4a166f58a411f67501076568ddb3503031a924ca 100644 (file)
@@ -92,9 +92,9 @@ GNUNET_JSONAPI_resource_new (const char *type, const char *id)
 {
   struct GNUNET_JSONAPI_Resource *res;
 
-  if ( (NULL == type) || (0 == strlen (type)) )
+  if (NULL == type)
     return NULL;
-  if ( (NULL == id) || (0 == strlen (id)) )
+  if (NULL == id)
     return NULL;
 
   res = GNUNET_new (struct GNUNET_JSONAPI_Resource);
index 50957a5b402229a429421c40546fd4dce3754ae7..05776801beb10192eac7dfd4f4a7151019290092 100644 (file)
@@ -401,11 +401,16 @@ namestore_list_finished (void *cls)
   struct MHD_Response *resp;
 
   handle->list_it = NULL;
+  if (NULL == handle->resp_object)
+    handle->resp_object = GNUNET_JSONAPI_document_new ();
+
   if (GNUNET_SYSERR ==
       GNUNET_JSONAPI_document_serialize (handle->resp_object,
                                          &result))
   {
-    do_error (handle);
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error,
+                              handle);
     return;
   }
   resp = GNUNET_REST_create_response (result);
@@ -467,10 +472,10 @@ namestore_list_response (void *cls,
   if (0 < json_array_size(result_array))
   {
     json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_NAMESTORE_TYPEINFO,
-                                                      rname);
+                                                 rname);
     GNUNET_JSONAPI_resource_add_attr (json_resource,
-                                           GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
-                                           result_array);
+                                      GNUNET_REST_JSONAPI_NAMESTORE_RECORD,
+                                      result_array);
     GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
   }
 
@@ -767,8 +772,8 @@ namestore_create_cont (struct GNUNET_REST_RequestHandle *con,
   }
   term_data[handle->rest_handle->data_size] = '\0';
   GNUNET_memcpy (term_data,
-          handle->rest_handle->data,
-          handle->rest_handle->data_size);
+                 handle->rest_handle->data,
+                 handle->rest_handle->data_size);
   data_js = json_loads (term_data,
                         JSON_DECODE_ANY,
                         &err);
@@ -902,7 +907,7 @@ namestore_zkey_cont (struct GNUNET_REST_RequestHandle *con,
   if ((NULL == handle->zkey_str) ||
       (GNUNET_OK !=
        GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->zkey_str,
-                                                  strlen (handle->zkey_str),
+                                                   strlen (handle->zkey_str),
                                                    &pubkey)))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1021,13 +1026,13 @@ identity_cb (void *cls,
 
   if (GNUNET_OK !=
       GNUNET_JSONAPI_handle_request (handle->rest_handle,
-                                    handlers,
-                                    &err,
-                                    handle))
+                                     handlers,
+                                     &err,
+                                     handle))
   {
     handle->response_code = err.error_code;
     GNUNET_SCHEDULER_add_now (&do_error,
-                             (void *) handle);
+                              (void *) handle);
   }
 }