Merge remote-tracking branch 'origin/master' into credentials
authorSchanzenbach, Martin <mschanzenbach@posteo.de>
Thu, 1 Dec 2016 16:05:29 +0000 (17:05 +0100)
committerSchanzenbach, Martin <mschanzenbach@posteo.de>
Thu, 1 Dec 2016 16:05:29 +0000 (17:05 +0100)
13 files changed:
configure.ac
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/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/test_credential_lookup.sh [new file with mode: 0755]
src/include/gnunet_credential_service.h
src/include/gnunet_gnsrecord_lib.h
src/include/gnunet_protocols.h

index ebe5753aaaf838faae9f68e149a8e71ec709d4e3..38b3660b1fdaa6697644abbb15a1113a778c7ab7 100644 (file)
@@ -1581,6 +1581,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 98ca70ae3254aaac9fbf570cdc26c06ac3a59e1f..2877cab0b8e7168c05de1c243b145be134462b19 100644 (file)
@@ -109,6 +109,7 @@ SUBDIRS = \
   revocation \
   vpn \
   gns \
+       credential \
   $(CONVERSATION_DIR) \
   fs \
   exit \
diff --git a/src/credential/Makefile.am b/src/credential/Makefile.am
new file mode 100644 (file)
index 0000000..6469895
--- /dev/null
@@ -0,0 +1,113 @@
+# 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
+#  test_gns_nick_shorten.conf \
+####  test_gns_proxy.conf \
+#  test_gns_simple_lookup.conf \
+#  gns-helper-service-w32.conf \
+#  w32nsp.def \
+#  gnunet-gns-proxy-setup-ca \
+#  zonefiles/J7POEUT41A8PBFS7KVVDRF88GBOU4HK8PSU5QKVLVE3R9T91E99G.zkey \
+#  zonefiles/OEFL7A4VEF1B40QLEMTG5D8G1CN6EN16QUSG5R2DT71GRJN34LSG.zkey \
+#  zonefiles/test_zonekey \
+#  $(check_SCRIPTS)
+
+
+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_gns.la
+#endif
+#endif
+
+
+gnunet_credential_SOURCES = \
+ gnunet-credential.c
+gnunet_credential_LDADD = \
+  libgnunetcredential.la \
+  $(top_builddir)/src/util/libgnunetutil.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 = \
+  $(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 = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+       $(top_builddir)/src/gns/libgnunetgns.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(GN_LIBINTL)
+
+
+libgnunetcredential_la_SOURCES = \
+ credential_api.c credential.h
+libgnunetcredential_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIB) 
+libgnunetcredential_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS)
+
+
+#libgnunet_plugin_rest_gns_la_SOURCES = \
+#  plugin_rest_gns.c
+#libgnunet_plugin_rest_gns_la_LIBADD = \
+#  libgnunetgns.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_gns_la_LDFLAGS = \
+# $(GN_PLUGIN_LDFLAGS)
+
+
+#check_SCRIPTS = \
+  #test_gns_lookup.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..2acaf73
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+      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 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;
+
+  /**
+   * Unique identifier for this request (for key collisions).
+   */
+  uint32_t id GNUNET_PACKED;
+
+  /* Followed by the zero-terminated attributes to look up */
+
+};
+
+
+/**
+ * Message from CREDENTIAL service to client: new results.
+ */
+struct VerifyResultMessage
+{
+  /**
+    * 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;
+
+
+  /**
+   * The number of credentials in the response
+   */
+  uint32_t ad_count GNUNET_PACKED;
+
+  /* followed by ad_count GNUNET_CREDENTIAL_RecordData structs*/
+
+};
+
+
+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..8ff66c5
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+     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 "credential.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_VerifyResultProcessor 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 *verify_head;
+
+  /**
+   * Tail of linked list of active verify requests.
+   */
+  struct GNUNET_CREDENTIAL_Request *verify_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 VerifyResultMessage *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 VerifyResultMessage *vr_msg)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = cls;
+  uint32_t r_id = ntohl (vr_msg->id);
+  struct GNUNET_CREDENTIAL_Request *vr;
+  GNUNET_CREDENTIAL_VerifyResultProcessor proc;
+  void *proc_cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received verify reply from CREDENTIAL service\n");
+  for (vr = handle->verify_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->verify_head,
+                               handle->verify_tail,
+                               vr);
+  GNUNET_free (vr);
+  /**
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CREDENTIAL_records_deserialize (mlen,
+                                                       (const char*) &lookup_msg[1],
+                                                       rd_count,
+                                                         rd));
+                                                         */
+  proc (proc_cls,
+        NULL,
+        GNUNET_NO); // TODO
+}
+
+
+/**
+ * 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 VerifyResultMessage,
+                           NULL),
+    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->verify_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->verify_head);
+  GNUNET_free (handle);
+}
+
+
+/**
+ * Cancel pending verify request
+ *
+ * @param lr the verify request to cancel
+ */
+void
+GNUNET_CREDENTIAL_verify_cancel (struct GNUNET_CREDENTIAL_Request *vr)
+{
+  struct GNUNET_CREDENTIAL_Handle *handle = vr->credential_handle;
+
+  GNUNET_CONTAINER_DLL_remove (handle->verify_head,
+                               handle->verify_tail,
+                               vr);
+  GNUNET_MQ_discard (vr->env);
+  GNUNET_free (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 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_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,
+                          const char *subject_attribute,
+                          GNUNET_CREDENTIAL_VerifyResultProcessor proc,
+                          void *proc_cls)
+{
+  /* IPC to shorten credential names, return shorten_handle */
+  struct VerifyMessage *v_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 verify `%s' in CREDENTIAL\n",
+       issuer_attribute);
+  nlen = strlen (issuer_attribute) + 1;
+  if (nlen >= GNUNET_SERVER_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->issuer_key =  *issuer_key;
+  GNUNET_memcpy (&v_msg[1],
+                 subject_attribute,
+                 nlen);
+  GNUNET_CONTAINER_DLL_insert (handle->verify_head,
+                               handle->verify_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/gnunet-credential.c b/src/credential/gnunet-credential.c
new file mode 100644 (file)
index 0000000..31cd4fd
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+     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_identity_service.h>
+#include <gnunet_credential_service.h>
+
+/**
+ * Configuration we are using.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * 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;
+
+/**
+ * Credential to lookup. (-u option)
+ */
+static char *lookup_credential;
+
+/**
+ * Handle to verify request
+ */
+static struct GNUNET_CREDENTIAL_Request *verify_request;
+
+/**
+ * Lookup an ego with the identity service.
+ */
+static struct GNUNET_IDENTITY_EgoLookup *el;
+
+/**
+ * Handle for identity service.
+ */
+static struct GNUNET_IDENTITY_Handle *identity;
+
+/**
+ * Active operation on identity service.
+ */
+static struct GNUNET_IDENTITY_Operation *id_op;
+
+/**
+ * Task scheduled to handle timeout.
+ */
+static struct GNUNET_SCHEDULER_Task *tt;
+
+/**
+ * Subject pubkey string
+ */
+static char *subject_key;
+
+/**
+ * Subject pubkey string
+ */
+static char *issuer_key;
+
+
+
+/**
+ * Identity of the zone to use for the lookup (-z option)
+ */
+static char *zone_ego_name;
+
+
+/**
+ * Task run on shutdown.  Cleans up everything.
+ *
+ * @param cls unused
+ */
+static void
+do_shutdown (void *cls)
+{
+  if (NULL != el)
+  {
+    GNUNET_IDENTITY_ego_lookup_cancel (el);
+    el = NULL;
+  }
+  if (NULL != id_op)
+  {
+    GNUNET_IDENTITY_cancel (id_op);
+    id_op = NULL;
+  }
+  if (NULL != verify_request)
+  {
+    GNUNET_CREDENTIAL_verify_cancel (verify_request);
+    verify_request = NULL;
+  }
+  if (NULL != identity)
+  {
+    GNUNET_IDENTITY_disconnect (identity);
+    identity = 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_verify_result (void *cls,
+                      struct GNUNET_CRYPTO_EcdsaPublicKey *issuer,
+                      uint32_t status)
+{
+
+
+  verify_request = NULL;
+  if (GNUNET_NO == status)
+    printf ("Verify failed.\n");
+  else
+    printf ("Successful.\n");
+
+
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+
+
+/**
+ * Perform the actual resolution, with the subject pkey and
+ * the issuer public key
+ *
+ * @param pkey public key to use for the zone, can be NULL
+ * @param shorten_key private key used for shortening, can be NULL
+ */
+static void
+lookup_credentials (struct GNUNET_IDENTITY_Ego *ego)
+{
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
+
+  if (NULL != subject_key && NULL != issuer_key && NULL != lookup_credential)
+  {
+    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_OK !=
+        GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
+                                                    strlen (issuer_key),
+                                                    &issuer_pkey))
+    {
+      fprintf (stderr,
+               _("Authority public key `%s' is not well-formed\n"),
+               issuer_key);
+      GNUNET_SCHEDULER_shutdown ();
+      return;
+    }
+
+    verify_request = GNUNET_CREDENTIAL_verify(credential,
+                                              &issuer_pkey,
+                                              "test", //TODO argument
+                                              &subject_pkey,
+                                              lookup_credential,
+                                              &handle_verify_result,
+                                              NULL);
+    return;
+  }
+  else
+  {
+    fprintf (stderr,
+             _("Please specify name to lookup, subject key and issuer key!\n"));
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+}
+
+
+/**
+ * Method called to with the ego we are to use for the lookup,
+ * when the ego is the one for the default master zone.
+ *
+ * @param cls closure (NULL, unused)
+ * @param ego ego handle, NULL if not found
+ * @param ctx context for application to store data for this ego
+ *                 (during the lifetime of this process, initially NULL)
+ * @param name name assigned by the user for this ego,
+ *                   NULL if the user just deleted the ego and it
+ *                   must thus no longer be used
+ */
+static void
+identity_master_cb (void *cls,
+                    struct GNUNET_IDENTITY_Ego *ego,
+                    void **ctx,
+                    const char *name)
+{
+
+  id_op = NULL;
+  if (NULL == ego)
+  {
+    fprintf (stderr,
+             _("Ego for `gns-master' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+
+  lookup_credentials(ego);
+
+
+}
+
+
+/**
+ * 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;
+  credential = GNUNET_CREDENTIAL_connect (cfg);
+  identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
+
+
+
+
+  if (NULL == credential)
+  {
+    fprintf (stderr,
+             _("Failed to connect to CREDENTIAL\n"));
+    return;
+  }
+  if (NULL == identity)
+  {
+    fprintf (stderr,
+             _("Failed to connect to IDENTITY\n"));
+    return;
+  }
+  tt = GNUNET_SCHEDULER_add_delayed (timeout,
+                                     &do_timeout, NULL);
+  GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
+
+
+
+  GNUNET_break (NULL == id_op);
+  id_op = GNUNET_IDENTITY_get (identity,
+                               "gns-master",//# TODO: Create credential-master
+                               &identity_master_cb,
+                               cls);
+  GNUNET_assert (NULL != id_op);
+
+
+
+
+}
+
+
+/**
+ * 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)
+{
+  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    {'u', "lookup", "CREDENTIAL",
+      gettext_noop ("Lookup a record for the given credential"), 1,
+      &GNUNET_GETOPT_set_string, &lookup_credential},
+    /** { 'T', "timeout", "DELAY",
+      gettext_noop ("Specify timeout for the lookup"), 1,
+      &GNUNET_GETOPT_set_relative_time, &timeout },
+      {'t', "type", "TYPE",
+      gettext_noop ("Specify the type of the record to lookup"), 1,
+      &GNUNET_GETOPT_set_string, &lookup_type},**/
+    {'z', "zone", "NAME",
+      gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1,
+      &GNUNET_GETOPT_set_string, &zone_ego_name},
+    {'s', "subject", "PKEY",
+      gettext_noop ("Specify the public key of the subject to lookup the credential for"), 1,
+      &GNUNET_GETOPT_set_string, &subject_key},
+    {'i', "issuer", "PKEY",
+      gettext_noop ("Specify the public key of the authority to verify the credential against"), 1,
+      &GNUNET_GETOPT_set_string, &issuer_key},
+    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..58be785
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+     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 "gnunet_protocols.h"
+
+// For Looking up GNS request
+#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>
+#include "gnunet_gns_service.h"
+
+
+
+
+#define GNUNET_CREDENTIAL_MAX_LENGTH 255
+
+/**
+ * DLL for record
+ */
+struct AttributeRecordEntry
+{
+  /**
+   * DLL
+   */
+  struct AttributeRecordEntry *next;
+
+  /**
+   * DLL
+   */
+  struct AttributeRecordEntry *prev;
+
+
+  /**
+   * Payload
+   */
+  struct GNUNET_CREDENTIAL_AttributeRecordData record_data;
+};
+
+/**
+ * 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;
+
+  /**
+   * Handle to GNS lookup
+   */
+  struct GNUNET_GNS_LookupRequest *lookup_request;
+
+  /**
+   * Issuer public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Subject public key
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+
+  /**
+   * Attribute Chain
+   */
+  struct AttributeRecordEntry *attr_chain_head;
+
+  /**
+   * Attribute Chain
+   */
+  struct AttributeRecordEntry *attr_chain_tail;
+
+  /**
+   * request id
+   */
+  uint32_t request_id;
+
+};
+
+
+/**
+ * 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;
+
+/**
+ * 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);
+    GNUNET_free (vrh);
+  }
+
+  
+  if (NULL != statistics)
+  {
+    GNUNET_STATISTICS_destroy (statistics,
+                               GNUNET_NO);
+    statistics = NULL;
+  }
+  
+}
+
+/**
+ * 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;
+  size_t attr_len;
+  const char* s_attr;
+  const char* i_attr;
+
+  msg_size = ntohs (v_msg->header.size);
+  if (msg_size < sizeof (struct VerifyMessage))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  i_attr = (const char *) &v_msg[1];
+  if ( ('\0' != i_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
+       (strlen (i_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  attr_len = strlen (i_attr);
+  s_attr = ((const char *) &v_msg[1]) + attr_len + 1;
+  if ( ('\0' != s_attr[v_msg->header.size - sizeof (struct VerifyMessage) - 1]) ||
+       (strlen (s_attr) > GNUNET_CREDENTIAL_MAX_LENGTH) )
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * 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
+send_lookup_response (void* cls,
+                      uint32_t rd_count,
+                      const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct VerifyRequestHandle *vrh = cls;
+  size_t len;
+  int i;
+  int attr_record_count;
+  struct GNUNET_MQ_Envelope *env;
+  struct VerifyResultMessage *rmsg;
+  const struct GNUNET_CREDENTIAL_AttributeRecordData *ard;
+  struct AttributeRecordEntry *ar_entry;
+
+  attr_record_count = 0;
+  for (i=0; i < rd_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type)
+      continue;
+    attr_record_count++;
+    ard = rd[i].data;
+    /**
+     * TODO:
+     * Check if we have already found our credential here
+     * If so return success
+     * Else
+     *  Save all found attributes/issues and prepare forward
+     *  resolution of issuer attribute
+     */
+    ar_entry = GNUNET_new (struct AttributeRecordEntry);
+    ar_entry->record_data = *ard;
+    GNUNET_CONTAINER_DLL_insert_tail (vrh->attr_chain_head,
+                                      vrh->attr_chain_tail,
+                                      ar_entry);
+
+  }
+
+  /**
+   * Get serialized record data size
+   */
+  len = attr_record_count * sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData);
+
+  /**
+   * Prepare a lookup result response message for the client
+   */
+  env = GNUNET_MQ_msg_extra (rmsg,
+                             len,
+                             GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT);
+  //Assign id so that client can find associated request
+  rmsg->id = vrh->request_id;
+  rmsg->ad_count = htonl (attr_record_count);
+
+  /**
+   * Get serialized record data
+   * Append at the end of rmsg
+   */
+  i = 0;
+  struct GNUNET_CREDENTIAL_AttributeRecordData *tmp_record = (struct GNUNET_CREDENTIAL_AttributeRecordData*) &rmsg[1];
+  for (ar_entry = vrh->attr_chain_head; NULL != ar_entry; ar_entry = ar_entry->next)
+  {
+    memcpy (tmp_record,
+            &ar_entry->record_data,
+            sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData));
+    tmp_record++;
+  }
+  GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client),
+                  env);
+
+  GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh);
+
+  /**
+   * TODO:
+   * - Free DLL
+   * - Refactor into cleanup_handle() function for this
+   */
+  GNUNET_free (vrh);
+
+  GNUNET_STATISTICS_update (statistics,
+                            "Completed verifications", 1,
+                            GNUNET_NO);
+  GNUNET_STATISTICS_update (statistics,
+                            "Attributes resolved",
+                            rd_count,
+                            GNUNET_NO);
+}
+
+/**
+ * Handle attribute 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) 
+{
+  char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  char subject_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1];
+  size_t issuer_attribute_len;
+  struct VerifyRequestHandle *vrh;
+  struct GNUNET_SERVICE_Client *client = cls;
+  char *attrptr = issuer_attribute;
+  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);
+  issuer_attribute_len = strlen (utf_in);
+  utf_in = (const char *) (&v_msg[1] + issuer_attribute_len + 1);
+  attrptr = subject_attribute;
+  GNUNET_STRINGS_utf8_tolower (utf_in, attrptr);
+  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;
+
+  if (NULL == subject_attribute)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "No subject attribute provided!\n");
+    send_lookup_response (vrh, 0, NULL);
+    return;
+  }
+  if (NULL == issuer_attribute)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
+                "No issuer attribute provided!\n");
+    send_lookup_response (vrh, 0, NULL);
+    return;
+  }
+  /**
+   * First, get attribute from subject
+   */
+  vrh->lookup_request = GNUNET_GNS_lookup (gns,
+                                           subject_attribute,
+                                           &v_msg->subject_key, //subject_pkey,
+                                           GNUNET_GNSRECORD_TYPE_ATTRIBUTE,
+                                           GNUNET_GNS_LO_DEFAULT,
+                                           NULL, //shorten_key, always NULL
+                                           &send_lookup_response,
+                                           vrh);
+}
+
+
+/**
+ * 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"));
+  }
+
+  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_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..cc64546
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+     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"
+
+
+/**
+ * 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_CREDENTIAL:
+   {
+    struct GNUNET_CREDENTIAL_AttributeRecordData cred;
+    char *cred_str;
+    char *subject_pkey;
+    char *issuer_pkey;
+    uint32_t cf; // Credential flags
+    if (data_size < sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData))
+        return NULL; /* malformed */
+    memcpy (&cred,
+              data,
+              sizeof (cred));
+    cdata = data;  
+    subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred.subject_key);
+    issuer_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred.issuer_key);
+    cf = ntohl (cred.credential_flags);
+
+     GNUNET_asprintf (&cred_str,
+                     "%s %s %u %s",
+                     subject_pkey,
+                     issuer_pkey,
+                     (unsigned int) cf,
+                     &cdata[sizeof (cred)]);
+      GNUNET_free (subject_pkey);
+      GNUNET_free (issuer_pkey);
+
+
+
+    return cred_str;
+    }
+  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_CREDENTIAL:
+      { 
+        struct GNUNET_CREDENTIAL_AttributeRecordData *cred;
+        unsigned int cf; // credential flags
+
+        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];
+
+        if (5 != SSCANF (s,
+                         "%52s %52s %u %253s",
+                         subject_pkey,
+                         issuer_pkey,
+                         &cf,
+                         name))
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                      _("Unable to parse CRED record string `%s'\n"),
+                      s);
+          return GNUNET_SYSERR;
+        }
+        *data_size = sizeof (struct GNUNET_CREDENTIAL_AttributeRecordData) + strlen (name) + 1;
+        *data = cred = GNUNET_malloc (*data_size);
+        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);
+        cred->credential_flags = htonl (cf);
+        GNUNET_memcpy (&cred[1],
+                       name,
+                       strlen (name));
+
+
+        *data = GNUNET_strdup (s);
+        *data_size = strlen (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 },
+  { 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/test_credential_lookup.sh b/src/credential/test_credential_lookup.sh
new file mode 100755 (executable)
index 0000000..216c281
--- /dev/null
@@ -0,0 +1,40 @@
+#!/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`
+which timeout &> /dev/null && DO_TIMEOUT="timeout 30"
+TEST_CREDENTIAL="keySub keyIss credName"
+gnunet-arm -s -c test_credential_lookup.conf
+gnunet-identity -C testsubject -c test_credential_lookup.conf
+
+#TODO1 Plugin serialization functions see REVERSE in gns/plugin_gnsrecord_gns.c
+gnunet-namestore -p -z testsubject -a -n newcred -t CRED -V $TEST_CREDENTIAL -e never -c test_credential_lookup.conf
+
+#TODO2 Add -z swich like in gnunet-gns
+RES_IP=`$DO_TIMEOUT gnunet-credential -z testsubject -s testsubject -u credName -c test_credential_lookup.conf`
+gnunet-namestore -z testsubject -d -n newcred -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
+
+#TODO3 proper test
+exit 0
+
+#if [ "$RES_IP" == "$TEST_CRED" ]
+#then
+#  exit 0
+#else
+#  echo "FAIL: Failed to resolve to proper IP, got $RES_IP."
+#  exit 1
+#fi
index 99d41616987cc3f2ec933d15e1fbef4573fae720..84cc681461f67ddb561bf5b1d9867c0d281fee85 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "gnunet_util_lib.h"
 #include "gnunet_gns_service.h"
+#include "gnunet_identity_service.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -52,7 +53,80 @@ 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 record 
+ */
+struct GNUNET_CREDENTIAL_AttributeRecordData {
+  
+  /**
+   * Public key of the subject this credential was issued to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+  
+  /**
+   * Public key of the issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key;
+
+  /**
+   * Flags for this credential
+   */
+  uint32_t credential_flags GNUNET_PACKED;
+
+  /**
+   * Expiration time of this credential
+   */
+  uint64_t expiration GNUNET_PACKED;
+  
+  /**
+   * The signature for this credential by the issuer
+   */
+  struct GNUNET_CRYPTO_EcdsaSignature sig;
+  
+  /**
+   * Followed by the attribute string
+   */
+};
+
+
+/**
+ * The attribute delegation record
+*/
+struct GNUNET_CREDENTIAL_AttributeDelegationRecordData {
+  
+  /**
+   * Public key of the subject this attribute was delegated to
+   */
+  struct GNUNET_CRYPTO_EcdsaPublicKey subject_key;
+  
+  /**
+   * Followed by the attribute that was delegated to as string
+   */
+};
+
+
+
+GNUNET_NETWORK_STRUCT_END
+
 
 
 /**
@@ -61,7 +135,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 +149,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 issuer the issuer of the attribute NULL if verification failed
+ * @param result the result of the verification
  * @param rd the records in reply
  */
-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_VerifyResultProcessor) (void *cls,
+                                                 struct GNUNET_CRYPTO_EcdsaPublicKey *issuer,
+              uint32_t result);
+
+/**
+ * Iterator called on obtained result for an attribute issuance.
+ *
+ * @param cls closure
+ * @param result the record data that can be handed to the subject
+ */
+typedef void (*GNUNET_CREDENTIAL_IssueResultProcessor) (void *cls,
+                                                 struct GNUNET_CREDENTIAL_AttributeRecordData *data);
 
