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 free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Affero 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.
-*/
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
/**
* @file gnunet-credential.c
* @brief command line tool to access command line Credential service
- * @author Adnan Husain
+ * @author Martin Schanzenbach
*/
#include "platform.h"
#include <gnunet_util_lib.h>
-#include <gnunet_identity_service.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_TIME_Relative timeout;
/**
- * Credential to lookup. (-u option)
+ * Handle to verify request
*/
-static char *lookup_credential;
+static struct GNUNET_CREDENTIAL_Request *verify_request;
/**
- * Handle to lookup request
+ * Handle to collect request
*/
-static struct GNUNET_CREDENTIAL_LookupRequest *lookup_request;
+static struct GNUNET_CREDENTIAL_Request *collect_request;
/**
- * Lookup an ego with the identity service.
+ * Task scheduled to handle timeout.
*/
-static struct GNUNET_IDENTITY_EgoLookup *el;
+static struct GNUNET_SCHEDULER_Task *tt;
/**
- * Handle for identity service.
+ * Subject pubkey string
*/
-static struct GNUNET_IDENTITY_Handle *identity;
+static char *subject_key;
/**
- * Active operation on identity service.
+ * Subject credential string
*/
-static struct GNUNET_IDENTITY_Operation *id_op;
+static char *subject_credential;
/**
- * Task scheduled to handle timeout.
+ * Credential TTL
*/
-static struct GNUNET_SCHEDULER_Task *tt;
+static char *expiration;
/**
- * Subject pubkey string
+ * Subject key
*/
-static char *subject_key;
+struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
/**
- * Subject pubkey string
+ * Issuer key
*/
-static char *issuer_key;
+struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
-/*
- * Credential flags
+
+/**
+ * Issuer pubkey string
*/
-static int credential_flags;
+static char *issuer_key;
-/*
- * Maximum delegation depth
+/**
+ * ego
*/
-static int max_delegation_depth;
+static char *ego_name;
+/**
+ * Issuer attribute
+ */
+static char *issuer_attr;
+/**
+ * Verify mode
+ */
+static int verify;
/**
- * Identity of the zone to use for the lookup (-z option)
+ * Issue mode
*/
-static char *zone_ego_name;
+static int create_cred;
+/**
+ * Collect mode
+ */
+static int collect;
/**
* Task run on shutdown. Cleans up everything.
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 != lookup_request)
+ if (NULL != verify_request)
{
- GNUNET_CREDENTIAL_lookup_cancel (lookup_request);
- lookup_request = NULL;
- }
- if (NULL != identity)
- {
- GNUNET_IDENTITY_disconnect (identity);
- identity = NULL;
+ GNUNET_CREDENTIAL_request_cancel (verify_request);
+ verify_request = NULL;
}
if (NULL != credential)
{
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_lookup_result (void *cls,
- struct GNUNET_IDENTITY_Ego *issuer,
- uint16_t issuer_len,
- const struct GNUNET_CREDENTIAL_RecordData *data)
+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);
+ }
+ }
- lookup_request = NULL;
- if (0 == issuer_len)
- printf ("No results.\n");
- else
- printf ("%u\n",
- issuer_len);
-
GNUNET_SCHEDULER_shutdown ();
}
+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 ();
+}
/**
- * Perform the actual resolution, with the subject pkey and
- * the issuer public key
+ * Callback invoked from identity service with ego information.
+ * An @a ego of NULL means the ego was not found.
*
- * @param pkey public key to use for the zone, can be NULL
- * @param shorten_key private key used for shortening, can be NULL
+ * @param cls closure with the configuration
+ * @param ego an ego known to identity service, or NULL
*/
static void
-lookup_credentials (struct GNUNET_IDENTITY_Ego *ego)
+identity_cb (void *cls,
+ const struct GNUNET_IDENTITY_Ego *ego)
{
-
- struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
- struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
+ 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;
- if (NULL != subject_key && NULL != issuer_key && NULL != lookup_credential)
+ el = NULL;
+ if (NULL == ego)
{
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
- strlen (subject_key),
- &subject_pkey))
+ if (NULL != ego_name)
{
fprintf (stderr,
- _("Subject public key `%s' is not well-formed\n"),
- subject_key);
- GNUNET_SCHEDULER_shutdown ();
- return;
+ _ ("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,
- _("Authority public key `%s' is not well-formed\n"),
+ _ ("Issuer public key `%s' is not well-formed\n"),
issuer_key);
GNUNET_SCHEDULER_shutdown ();
- return;
}
-
- lookup_request = GNUNET_CREDENTIAL_lookup(credential,
- lookup_credential,
- ego,
- &subject_pkey,
- &issuer_pkey,
- credential_flags,
- max_delegation_depth,
- &handle_lookup_result,
- NULL);
- return;
+ 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
+
+ // Else issue
+
+ if (NULL == expiration)
{
fprintf (stderr,
- _("Please specify name to lookup, subject key and issuer key!\n"));
+ "Please specify a TTL\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)
+ 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,
- _("Ego for `gns-master' not found, cannot perform lookup. Did you run gnunet-gns-import.sh?\n"));
+ "%s is not a valid ttl!\n",
+ expiration);
GNUNET_SCHEDULER_shutdown ();
return;
}
- lookup_credentials(ego);
-
+ 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.
*
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)
+ 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 ();
+ return;
+ }
+ if (NULL == issuer_attr)
+ {
+ fprintf (stderr,
+ _ ("You must provide issuer the attribute\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ 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,
- _("Failed to connect to CREDENTIAL\n"));
+ _ ("Subject public key needed\n"));
+ GNUNET_SCHEDULER_shutdown ();
return;
}
- if (NULL == identity)
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key,
+ strlen (subject_key),
+ &subject_pkey))
{
fprintf (stderr,
- _("Failed to connect to IDENTITY\n"));
+ _ ("Subject public key `%s' is not well-formed\n"),
+ subject_key);
+ GNUNET_SCHEDULER_shutdown ();
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);
+ 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 ();
+ return;
+ }
+ credential = GNUNET_CREDENTIAL_connect (cfg);
+ if (NULL == credential)
+ {
+ fprintf (stderr,
+ _ ("Failed to connect to CREDENTIAL\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if ((NULL == issuer_attr) ||(NULL == subject_credential) )
+ {
+ fprintf (stderr,
+ _ ("You must provide issuer and subject attributes\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
-
+ // 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 ();
+ return;
+ }
+ 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);
+ }
+ GNUNET_free (tmp);
+ }
+ 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;
}
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},
+ 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;
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_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-credential",
+ _ ("GNUnet credential resolver tool"),
+ options,
+ &run, NULL)) ? 0 : 1;
GNUNET_free ((void*) argv);
return ret;
}