From 3cd24823660a0447e590ff352e9da7eb076b292b Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Mon, 22 Feb 2021 10:16:16 +0100 Subject: RECLAIM: Added libpabc credential support. --- src/reclaim/plugin_reclaim_credential_pabc.c | 639 +++++++++++++++++++++++++++ 1 file changed, 639 insertions(+) create mode 100644 src/reclaim/plugin_reclaim_credential_pabc.c (limited to 'src/reclaim/plugin_reclaim_credential_pabc.c') diff --git a/src/reclaim/plugin_reclaim_credential_pabc.c b/src/reclaim/plugin_reclaim_credential_pabc.c new file mode 100644 index 000000000..2f6b7b8c4 --- /dev/null +++ b/src/reclaim/plugin_reclaim_credential_pabc.c @@ -0,0 +1,639 @@ +/* + This file is part of GNUnet + Copyright (C) 2013, 2014, 2016 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file reclaim/plugin_reclaim_credential_pabc.c + * @brief reclaim-credential-plugin-pabc attribute plugin to provide the API for + * pabc credentials. + * + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_reclaim_plugin.h" +#include +#include +#include +#include "pabc_helper.h" + +/** + * Convert the 'value' of an credential to a string. + * + * @param cls closure, unused + * @param type type of the credential + * @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 * +pabc_value_to_string (void *cls, + uint32_t type, + const void *data, + size_t data_size) +{ + switch (type) + { + case GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC: + return GNUNET_strndup (data, data_size); + + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of an credential to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the credential + * @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 +pabc_string_to_value (void *cls, + uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + if (NULL == s) + return GNUNET_SYSERR; + switch (type) + { + case GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC: + *data = GNUNET_strdup (s); + *data_size = strlen (s) + 1; + return GNUNET_OK; + + default: + return GNUNET_SYSERR; + } +} + + +/** + * Mapping of credential type numbers to human-readable + * credential type names. + */ +static struct +{ + const char *name; + uint32_t number; +} pabc_cred_name_map[] = { { "PABC", GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC }, + { NULL, UINT32_MAX } }; + +/** + * Convert a type name to the corresponding number. + * + * @param cls closure, unused + * @param pabc_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +pabc_typename_to_number (void *cls, const char *pabc_typename) +{ + unsigned int i; + + i = 0; + while ((NULL != pabc_cred_name_map[i].name) && + (0 != strcasecmp (pabc_typename, pabc_cred_name_map[i].name))) + i++; + return pabc_cred_name_map[i].number; +} + + +/** + * Convert a type number (i.e. 1) to the corresponding type string + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +pabc_number_to_typename (void *cls, uint32_t type) +{ + unsigned int i; + + i = 0; + while ((NULL != pabc_cred_name_map[i].name) && (type != + pabc_cred_name_map[i]. + number)) + i++; + return pabc_cred_name_map[i].name; +} + + +static void +inspect_attrs (char const *const key, + char const *const value, + void *ctx) +{ + struct GNUNET_RECLAIM_AttributeList *attrs = ctx; + + if (NULL == value) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found attribue in PABC credential: `%s': `%s'\n", + key, value); + if (0 == strcmp (key, "expiration")) + return; + if (0 == strcmp (key, "issuer")) + return; + if (0 == strcmp (key, "subject")) + return; + GNUNET_RECLAIM_attribute_list_add (attrs, + key, + NULL, + GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING, + value, + strlen (value)); +} + + +/** + * Parse a pabc and return the respective claim value as Attribute + * + * @param cls the plugin + * @param cred the pabc credential + * @return a GNUNET_RECLAIM_Attribute, containing the new value + */ +struct GNUNET_RECLAIM_AttributeList * +pabc_parse_attributes (void *cls, + const char *data, + size_t data_size) +{ + struct GNUNET_RECLAIM_AttributeList *attrs; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Collecting PABC attributes...\n"); + attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList); + GNUNET_assert (PABC_OK == + pabc_cred_inspect_credential (data, + &inspect_attrs, attrs)); + return attrs; +} + + +/** + * Parse a pabc and return the respective claim value as Attribute + * + * @param cls the plugin + * @param cred the pabc credential + * @return a GNUNET_RECLAIM_Attribute, containing the new value + */ +struct GNUNET_RECLAIM_AttributeList * +pabc_parse_attributes_c (void *cls, + const struct GNUNET_RECLAIM_Credential *cred) +{ + if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC) + return NULL; + return pabc_parse_attributes (cls, cred->data, cred->data_size); +} + + +/** + * Parse a pabc and return the respective claim value as Attribute + * + * @param cls the plugin + * @param cred the pabc credential + * @return a GNUNET_RECLAIM_Attribute, containing the new value + */ +struct GNUNET_RECLAIM_AttributeList * +pabc_parse_attributes_p (void *cls, + const struct GNUNET_RECLAIM_Presentation *cred) +{ + if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC) + return NULL; + return pabc_parse_attributes (cls, cred->data, cred->data_size); +} + +struct Finder +{ + const char* target; + char *result; +}; + +static void +find_attr (char const *const key, + char const *const value, + void *ctx) +{ + struct Finder *fdr = ctx; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found `%s', looking for `%s'\n", + key, fdr->target); + if (0 == strcmp (key, fdr->target)) + fdr->result = GNUNET_strdup (value); +} + + + +/** + * Parse a pabc and return an attribute value. + * + * @param cls the plugin + * @param data the pabc credential data + * @param data_size the pabc credential size + * @param skey the attribute key to look for. + * @return a string, containing the isser + */ +char * +pabc_get_attribute (void *cls, + const char *data, + size_t data_size, + const char *skey) +{ + + struct Finder fdr; + memset (&fdr, 0, sizeof (fdr)); + fdr.target = skey; + pabc_cred_inspect_credential (data, &find_attr, &fdr); + return fdr.result; +} + + +/** + * Parse a pabc and return the issuer + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +char* +pabc_get_issuer (void *cls, + const char *data, + size_t data_size) +{ + char *res; + if (PABC_OK != pabc_cred_get_attr_by_name_from_cred (data, + "issuer", + &res)) + return NULL; + return res; +} + + +/** + * Parse a pabc and return the issuer + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +char* +pabc_get_issuer (void *cls, + const char *data, + size_t data_size) +{ + return pabc_get_attribute (cls, data, data_size, "issuer"); +} + + +/** + * Parse a pabc and return the issuer + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +char * +pabc_get_issuer_c (void *cls, + const struct GNUNET_RECLAIM_Credential *cred) +{ + if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != cred->type) + return NULL; + return pabc_get_issuer (cls, cred->data, cred->data_size); +} + + +/** + * Parse a pabc and return the issuer + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +char * +pabc_get_issuer_p (void *cls, + const struct GNUNET_RECLAIM_Presentation *cred) +{ + if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != cred->type) + return NULL; + return pabc_get_issuer (cls, cred->data, cred->data_size); +} + + +/** + * Parse a pabc and return the expiration + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +int +pabc_get_expiration (void *cls, + const char *data, + size_t data_size, + struct GNUNET_TIME_Absolute *exp) +{ + json_t *json_root; + json_t *json_attrs; + json_t *value; + json_t *exp_j; + json_error_t *json_err = NULL; + const char*key; + + json_root = json_loads (data, JSON_DECODE_ANY, json_err); + if ((NULL == json_root) || + (! json_is_object (json_root))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to retrive expiration from credential\n"); + return GNUNET_SYSERR; + } + + if (1 != sscanf (exp_str, "%llu", &exp_i)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid expiration `%s'\n", exp_str); + GNUNET_free (exp_str); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Converted expiration string `%s' to %llu", + exp_str, exp_i); + + GNUNET_free (exp_str); + exp->abs_value_us = exp_i * 1000 * 1000; + return GNUNET_OK; +} + + +/** + * Parse a pabc and return the expiration + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +enum GNUNET_GenericReturnValue +pabc_get_expiration_c (void *cls, + const struct GNUNET_RECLAIM_Credential *cred, + struct GNUNET_TIME_Absolute *exp) +{ + if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC) + return GNUNET_NO; + return pabc_get_expiration (cls, cred->data, cred->data_size, exp); +} + + +/** + * Parse a pabc and return the expiration + * + * @param cls the plugin + * @param cred the pabc credential + * @return a string, containing the isser + */ +enum GNUNET_GenericReturnValue +pabc_get_expiration_p (void *cls, + const struct GNUNET_RECLAIM_Presentation *cred, + struct GNUNET_TIME_Absolute *exp) +{ + if (cred->type != GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC) + return GNUNET_NO; + return pabc_get_expiration (cls, cred->data, cred->data_size, exp); +} + + +int +pabc_create_presentation (void *cls, + const struct GNUNET_RECLAIM_Credential *credential, + const struct GNUNET_RECLAIM_AttributeList *attrs, + struct GNUNET_RECLAIM_Presentation **pres) +{ + struct pabc_context *ctx = NULL; + struct pabc_user_context *usr_ctx = NULL; + struct pabc_public_parameters *pp = NULL; + struct pabc_credential *cred = NULL; + struct pabc_blinded_proof *proof = NULL; + struct GNUNET_RECLAIM_AttributeListEntry *ale; + char *issuer; + char *subject; + enum pabc_status status; + + if (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC != credential->type) + return GNUNET_NO; + + + PABC_ASSERT (pabc_new_ctx (&ctx)); + issuer = pabc_get_issuer_c (cls, credential); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No issuer found in credential\n"); + pabc_free_ctx (&ctx); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got issuer for credential: %s\n", issuer); + status = PABC_load_public_parameters (ctx, issuer, &pp); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to read public parameters.\n"); + pabc_free_ctx (&ctx); + GNUNET_free (issuer); + return GNUNET_SYSERR; + } + if (PABC_OK != pabc_cred_get_attr_by_name_from_cred (credential->data, + "subject", + &subject)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to get subject.\n"); + pabc_free_ctx (&ctx); + GNUNET_free (issuer); + return GNUNET_SYSERR; + } + status = PABC_read_usr_ctx (subject, issuer, ctx, pp, &usr_ctx); + GNUNET_free (issuer); + GNUNET_free (subject); + if (PABC_OK != status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to read user context.\n"); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + + status = pabc_new_credential (ctx, pp, &cred); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to allocate credential.\n"); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + + status = pabc_decode_credential (ctx, pp, cred, credential->data); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to decode credential.\n"); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + + status = pabc_new_proof (ctx, pp, &proof); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to allocate proof.\n"); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + + // now we can parse the attributes to disclose and configure the proof + for (ale = attrs->list_head; NULL != ale; ale = ale->next) + { + status = pabc_set_disclosure_by_attribute_name (ctx, pp, proof, + ale->attribute->name, + PABC_DISCLOSED, cred); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to configure proof.\n"); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + } + + // and finally -> sign the proof + status = pabc_gen_proof (ctx, usr_ctx, pp, proof, cred); + if (status != PABC_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to sign proof.\n"); + pabc_free_proof (ctx, pp, &proof); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + // print the result + char *json = NULL; + char *ppid = NULL; + char *userid = NULL; + GNUNET_assert (PABC_OK == pabc_cred_get_userid_from_cred (credential->data, + &userid)); + GNUNET_assert (PABC_OK == pabc_cred_get_ppid_from_cred (credential->data, + &ppid)); + pabc_cred_encode_proof (ctx, pp, proof, userid, ppid, &json); + GNUNET_free (ppid); + GNUNET_free (userid); + if (PABC_OK != status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to serialize proof.\n"); + pabc_free_proof (ctx, pp, &proof); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_SYSERR; + } + char *json_enc; + GNUNET_STRINGS_base64_encode (json, + strlen (json) + 1, + &json_enc); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Presentation: %s\n", json_enc); + // clean up + *pres = GNUNET_RECLAIM_presentation_new (GNUNET_RECLAIM_CREDENTIAL_TYPE_PABC, + json_enc, + strlen (json_enc) + 1); + GNUNET_free (json_enc); + PABC_FREE_NULL (json); + pabc_free_proof (ctx, pp, &proof); + pabc_free_credential (ctx, pp, &cred); + pabc_free_user_context (ctx, pp, &usr_ctx); + pabc_free_public_parameters (ctx, &pp); + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_reclaim_credential_pabc_init (void *cls) +{ + struct GNUNET_RECLAIM_CredentialPluginFunctions *api; + + api = GNUNET_new (struct GNUNET_RECLAIM_CredentialPluginFunctions); + api->value_to_string = &pabc_value_to_string; + api->string_to_value = &pabc_string_to_value; + api->typename_to_number = &pabc_typename_to_number; + api->number_to_typename = &pabc_number_to_typename; + api->get_attributes = &pabc_parse_attributes_c; + api->get_issuer = &pabc_get_issuer_c; + api->get_expiration = &pabc_get_expiration_c; + api->value_to_string_p = &pabc_value_to_string; + api->string_to_value_p = &pabc_string_to_value; + api->typename_to_number_p = &pabc_typename_to_number; + api->number_to_typename_p = &pabc_number_to_typename; + api->get_attributes_p = &pabc_parse_attributes_p; + api->get_issuer_p = &pabc_get_issuer_p; + api->get_expiration_p = &pabc_get_expiration_p; + api->create_presentation = &pabc_create_presentation; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init() + * @return NULL + */ +void * +libgnunet_plugin_reclaim_credential_pabc_done (void *cls) +{ + struct GNUNET_RECLAIM_CredentialPluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + + +/* end of plugin_reclaim_credential_type_pabc.c */ -- cgit v1.2.3