+/**
+ * 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,
-                  void *proc_cls);
+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,
+                          const char *subject_attribute,
+                          GNUNET_CREDENTIAL_VerifyResultProcessor proc,
+                          void *proc_cls);
 
+/**
+ * Delegate an attribute
+ *
+ * @param handle handle to the Credential service
+ * @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);
 
 /**
- * Issue a credential to an identity
+ * Remove a delegation
  *
  * @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 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 *
+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
+ * @return handle to the queued request
+ */
+struct GNUNET_CREDENTIAL_Request *
 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,
+                         struct GNUNET_CRYPTO_EcdsaPublicKey *subject,
+                         const char *attribute,
                          GNUNET_CREDENTIAL_IssueResultProcessor proc,
                          void *proc_cls);
 
+
 /**
  * Remove a credential
  *
@@ -134,14 +281,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);
+  */
 
 
 /**
@@ -150,7 +298,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_verify_cancel (struct GNUNET_CREDENTIAL_Request *vr);
 
 
 #if 0                           /* keep Emacsens' auto-indent happy */
index 985ae1f7ab0d5489d6ffbc3b00644787bf119990..4f96d50d57584281197b68db576654bacf4e0e96 100644 (file)
@@ -108,11 +108,22 @@ extern "C"
  */
 #define GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA 65546
 
+/**
+ * Record type for credential
+ */
+#define GNUNET_GNSRECORD_TYPE_CREDENTIAL 65547
+
 /**
  * Record type for reverse lookups
  */
 #define GNUNET_GNSRECORD_TYPE_REVERSE 65548
 
+/**
+ * Record type for reverse lookups
+ */
+#define GNUNET_GNSRECORD_TYPE_ATTRIBUTE 65549
+
+
 /**
  * Flags that can be set for a record.
  */
index f9b7d3cb89b0a2d9926f59f1af5f5e47ecebea0d..596196311034b5cefea9a67e101bbc655533d1db 100644 (file)
@@ -2607,6 +2607,15 @@ 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
+
 /******************************************************************************/